add shadowtls gui

This commit is contained in:
arm64v8a 2023-03-18 18:01:33 +09:00
parent 1f04d35e94
commit f55d14b443
15 changed files with 257 additions and 24 deletions

View File

@ -2,7 +2,7 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 2, "version": 2,
"identityHash": "937a517378a0cb35dc1f8bd181683882", "identityHash": "9ec160533656482a17cbd563e9e3e416",
"entities": [ "entities": [
{ {
"tableName": "proxy_groups", "tableName": "proxy_groups",
@ -80,7 +80,7 @@
}, },
{ {
"tableName": "proxy_entities", "tableName": "proxy_entities",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `groupId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `status` INTEGER NOT NULL, `ping` INTEGER NOT NULL, `uuid` TEXT NOT NULL, `error` TEXT, `socksBean` BLOB, `httpBean` BLOB, `ssBean` BLOB, `vmessBean` BLOB, `trojanBean` BLOB, `trojanGoBean` BLOB, `naiveBean` BLOB, `hysteriaBean` BLOB, `tuicBean` BLOB, `sshBean` BLOB, `wgBean` BLOB, `chainBean` BLOB, `nekoBean` BLOB, `configBean` BLOB)", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `groupId` INTEGER NOT NULL, `type` INTEGER NOT NULL, `userOrder` INTEGER NOT NULL, `tx` INTEGER NOT NULL, `rx` INTEGER NOT NULL, `status` INTEGER NOT NULL, `ping` INTEGER NOT NULL, `uuid` TEXT NOT NULL, `error` TEXT, `socksBean` BLOB, `httpBean` BLOB, `ssBean` BLOB, `vmessBean` BLOB, `trojanBean` BLOB, `trojanGoBean` BLOB, `naiveBean` BLOB, `hysteriaBean` BLOB, `tuicBean` BLOB, `sshBean` BLOB, `wgBean` BLOB, `shadowTLSBean` BLOB, `chainBean` BLOB, `nekoBean` BLOB, `configBean` BLOB)",
"fields": [ "fields": [
{ {
"fieldPath": "id", "fieldPath": "id",
@ -208,6 +208,12 @@
"affinity": "BLOB", "affinity": "BLOB",
"notNull": false "notNull": false
}, },
{
"fieldPath": "shadowTLSBean",
"columnName": "shadowTLSBean",
"affinity": "BLOB",
"notNull": false
},
{ {
"fieldPath": "chainBean", "fieldPath": "chainBean",
"columnName": "chainBean", "columnName": "chainBean",
@ -342,7 +348,7 @@
"views": [], "views": [],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '937a517378a0cb35dc1f8bd181683882')" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '9ec160533656482a17cbd563e9e3e416')"
] ]
} }
} }

View File

@ -184,6 +184,9 @@
<activity <activity
android:name="io.nekohasekai.sagernet.ui.profile.ChainSettingsActivity" android:name="io.nekohasekai.sagernet.ui.profile.ChainSettingsActivity"
android:configChanges="uiMode" /> android:configChanges="uiMode" />
<activity
android:name="moe.matsuri.nb4a.proxy.shadowtls.ShadowTLSSettingsActivity"
android:configChanges="uiMode" />
<activity <activity
android:name="moe.matsuri.nb4a.proxy.neko.NekoSettingActivity" android:name="moe.matsuri.nb4a.proxy.neko.NekoSettingActivity"
android:configChanges="uiMode" /> android:configChanges="uiMode" />

View File

@ -15,6 +15,7 @@ import io.nekohasekai.sagernet.fmt.naive.NaiveBean
import io.nekohasekai.sagernet.fmt.naive.buildNaiveConfig import io.nekohasekai.sagernet.fmt.naive.buildNaiveConfig
import io.nekohasekai.sagernet.fmt.naive.toUri import io.nekohasekai.sagernet.fmt.naive.toUri
import io.nekohasekai.sagernet.fmt.shadowsocks.* import io.nekohasekai.sagernet.fmt.shadowsocks.*
import moe.matsuri.nb4a.proxy.shadowtls.ShadowTLSBean
import io.nekohasekai.sagernet.fmt.socks.SOCKSBean import io.nekohasekai.sagernet.fmt.socks.SOCKSBean
import io.nekohasekai.sagernet.fmt.socks.toUri import io.nekohasekai.sagernet.fmt.socks.toUri
import io.nekohasekai.sagernet.fmt.ssh.SSHBean import io.nekohasekai.sagernet.fmt.ssh.SSHBean
@ -34,6 +35,7 @@ import moe.matsuri.nb4a.Protocols
import moe.matsuri.nb4a.proxy.config.ConfigBean import moe.matsuri.nb4a.proxy.config.ConfigBean
import moe.matsuri.nb4a.proxy.config.ConfigSettingActivity import moe.matsuri.nb4a.proxy.config.ConfigSettingActivity
import moe.matsuri.nb4a.proxy.neko.* import moe.matsuri.nb4a.proxy.neko.*
import moe.matsuri.nb4a.proxy.shadowtls.ShadowTLSSettingsActivity
@Entity( @Entity(
tableName = "proxy_entities", indices = [Index("groupId", name = "groupId")] tableName = "proxy_entities", indices = [Index("groupId", name = "groupId")]
@ -60,6 +62,7 @@ data class ProxyEntity(
var tuicBean: TuicBean? = null, var tuicBean: TuicBean? = null,
var sshBean: SSHBean? = null, var sshBean: SSHBean? = null,
var wgBean: WireGuardBean? = null, var wgBean: WireGuardBean? = null,
var shadowTLSBean: ShadowTLSBean? = null,
var chainBean: ChainBean? = null, var chainBean: ChainBean? = null,
var nekoBean: NekoBean? = null, var nekoBean: NekoBean? = null,
var configBean: ConfigBean? = null, var configBean: ConfigBean? = null,
@ -70,16 +73,17 @@ data class ProxyEntity(
const val TYPE_HTTP = 1 const val TYPE_HTTP = 1
const val TYPE_SS = 2 const val TYPE_SS = 2
const val TYPE_VMESS = 4 const val TYPE_VMESS = 4
const val TYPE_TROJAN = 6 const val TYPE_TROJAN = 6
const val TYPE_TROJAN_GO = 7 const val TYPE_TROJAN_GO = 7
const val TYPE_NAIVE = 9 const val TYPE_NAIVE = 9
const val TYPE_HYSTERIA = 15 const val TYPE_HYSTERIA = 15
const val TYPE_TUIC = 20
const val TYPE_SSH = 17 const val TYPE_SSH = 17
const val TYPE_WG = 18 const val TYPE_WG = 18
const val TYPE_TUIC = 20 const val TYPE_SHADOWTLS = 19
const val TYPE_CONFIG = 998 const val TYPE_CONFIG = 998
const val TYPE_NEKO = 999 const val TYPE_NEKO = 999
@ -103,10 +107,6 @@ data class ProxyEntity(
} }
} }
@Ignore
@Transient
var info: String = ""
@Ignore @Ignore
@Transient @Transient
var dirty: Boolean = false var dirty: Boolean = false
@ -167,6 +167,7 @@ data class ProxyEntity(
TYPE_SSH -> sshBean = KryoConverters.sshDeserialize(byteArray) TYPE_SSH -> sshBean = KryoConverters.sshDeserialize(byteArray)
TYPE_WG -> wgBean = KryoConverters.wireguardDeserialize(byteArray) TYPE_WG -> wgBean = KryoConverters.wireguardDeserialize(byteArray)
TYPE_TUIC -> tuicBean = KryoConverters.tuicDeserialize(byteArray) TYPE_TUIC -> tuicBean = KryoConverters.tuicDeserialize(byteArray)
TYPE_SHADOWTLS -> shadowTLSBean = KryoConverters.shadowTLSDeserialize(byteArray)
TYPE_CHAIN -> chainBean = KryoConverters.chainDeserialize(byteArray) TYPE_CHAIN -> chainBean = KryoConverters.chainDeserialize(byteArray)
TYPE_NEKO -> nekoBean = KryoConverters.nekoDeserialize(byteArray) TYPE_NEKO -> nekoBean = KryoConverters.nekoDeserialize(byteArray)
TYPE_CONFIG -> configBean = KryoConverters.configDeserialize(byteArray) TYPE_CONFIG -> configBean = KryoConverters.configDeserialize(byteArray)
@ -185,6 +186,7 @@ data class ProxyEntity(
TYPE_SSH -> "SSH" TYPE_SSH -> "SSH"
TYPE_WG -> "WireGuard" TYPE_WG -> "WireGuard"
TYPE_TUIC -> "TUIC" TYPE_TUIC -> "TUIC"
TYPE_SHADOWTLS -> "ShadowTLS"
TYPE_CHAIN -> chainName TYPE_CHAIN -> chainName
TYPE_NEKO -> nekoBean!!.displayType() TYPE_NEKO -> nekoBean!!.displayType()
TYPE_CONFIG -> configBean!!.displayType() TYPE_CONFIG -> configBean!!.displayType()
@ -207,6 +209,7 @@ data class ProxyEntity(
TYPE_SSH -> sshBean TYPE_SSH -> sshBean
TYPE_WG -> wgBean TYPE_WG -> wgBean
TYPE_TUIC -> tuicBean TYPE_TUIC -> tuicBean
TYPE_SHADOWTLS -> shadowTLSBean
TYPE_CHAIN -> chainBean TYPE_CHAIN -> chainBean
TYPE_NEKO -> nekoBean TYPE_NEKO -> nekoBean
TYPE_CONFIG -> configBean TYPE_CONFIG -> configBean
@ -226,6 +229,7 @@ data class ProxyEntity(
is TuicBean -> false is TuicBean -> false
is SSHBean -> false is SSHBean -> false
is WireGuardBean -> false is WireGuardBean -> false
is ShadowTLSBean -> false
is NekoBean -> nekoBean!!.haveStandardLink() is NekoBean -> nekoBean!!.haveStandardLink()
is ConfigBean -> false is ConfigBean -> false
else -> true else -> true
@ -245,6 +249,7 @@ data class ProxyEntity(
is SSHBean -> toUniversalLink() is SSHBean -> toUniversalLink()
is WireGuardBean -> toUniversalLink() is WireGuardBean -> toUniversalLink()
is TuicBean -> toUniversalLink() is TuicBean -> toUniversalLink()
is ShadowTLSBean -> toUniversalLink()
is ConfigBean -> toUniversalLink() is ConfigBean -> toUniversalLink()
is NekoBean -> shareLink() is NekoBean -> shareLink()
else -> null else -> null
@ -329,6 +334,7 @@ data class ProxyEntity(
sshBean = null sshBean = null
wgBean = null wgBean = null
tuicBean = null tuicBean = null
shadowTLSBean = null
chainBean = null chainBean = null
configBean = null configBean = null
nekoBean = null nekoBean = null
@ -378,6 +384,10 @@ data class ProxyEntity(
type = TYPE_TUIC type = TYPE_TUIC
tuicBean = bean tuicBean = bean
} }
is ShadowTLSBean -> {
type = TYPE_SHADOWTLS
shadowTLSBean = bean
}
is ChainBean -> { is ChainBean -> {
type = TYPE_CHAIN type = TYPE_CHAIN
chainBean = bean chainBean = bean
@ -409,6 +419,7 @@ data class ProxyEntity(
TYPE_SSH -> SSHSettingsActivity::class.java TYPE_SSH -> SSHSettingsActivity::class.java
TYPE_WG -> WireGuardSettingsActivity::class.java TYPE_WG -> WireGuardSettingsActivity::class.java
TYPE_TUIC -> TuicSettingsActivity::class.java TYPE_TUIC -> TuicSettingsActivity::class.java
TYPE_SHADOWTLS -> ShadowTLSSettingsActivity::class.java
TYPE_CHAIN -> ChainSettingsActivity::class.java TYPE_CHAIN -> ChainSettingsActivity::class.java
TYPE_NEKO -> NekoSettingActivity::class.java TYPE_NEKO -> NekoSettingActivity::class.java
TYPE_CONFIG -> ConfigSettingActivity::class.java TYPE_CONFIG -> ConfigSettingActivity::class.java

View File

@ -32,6 +32,8 @@ import moe.matsuri.nb4a.DNS.makeSingBoxRule
import moe.matsuri.nb4a.SingBoxOptions.* import moe.matsuri.nb4a.SingBoxOptions.*
import moe.matsuri.nb4a.plugin.Plugins import moe.matsuri.nb4a.plugin.Plugins
import moe.matsuri.nb4a.proxy.config.ConfigBean import moe.matsuri.nb4a.proxy.config.ConfigBean
import moe.matsuri.nb4a.proxy.shadowtls.ShadowTLSBean
import moe.matsuri.nb4a.proxy.shadowtls.buildSingBoxOutboundShadowTLSBean
import moe.matsuri.nb4a.utils.JavaUtil.gson import moe.matsuri.nb4a.utils.JavaUtil.gson
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
@ -360,7 +362,9 @@ fun buildConfig(
currentOutbound = when (bean) { currentOutbound = when (bean) {
is ConfigBean -> is ConfigBean ->
gson.fromJson(bean.config, currentOutbound.javaClass) gson.fromJson(bean.config, currentOutbound.javaClass)
is StandardV2RayBean -> is ShadowTLSBean -> // before StandardV2RayBean
buildSingBoxOutboundShadowTLSBean(bean).asMap()
is StandardV2RayBean -> // http/trojan/vmess/vless
buildSingBoxOutboundStandardV2RayBean(bean).asMap() buildSingBoxOutboundStandardV2RayBean(bean).asMap()
is HysteriaBean -> is HysteriaBean ->
buildSingBoxOutboundHysteriaBean(bean).asMap() buildSingBoxOutboundHysteriaBean(bean).asMap()

View File

@ -15,6 +15,7 @@ import io.nekohasekai.sagernet.fmt.hysteria.HysteriaBean;
import io.nekohasekai.sagernet.fmt.internal.ChainBean; import io.nekohasekai.sagernet.fmt.internal.ChainBean;
import io.nekohasekai.sagernet.fmt.naive.NaiveBean; import io.nekohasekai.sagernet.fmt.naive.NaiveBean;
import io.nekohasekai.sagernet.fmt.shadowsocks.ShadowsocksBean; import io.nekohasekai.sagernet.fmt.shadowsocks.ShadowsocksBean;
import moe.matsuri.nb4a.proxy.shadowtls.ShadowTLSBean;
import io.nekohasekai.sagernet.fmt.socks.SOCKSBean; import io.nekohasekai.sagernet.fmt.socks.SOCKSBean;
import io.nekohasekai.sagernet.fmt.ssh.SSHBean; import io.nekohasekai.sagernet.fmt.ssh.SSHBean;
import io.nekohasekai.sagernet.fmt.trojan.TrojanBean; import io.nekohasekai.sagernet.fmt.trojan.TrojanBean;
@ -128,6 +129,12 @@ public class KryoConverters {
return deserialize(new TuicBean(), bytes); return deserialize(new TuicBean(), bytes);
} }
@TypeConverter
public static ShadowTLSBean shadowTLSDeserialize(byte[] bytes) {
if (JavaUtil.isEmpty(bytes)) return null;
return deserialize(new ShadowTLSBean(), bytes);
}
@TypeConverter @TypeConverter
public static ChainBean chainDeserialize(byte[] bytes) { public static ChainBean chainDeserialize(byte[] bytes) {
if (JavaUtil.isEmpty(bytes)) return null; if (JavaUtil.isEmpty(bytes)) return null;

View File

@ -61,6 +61,7 @@ import moe.matsuri.nb4a.proxy.config.ConfigSettingActivity
import moe.matsuri.nb4a.proxy.neko.NekoJSInterface import moe.matsuri.nb4a.proxy.neko.NekoJSInterface
import moe.matsuri.nb4a.proxy.neko.NekoSettingActivity import moe.matsuri.nb4a.proxy.neko.NekoSettingActivity
import moe.matsuri.nb4a.proxy.neko.canShare import moe.matsuri.nb4a.proxy.neko.canShare
import moe.matsuri.nb4a.proxy.shadowtls.ShadowTLSSettingsActivity
import okhttp3.internal.closeQuietly import okhttp3.internal.closeQuietly
import java.net.InetAddress import java.net.InetAddress
import java.net.InetSocketAddress import java.net.InetSocketAddress
@ -354,6 +355,9 @@ class ConfigurationFragment @JvmOverloads constructor(
R.id.action_new_wg -> { R.id.action_new_wg -> {
startActivity(Intent(requireActivity(), WireGuardSettingsActivity::class.java)) startActivity(Intent(requireActivity(), WireGuardSettingsActivity::class.java))
} }
R.id.action_new_shadowtls -> {
startActivity(Intent(requireActivity(), ShadowTLSSettingsActivity::class.java))
}
R.id.action_new_config -> { R.id.action_new_config -> {
startActivity(Intent(requireActivity(), ConfigSettingActivity::class.java)) startActivity(Intent(requireActivity(), ConfigSettingActivity::class.java))
} }

View File

@ -0,0 +1,61 @@
package moe.matsuri.nb4a.proxy.shadowtls;
import androidx.annotation.NonNull;
import com.esotericsoftware.kryo.io.ByteBufferInput;
import com.esotericsoftware.kryo.io.ByteBufferOutput;
import org.jetbrains.annotations.NotNull;
import io.nekohasekai.sagernet.fmt.KryoConverters;
import io.nekohasekai.sagernet.fmt.v2ray.StandardV2RayBean;
public class ShadowTLSBean extends StandardV2RayBean {
public Integer version;
public String password;
@Override
public void initializeDefaultValues() {
super.initializeDefaultValues();
security = "tls";
if (version == null) version = 3;
if (password == null) password = "";
}
@Override
public void serialize(ByteBufferOutput output) {
output.writeInt(0);
super.serialize(output);
output.writeInt(version);
output.writeString(password);
}
@Override
public void deserialize(ByteBufferInput input) {
int version_ = input.readInt();
super.deserialize(input);
version = input.readInt();
password = input.readString();
}
@NotNull
@Override
public ShadowTLSBean clone() {
return KryoConverters.deserialize(new ShadowTLSBean(), KryoConverters.serialize(this));
}
public static final Creator<ShadowTLSBean> CREATOR = new CREATOR<ShadowTLSBean>() {
@NonNull
@Override
public ShadowTLSBean newInstance() {
return new ShadowTLSBean();
}
@Override
public ShadowTLSBean[] newArray(int size) {
return new ShadowTLSBean[size];
}
};
}

View File

@ -0,0 +1,15 @@
package moe.matsuri.nb4a.proxy.shadowtls
import io.nekohasekai.sagernet.fmt.v2ray.buildSingBoxOutboundTLS
import moe.matsuri.nb4a.SingBoxOptions
fun buildSingBoxOutboundShadowTLSBean(bean: ShadowTLSBean): SingBoxOptions.Outbound_ShadowTLSOptions {
return SingBoxOptions.Outbound_ShadowTLSOptions().apply {
type = "shadowtls"
server = bean.serverAddress
server_port = bean.serverPort
version = bean.version
password = bean.password
tls = buildSingBoxOutboundTLS(bean)
}
}

View File

@ -0,0 +1,55 @@
package moe.matsuri.nb4a.proxy.shadowtls
import android.os.Bundle
import androidx.preference.EditTextPreference
import androidx.preference.PreferenceFragmentCompat
import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.database.preference.EditTextPreferenceModifiers
import io.nekohasekai.sagernet.ui.profile.ProfileSettingsActivity
import moe.matsuri.nb4a.proxy.PreferenceBinding
import moe.matsuri.nb4a.proxy.PreferenceBindingManager
import moe.matsuri.nb4a.proxy.Type
class ShadowTLSSettingsActivity : ProfileSettingsActivity<ShadowTLSBean>() {
override fun createEntity() = ShadowTLSBean()
private val pbm = PreferenceBindingManager()
private val name = pbm.add(PreferenceBinding(Type.Text, "name"))
private val serverAddress = pbm.add(PreferenceBinding(Type.Text, "serverAddress"))
private val serverPort = pbm.add(PreferenceBinding(Type.TextToInt, "serverPort"))
private val password = pbm.add(PreferenceBinding(Type.Text, "password"))
private val version = pbm.add(PreferenceBinding(Type.TextToInt, "version"))
private val sni = pbm.add(PreferenceBinding(Type.Text, "sni"))
private val alpn = pbm.add(PreferenceBinding(Type.Text, "alpn"))
private val certificates = pbm.add(PreferenceBinding(Type.Text, "certificates"))
private val allowInsecure = pbm.add(PreferenceBinding(Type.Bool, "allowInsecure"))
private val utlsFingerprint = pbm.add(PreferenceBinding(Type.Text, "utlsFingerprint"))
override fun ShadowTLSBean.init() {
pbm.writeToCacheAll(this)
}
override fun ShadowTLSBean.serialize() {
pbm.fromCacheAll(this)
}
override fun PreferenceFragmentCompat.createPreferences(
savedInstanceState: Bundle?,
rootKey: String?,
) {
addPreferencesFromResource(R.xml.shadowtls_preferences)
pbm.setPreferenceFragment(this)
serverPort.preference.apply {
this as EditTextPreference
setOnBindEditTextListener(EditTextPreferenceModifiers.Port)
}
password.preference.apply {
this as EditTextPreference
summaryProvider = PasswordSummaryProvider
}
}
}

View File

@ -60,6 +60,9 @@
<item <item
android:id="@+id/action_new_wg" android:id="@+id/action_new_wg"
android:title="@string/action_wireguard" /> android:title="@string/action_wireguard" />
<item
android:id="@+id/action_new_shadowtls"
android:title="@string/action_shadowtls" />
<item <item
android:id="@+id/action_new_config" android:id="@+id/action_new_config"
android:title="@string/custom_config" /> android:title="@string/custom_config" />

View File

@ -194,18 +194,6 @@
<string name="share">Compartir</string> <string name="share">Compartir</string>
<string name="add_profile">Añadir perfil</string> <string name="add_profile">Añadir perfil</string>
<string name="select_profile">Seleccionar perfil</string> <string name="select_profile">Seleccionar perfil</string>
<string name="action_socks" translatable="false">SOCKS</string>
<string name="action_http" translatable="false">HTTP</string>
<string name="action_shadowsocks" translatable="false">Shadowsocks</string>
<string name="action_shadowsocksr" translatable="false">ShadowsocksR</string>
<string name="action_vmess" translatable="false">VMess</string>
<string name="action_trojan" translatable="false">Trojan</string>
<string name="action_trojan_go" translatable="false">Trojan Go</string>
<string name="action_naive" translatable="false">Naïve</string>
<string name="action_ping_tunnel" translatable="false">Ping Tunnel</string>
<string name="action_hysteria" translatable="false">Hysteria</string>
<string name="action_ssh" translatable="false">SSH</string>
<string name="action_wireguard" translatable="false">WireGuard</string>
<string name="proxy_chain">Cadena del proxy</string> <string name="proxy_chain">Cadena del proxy</string>
<string name="custom_config">Configuración personalizada</string> <string name="custom_config">Configuración personalizada</string>
<string name="balancer">Equilibrador</string> <string name="balancer">Equilibrador</string>

View File

@ -462,4 +462,8 @@
<string name="log_level">日志级别</string> <string name="log_level">日志级别</string>
<string name="ads">推广</string> <string name="ads">推广</string>
<string name="need_restart">重新启动应用程序以应用更改</string> <string name="need_restart">重新启动应用程序以应用更改</string>
<string name="use_selector">启用 selector (免重载切换节点)</string>
<string name="front_proxy">前置代理</string>
<string name="landing_proxy">落地代理</string>
<string name="shadowtls_version">ShadowTLS 版本</string>
</resources> </resources>

View File

@ -507,4 +507,9 @@
<item>trace</item> <item>trace</item>
</string-array> </string-array>
<string-array name="shadowtls_version_value">
<item>2</item>
<item>3</item>
</string-array>
</resources> </resources>

View File

@ -505,5 +505,7 @@ Anyone can write advanced plugins, which can control NekoBox. please download an
<string name="use_selector">Use selector</string> <string name="use_selector">Use selector</string>
<string name="front_proxy">Front proxy</string> <string name="front_proxy">Front proxy</string>
<string name="landing_proxy">Landing Proxy</string> <string name="landing_proxy">Landing Proxy</string>
<string name="action_shadowtls" translatable="false">ShadowTLS</string>
<string name="shadowtls_version">ShadowTLS Version</string>
</resources> </resources>

View File

@ -0,0 +1,65 @@
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
<EditTextPreference
app:icon="@drawable/ic_social_emoji_symbols"
app:key="name"
app:title="@string/profile_name"
app:useSimpleSummaryProvider="true" />
<PreferenceCategory app:title="@string/proxy_cat">
<EditTextPreference
app:icon="@drawable/ic_hardware_router"
app:key="serverAddress"
app:title="@string/server_address"
app:useSimpleSummaryProvider="true" />
<EditTextPreference
app:icon="@drawable/ic_maps_directions_boat"
app:key="serverPort"
app:title="@string/server_port"
app:useSimpleSummaryProvider="true" />
<moe.matsuri.nb4a.ui.SimpleMenuPreference
app:entries="@array/shadowtls_version_value"
app:entryValues="@array/shadowtls_version_value"
app:icon="@drawable/ic_baseline_update_24"
app:key="version"
app:title="@string/shadowtls_version"
app:useSimpleSummaryProvider="true" />
<EditTextPreference
app:dialogLayout="@layout/layout_password_dialog"
app:icon="@drawable/ic_notification_enhanced_encryption"
app:key="password"
app:title="@string/password" />
</PreferenceCategory>
<PreferenceCategory
app:key="serverSecurityCategory"
app:title="@string/security_settings">
<EditTextPreference
app:icon="@drawable/ic_action_copyright"
app:key="sni"
app:title="@string/sni"
app:useSimpleSummaryProvider="true" />
<EditTextPreference
app:icon="@drawable/ic_baseline_legend_toggle_24"
app:key="alpn"
app:title="@string/alpn"
app:useSimpleSummaryProvider="true" />
<EditTextPreference
app:icon="@drawable/ic_baseline_vpn_key_24"
app:key="certificates"
app:title="@string/certificates"
app:useSimpleSummaryProvider="true" />
<SwitchPreference
app:icon="@drawable/ic_notification_enhanced_encryption"
app:key="allowInsecure"
app:summary="@string/allow_insecure_sum"
app:title="@string/allow_insecure" />
<moe.matsuri.nb4a.ui.SimpleMenuPreference
app:defaultValue=""
app:entries="@array/utls_fingerprint_entry"
app:entryValues="@array/utls_fingerprint_entry"
app:icon="@drawable/ic_baseline_fingerprint_24"
app:key="utlsFingerprint"
app:title="@string/utls_fingerprint"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>
</PreferenceScreen>