Add ECH config support to TLS settings

https://github.com/2dust/v2rayNG/issues/5094
This commit is contained in:
2dust
2025-12-31 19:13:49 +08:00
parent 66d4c21b77
commit 08bf66350a
16 changed files with 115 additions and 42 deletions
@@ -40,6 +40,8 @@ data class ProfileItem(
var alpn: String? = null,
var fingerPrint: String? = null,
var insecure: Boolean? = null,
var echConfigList: String? = null,
var echForceQuery: String? = null,
var publicKey: String? = null,
var shortId: String? = null,
@@ -267,6 +267,8 @@ data class V2rayConfig(
val certificates: List<Any>? = null,
val disableSystemRoot: Boolean? = null,
val enableSessionResumption: Boolean? = null,
var echConfigList: String? = null,
var echForceQuery: String? = null,
// REALITY settings
val show: Boolean = false,
var publicKey: String? = null,
@@ -82,6 +82,7 @@ open class FmtBase {
config.sni = queryParam["sni"]
config.fingerPrint = queryParam["fp"]
config.alpn = queryParam["alpn"]
config.echConfigList = queryParam["ech"]
config.publicKey = queryParam["pbk"]
config.shortId = queryParam["sid"]
config.spiderX = queryParam["spx"]
@@ -100,6 +101,7 @@ open class FmtBase {
dicQuery["security"] = config.security?.ifEmpty { "none" }.orEmpty()
config.sni.let { if (it.isNotNullEmpty()) dicQuery["sni"] = it.orEmpty() }
config.alpn.let { if (it.isNotNullEmpty()) dicQuery["alpn"] = it.orEmpty() }
config.echConfigList.let { if (it.isNotNullEmpty()) dicQuery["ech"] = it.orEmpty() }
config.fingerPrint.let { if (it.isNotNullEmpty()) dicQuery["fp"] = it.orEmpty() }
config.publicKey.let { if (it.isNotNullEmpty()) dicQuery["pbk"] = it.orEmpty() }
config.shortId.let { if (it.isNotNullEmpty()) dicQuery["sid"] = it.orEmpty() }
@@ -1223,6 +1223,8 @@ object V2rayConfigManager {
}
val fingerprint = profileItem.fingerPrint
val alpns = profileItem.alpn
val echConfigList = profileItem.echConfigList
val echForceQuery = profileItem.echForceQuery
val publicKey = profileItem.publicKey
val shortId = profileItem.shortId
val spiderX = profileItem.spiderX
@@ -1235,6 +1237,8 @@ object V2rayConfigManager {
serverName = if (sni.isNullOrEmpty()) null else sni,
fingerprint = if (fingerprint.isNullOrEmpty()) null else fingerprint,
alpn = if (alpns.isNullOrEmpty()) null else alpns.split(",").map { it.trim() }.filter { it.isNotEmpty() },
echConfigList = if (echConfigList.isNullOrEmpty()) null else echConfigList,
echForceQuery = if (echForceQuery.isNullOrEmpty()) null else echForceQuery,
publicKey = if (publicKey.isNullOrEmpty()) null else publicKey,
shortId = if (shortId.isNullOrEmpty()) null else shortId,
spiderX = if (spiderX.isNullOrEmpty()) null else spiderX,
@@ -82,6 +82,9 @@ class ServerActivity : BaseActivity() {
private val xhttpMode: Array<out String> by lazy {
resources.getStringArray(R.array.xhttp_mode)
}
private val echForceQuerys: Array<out String> by lazy {
resources.getStringArray(R.array.ech_force_query_value)
}
// Kotlin synthetics was used, but since it is removed in 1.8. We switch to old manual approach.
@@ -130,6 +133,10 @@ class ServerActivity : BaseActivity() {
private val et_bandwidth_up: EditText? by lazy { findViewById(R.id.et_bandwidth_up) }
private val et_extra: EditText? by lazy { findViewById(R.id.et_extra) }
private val layout_extra: LinearLayout? by lazy { findViewById(R.id.layout_extra) }
private val et_ech_config_list: EditText? by lazy { findViewById(R.id.et_ech_config_list) }
private val container_ech_config_list: LinearLayout? by lazy { findViewById(R.id.lay_ech_config_list) }
private val sp_ech_force_query: Spinner? by lazy { findViewById(R.id.sp_ech_force_query) }
private val container_ech_force_query: LinearLayout? by lazy { findViewById(R.id.lay_ech_force_query) }
override fun onCreate(savedInstanceState: Bundle?) {
@@ -263,7 +270,9 @@ class ServerActivity : BaseActivity() {
container_public_key,
container_short_id,
container_spider_x,
container_mldsa65_verify
container_mldsa65_verify,
container_ech_config_list,
container_ech_force_query
).forEach { it?.visibility = View.GONE }
}
@@ -272,9 +281,11 @@ class ServerActivity : BaseActivity() {
listOf(
container_sni,
container_fingerprint,
container_alpn
container_alpn,
container_allow_insecure,
container_ech_config_list,
container_ech_force_query
).forEach { it?.visibility = View.VISIBLE }
container_allow_insecure?.visibility = View.VISIBLE
listOf(
container_public_key,
container_short_id,
@@ -285,11 +296,16 @@ class ServerActivity : BaseActivity() {
// Case 3: Other reality values
else -> {
listOf(container_sni, container_fingerprint).forEach {
it?.visibility = View.VISIBLE
}
container_alpn?.visibility = View.GONE
container_allow_insecure?.visibility = View.GONE
listOf(
container_sni,
container_fingerprint
).forEach { it?.visibility = View.VISIBLE }
listOf(
container_alpn,
container_allow_insecure,
container_ech_config_list,
container_ech_force_query
).forEach { it?.visibility = View.GONE }
listOf(
container_public_key,
container_short_id,
@@ -357,10 +373,6 @@ class ServerActivity : BaseActivity() {
val streamSecurity = Utils.arrayFind(streamSecuritys, config.security.orEmpty())
if (streamSecurity >= 0) {
sp_stream_security?.setSelection(streamSecurity)
container_sni?.visibility = View.VISIBLE
container_fingerprint?.visibility = View.VISIBLE
container_alpn?.visibility = View.VISIBLE
et_sni?.text = Utils.getEditable(config.sni)
config.fingerPrint?.let { it ->
val utlsIndex = Utils.arrayFind(uTlsItems, it)
@@ -371,42 +383,23 @@ class ServerActivity : BaseActivity() {
alpnIndex.let { sp_stream_alpn?.setSelection(if (it >= 0) it else 0) }
}
if (config.security == TLS) {
container_allow_insecure?.visibility = View.VISIBLE
val allowinsecure = Utils.arrayFind(allowinsecures, config.insecure.toString())
if (allowinsecure >= 0) {
sp_allow_insecure?.setSelection(allowinsecure)
}
listOf(
container_public_key,
container_short_id,
container_spider_x,
container_mldsa65_verify
).forEach { it?.visibility = View.GONE }
et_ech_config_list?.text = Utils.getEditable(config.echConfigList)
config.echForceQuery?.let { it ->
val index = Utils.arrayFind(echForceQuerys, it)
index.let { sp_ech_force_query?.setSelection(if (it >= 0) it else 0) }
}
} else if (config.security == REALITY) {
container_public_key?.visibility = View.VISIBLE
et_public_key?.text = Utils.getEditable(config.publicKey.orEmpty())
container_short_id?.visibility = View.VISIBLE
et_short_id?.text = Utils.getEditable(config.shortId.orEmpty())
container_spider_x?.visibility = View.VISIBLE
et_spider_x?.text = Utils.getEditable(config.spiderX.orEmpty())
container_mldsa65_verify?.visibility = View.VISIBLE
et_mldsa65_verify?.text = Utils.getEditable(config.mldsa65Verify.orEmpty())
container_allow_insecure?.visibility = View.GONE
}
}
if (config.security.isNullOrEmpty()) {
listOf(
container_sni,
container_fingerprint,
container_alpn,
container_allow_insecure,
container_public_key,
container_short_id,
container_spider_x,
container_mldsa65_verify
).forEach { it?.visibility = View.GONE }
}
val network = Utils.arrayFind(networks, config.network.orEmpty())
if (network >= 0) {
sp_network?.setSelection(network)
@@ -569,6 +562,8 @@ class ServerActivity : BaseActivity() {
val shortId = et_short_id?.text?.toString()
val spiderX = et_spider_x?.text?.toString()
val mldsa65Verify = et_mldsa65_verify?.text?.toString()
val echConfigList = et_ech_config_list?.text?.toString()
val echForceQueryIndex = sp_ech_force_query?.selectedItemPosition ?: 0
val allowInsecure =
if (allowInsecureField == null || allowinsecures[allowInsecureField].isBlank()) {
@@ -586,6 +581,8 @@ class ServerActivity : BaseActivity() {
config.shortId = shortId
config.spiderX = spiderX
config.mldsa65Verify = mldsa65Verify
config.echConfigList = echConfigList
config.echForceQuery = echForceQuerys[echForceQueryIndex]
}
private fun transportTypes(network: String?): Array<out String> {
+47 -6
View File
@@ -113,7 +113,49 @@
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:entries="@array/allowinsecures" />
android:entries="@array/allowinsecures"
android:nextFocusDown="@+id/et_ech_config_list"/>
</LinearLayout>
<LinearLayout
android:id="@+id/lay_ech_config_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/padding_spacing_dp16"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/server_lab_ech_config_list" />
<EditText
android:id="@+id/et_ech_config_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:nextFocusDown="@+id/sp_ech_force_query" />
</LinearLayout>
<LinearLayout
android:id="@+id/lay_ech_force_query"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/server_lab_ech_force_query" />
<Spinner
android:id="@+id/sp_ech_force_query"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/padding_spacing_dp8"
android:layout_marginBottom="@dimen/padding_spacing_dp8"
android:entries="@array/ech_force_query_value" />
</LinearLayout>
<LinearLayout
@@ -133,7 +175,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:nextFocusDown="@+id/sp_stream_fingerprint" />
android:nextFocusDown="@+id/et_short_id" />
</LinearLayout>
@@ -154,7 +196,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:nextFocusDown="@+id/sp_stream_fingerprint" />
android:nextFocusDown="@+id/et_spider_x" />
</LinearLayout>
@@ -175,7 +217,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:nextFocusDown="@+id/sp_stream_fingerprint" />
android:nextFocusDown="@+id/et_mldsa65_verify" />
</LinearLayout>
@@ -195,8 +237,7 @@
android:id="@+id/et_mldsa65_verify"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="text"
android:nextFocusDown="@+id/sp_stream_fingerprint" />
android:inputType="text" />
</LinearLayout>
</LinearLayout>
@@ -114,6 +114,8 @@
<string name="server_lab_bandwidth_up">Bandwidth up (Supported units: k/m/g/t)</string>
<string name="server_lab_xhttp_mode">XHTTP Mode</string>
<string name="server_lab_xhttp_extra">XHTTP Extra raw JSON, format: { XHTTPObject }</string>
<string name="server_lab_ech_config_list">EchConfigList</string>
<string name="server_lab_ech_force_query">EchForceQuery</string>
<!-- UserAssetActivity -->
<string name="toast_asset_copy_failed">فشل نسخ الملف، يرجى استخدام مدير الملفات</string>
@@ -113,6 +113,8 @@
<string name="server_lab_bandwidth_up">Bandwidth up (Supported units: k/m/g/t)</string>
<string name="server_lab_xhttp_mode">XHTTP Mode</string>
<string name="server_lab_xhttp_extra">XHTTP Extra raw JSON, format: { XHTTPObject }</string>
<string name="server_lab_ech_config_list">EchConfigList</string>
<string name="server_lab_ech_force_query">EchForceQuery</string>
<!-- UserAssetActivity -->
<string name="toast_asset_copy_failed">ফাইল কপি ব্যর্থ, অনুগ্রহ করে ফাইল ম্যানেজার ব্যবহার করুন</string>
@@ -113,6 +113,8 @@
<string name="server_lab_bandwidth_up">وا روء رئڌن پئنا باند (واهڌ)</string>
<string name="server_lab_xhttp_mode">هالت XHTTP</string>
<string name="server_lab_xhttp_extra">XHTTP Extra خام JSON، قالوو: { XHTTPObject }</string>
<string name="server_lab_ech_config_list">EchConfigList</string>
<string name="server_lab_ech_force_query">EchForceQuery</string>
<!-- UserAssetActivity -->
<string name="toast_asset_copy_failed">لف گیری فایل ٱنجوم نوابی، ز ی برنومه دؽوۉداری فایل هیاری بگرین</string>
@@ -113,6 +113,8 @@
<string name="server_lab_bandwidth_up">افزایش پهنای باند (واحد)</string>
<string name="server_lab_xhttp_mode">حالت XHTTP</string>
<string name="server_lab_xhttp_extra">خام JSON XHTTP Extra، قالب: { XHTTPObject }</string>
<string name="server_lab_ech_config_list">EchConfigList</string>
<string name="server_lab_ech_force_query">EchForceQuery</string>
<!-- UserAssetActivity -->
<string name="toast_asset_copy_failed">کپی فایل انجام نشد، لطفا از برنامه مدیریت فایل استفاده کنید</string>
@@ -113,6 +113,8 @@
<string name="server_lab_bandwidth_up">Исходящая пропускная способность (допускаются: k/m/g/t)</string>
<string name="server_lab_xhttp_mode">Режим XHTTP</string>
<string name="server_lab_xhttp_extra">Необработанный JSON XHTTP Extra, формат: { XHTTPObject }</string>
<string name="server_lab_ech_config_list">EchConfigList</string>
<string name="server_lab_ech_force_query">EchForceQuery</string>
<!-- UserAssetActivity -->
<string name="toast_asset_copy_failed">Невозможно скопировать файл, используйте файловый менеджер</string>
@@ -113,6 +113,8 @@
<string name="server_lab_bandwidth_up">Bandwidth up (Supported units: k/m/g/t)</string>
<string name="server_lab_xhttp_mode">XHTTP Mode</string>
<string name="server_lab_xhttp_extra">XHTTP Extra raw JSON, format: { XHTTPObject }</string>
<string name="server_lab_ech_config_list">EchConfigList</string>
<string name="server_lab_ech_force_query">EchForceQuery</string>
<!-- UserAssetActivity -->
<string name="toast_asset_copy_failed">Không thể sao chép tệp tin, hãy dùng trình quản lý tệp!</string>
@@ -113,6 +113,8 @@
<string name="server_lab_bandwidth_up">带宽上行 (支持的单位 k/m/g/t)</string>
<string name="server_lab_xhttp_mode">XHTTP 模式</string>
<string name="server_lab_xhttp_extra">XHTTP Extra 原始 JSON,格式: { XHTTPObject }</string>
<string name="server_lab_ech_config_list">EchConfigList</string>
<string name="server_lab_ech_force_query">EchForceQuery</string>
<!-- UserAssetActivity -->
<string name="toast_asset_copy_failed">失败, 请使用文件管理器</string>
@@ -113,6 +113,8 @@
<string name="server_lab_bandwidth_up">頻寬上行 (支持的單位 k/m/g/t)</string>
<string name="server_lab_xhttp_mode">XHTTP 模式</string>
<string name="server_lab_xhttp_extra">XHTTP Extra 原始 JSON,格式: { XHTTPObject }</string>
<string name="server_lab_ech_config_list">EchConfigList</string>
<string name="server_lab_ech_force_query">EchForceQuery</string>
<!-- UserAssetActivity -->
<string name="toast_asset_copy_failed">失敗,請使用檔案總管</string>
@@ -215,4 +215,11 @@
<item>2</item>
</string-array>
<string-array name="ech_force_query_value" translatable="false">
<item />
<item>none</item>
<item>half</item>
<item>full</item>
</string-array>
</resources>
@@ -114,6 +114,8 @@
<string name="server_lab_bandwidth_up">Bandwidth up (Supported units: k/m/g/t)</string>
<string name="server_lab_xhttp_mode">XHTTP Mode</string>
<string name="server_lab_xhttp_extra">XHTTP Extra raw JSON, format: { XHTTPObject }</string>
<string name="server_lab_ech_config_list">EchConfigList</string>
<string name="server_lab_ech_force_query">EchForceQuery</string>
<!-- UserAssetActivity -->
<string name="toast_asset_copy_failed">File copy failed, please use File Manager</string>