diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt index a3323d87..00de185d 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt @@ -349,139 +349,6 @@ data class V2rayConfig( ) } - fun populateTransportSettings( - transport: String, - headerType: String?, - host: String?, - path: String?, - seed: String?, - quicSecurity: String?, - key: String?, - mode: String?, - serviceName: String?, - authority: String? - ): String? { - var sni: String? = null - network = if (transport.isEmpty()) NetworkType.TCP.type else transport - when (network) { - NetworkType.TCP.type -> { - val tcpSetting = TcpSettingsBean() - if (headerType == AppConfig.HEADER_TYPE_HTTP) { - tcpSetting.header.type = AppConfig.HEADER_TYPE_HTTP - if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(path)) { - val requestObj = TcpSettingsBean.HeaderBean.RequestBean() - requestObj.headers.Host = host.orEmpty().split(",").map { it.trim() }.filter { it.isNotEmpty() } - requestObj.path = path.orEmpty().split(",").map { it.trim() }.filter { it.isNotEmpty() } - tcpSetting.header.request = requestObj - sni = requestObj.headers.Host?.getOrNull(0) - } - } else { - tcpSetting.header.type = "none" - sni = host - } - tcpSettings = tcpSetting - } - - NetworkType.KCP.type -> { - val kcpsetting = KcpSettingsBean() - kcpsetting.header.type = headerType ?: "none" - if (seed.isNullOrEmpty()) { - kcpsetting.seed = null - } else { - kcpsetting.seed = seed - } - if (host.isNullOrEmpty()) { - kcpsetting.header.domain = null - } else { - kcpsetting.header.domain = host - } - kcpSettings = kcpsetting - } - - NetworkType.WS.type -> { - val wssetting = WsSettingsBean() - wssetting.headers.Host = host.orEmpty() - sni = host - wssetting.path = path ?: "/" - wsSettings = wssetting - } - - NetworkType.HTTP_UPGRADE.type -> { - val httpupgradeSetting = HttpupgradeSettingsBean() - httpupgradeSetting.host = host.orEmpty() - sni = host - httpupgradeSetting.path = path ?: "/" - httpupgradeSettings = httpupgradeSetting - } - - NetworkType.XHTTP.type -> { - val xhttpSetting = XhttpSettingsBean() - xhttpSetting.host = host.orEmpty() - sni = host - xhttpSetting.path = path ?: "/" - xhttpSettings = xhttpSetting - } - - NetworkType.H2.type, NetworkType.HTTP.type -> { - network = NetworkType.H2.type - val h2Setting = HttpSettingsBean() - h2Setting.host = host.orEmpty().split(",").map { it.trim() }.filter { it.isNotEmpty() } - sni = h2Setting.host.getOrNull(0) - h2Setting.path = path ?: "/" - httpSettings = h2Setting - } - -// "quic" -> { -// val quicsetting = QuicSettingBean() -// quicsetting.security = quicSecurity ?: "none" -// quicsetting.key = key.orEmpty() -// quicsetting.header.type = headerType ?: "none" -// quicSettings = quicsetting -// } - - NetworkType.GRPC.type -> { - val grpcSetting = GrpcSettingsBean() - grpcSetting.multiMode = mode == "multi" - grpcSetting.serviceName = serviceName.orEmpty() - grpcSetting.authority = authority.orEmpty() - grpcSetting.idle_timeout = 60 - grpcSetting.health_check_timeout = 20 - sni = authority - grpcSettings = grpcSetting - } - } - return sni - } - - fun populateTlsSettings( - streamSecurity: String, - allowInsecure: Boolean, - sni: String?, - fingerprint: String?, - alpns: String?, - publicKey: String?, - shortId: String?, - spiderX: String? - ) { - security = if (streamSecurity.isEmpty()) null else streamSecurity - if (security == null) return - val tlsSetting = TlsSettingsBean( - allowInsecure = allowInsecure, - 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() }, - publicKey = if (publicKey.isNullOrEmpty()) null else publicKey, - shortId = if (shortId.isNullOrEmpty()) null else shortId, - spiderX = if (spiderX.isNullOrEmpty()) null else spiderX, - ) - if (security == AppConfig.TLS) { - tlsSettings = tlsSetting - realitySettings = null - } else if (security == AppConfig.REALITY) { - tlsSettings = null - realitySettings = tlsSetting - } - } } data class MuxBean( @@ -723,15 +590,4 @@ data class V2rayConfig( return null } - fun toPrettyPrinting(): String { - return GsonBuilder() - .setPrettyPrinting() - .disableHtmlEscaping() - .registerTypeAdapter( // custom serialiser is needed here since JSON by default parse number as Double, core will fail to start - object : TypeToken() {}.type, - JsonSerializer { src: Double?, _: Type?, _: JsonSerializationContext? -> JsonPrimitive(src?.toInt()) } - ) - .create() - .toJson(this) - } } \ No newline at end of file diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/FmtBase.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/FmtBase.kt index f8bc82fb..bc3229fe 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/FmtBase.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/FmtBase.kt @@ -1,11 +1,22 @@ package com.v2ray.ang.fmt +import android.text.TextUtils import com.v2ray.ang.AppConfig import com.v2ray.ang.dto.NetworkType import com.v2ray.ang.dto.ProfileItem +import com.v2ray.ang.dto.V2rayConfig.OutboundBean.StreamSettingsBean +import com.v2ray.ang.dto.V2rayConfig.OutboundBean.StreamSettingsBean.GrpcSettingsBean +import com.v2ray.ang.dto.V2rayConfig.OutboundBean.StreamSettingsBean.HttpSettingsBean +import com.v2ray.ang.dto.V2rayConfig.OutboundBean.StreamSettingsBean.HttpupgradeSettingsBean +import com.v2ray.ang.dto.V2rayConfig.OutboundBean.StreamSettingsBean.KcpSettingsBean +import com.v2ray.ang.dto.V2rayConfig.OutboundBean.StreamSettingsBean.TcpSettingsBean +import com.v2ray.ang.dto.V2rayConfig.OutboundBean.StreamSettingsBean.TlsSettingsBean +import com.v2ray.ang.dto.V2rayConfig.OutboundBean.StreamSettingsBean.WsSettingsBean +import com.v2ray.ang.dto.V2rayConfig.OutboundBean.StreamSettingsBean.XhttpSettingsBean import com.v2ray.ang.extension.isNotNullEmpty import com.v2ray.ang.handler.MmkvManager import com.v2ray.ang.util.HttpUtil +import com.v2ray.ang.util.JsonUtil import com.v2ray.ang.util.Utils import java.net.URI @@ -151,6 +162,146 @@ open class FmtBase { return dicQuery } + fun populateTransportSettings( + streamSettings: StreamSettingsBean, + transport: String, + headerType: String?, + host: String?, + path: String?, + seed: String?, + quicSecurity: String?, + key: String?, + mode: String?, + serviceName: String?, + authority: String?, + xhttpMode: String?, + xhttpExtra: String?, + ): String? { + var sni: String? = null + streamSettings.network = if (transport.isEmpty()) NetworkType.TCP.type else transport + when (streamSettings.network) { + NetworkType.TCP.type -> { + val tcpSetting = TcpSettingsBean() + if (headerType == AppConfig.HEADER_TYPE_HTTP) { + tcpSetting.header.type = AppConfig.HEADER_TYPE_HTTP + if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(path)) { + val requestObj = TcpSettingsBean.HeaderBean.RequestBean() + requestObj.headers.Host = host.orEmpty().split(",").map { it.trim() }.filter { it.isNotEmpty() } + requestObj.path = path.orEmpty().split(",").map { it.trim() }.filter { it.isNotEmpty() } + tcpSetting.header.request = requestObj + sni = requestObj.headers.Host?.getOrNull(0) + } + } else { + tcpSetting.header.type = "none" + sni = host + } + streamSettings.tcpSettings = tcpSetting + } + + NetworkType.KCP.type -> { + val kcpsetting = KcpSettingsBean() + kcpsetting.header.type = headerType ?: "none" + if (seed.isNullOrEmpty()) { + kcpsetting.seed = null + } else { + kcpsetting.seed = seed + } + if (host.isNullOrEmpty()) { + kcpsetting.header.domain = null + } else { + kcpsetting.header.domain = host + } + streamSettings.kcpSettings = kcpsetting + } + + NetworkType.WS.type -> { + val wssetting = WsSettingsBean() + wssetting.headers.Host = host.orEmpty() + sni = host + wssetting.path = path ?: "/" + streamSettings.wsSettings = wssetting + } + + NetworkType.HTTP_UPGRADE.type -> { + val httpupgradeSetting = HttpupgradeSettingsBean() + httpupgradeSetting.host = host.orEmpty() + sni = host + httpupgradeSetting.path = path ?: "/" + streamSettings.httpupgradeSettings = httpupgradeSetting + } + + NetworkType.XHTTP.type -> { + val xhttpSetting = XhttpSettingsBean() + xhttpSetting.host = host.orEmpty() + sni = host + xhttpSetting.path = path ?: "/" + xhttpSetting.mode = xhttpMode + xhttpSetting.extra = JsonUtil.parseString(xhttpExtra) + streamSettings.xhttpSettings = xhttpSetting + } + + NetworkType.H2.type, NetworkType.HTTP.type -> { + streamSettings.network = NetworkType.H2.type + val h2Setting = HttpSettingsBean() + h2Setting.host = host.orEmpty().split(",").map { it.trim() }.filter { it.isNotEmpty() } + sni = h2Setting.host.getOrNull(0) + h2Setting.path = path ?: "/" + streamSettings.httpSettings = h2Setting + } + +// "quic" -> { +// val quicsetting = QuicSettingBean() +// quicsetting.security = quicSecurity ?: "none" +// quicsetting.key = key.orEmpty() +// quicsetting.header.type = headerType ?: "none" +// quicSettings = quicsetting +// } + + NetworkType.GRPC.type -> { + val grpcSetting = GrpcSettingsBean() + grpcSetting.multiMode = mode == "multi" + grpcSetting.serviceName = serviceName.orEmpty() + grpcSetting.authority = authority.orEmpty() + grpcSetting.idle_timeout = 60 + grpcSetting.health_check_timeout = 20 + sni = authority + streamSettings.grpcSettings = grpcSetting + } + } + return sni + } + + fun populateTlsSettings( + streamSettings: StreamSettingsBean, + streamSecurity: String, + allowInsecure: Boolean, + sni: String?, + fingerprint: String?, + alpns: String?, + publicKey: String?, + shortId: String?, + spiderX: String? + ) { + streamSettings.security = if (streamSecurity.isEmpty()) null else streamSecurity + if (streamSettings.security == null) return + val tlsSetting = TlsSettingsBean( + allowInsecure = allowInsecure, + 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() }, + publicKey = if (publicKey.isNullOrEmpty()) null else publicKey, + shortId = if (shortId.isNullOrEmpty()) null else shortId, + spiderX = if (spiderX.isNullOrEmpty()) null else spiderX, + ) + if (streamSettings.security == AppConfig.TLS) { + streamSettings.tlsSettings = tlsSetting + streamSettings.realitySettings = null + } else if (streamSettings.security == AppConfig.REALITY) { + streamSettings.tlsSettings = null + streamSettings.realitySettings = tlsSetting + } + } + fun resolveHostToIP(server: String?): String { return HttpUtil.resolveHostToIP(server.orEmpty(), MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6) == true) } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/ShadowsocksFmt.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/ShadowsocksFmt.kt index 69588c2c..d0acc28d 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/ShadowsocksFmt.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/ShadowsocksFmt.kt @@ -140,29 +140,37 @@ object ShadowsocksFmt : FmtBase() { server.method = profileItem.method } - val sni = outboundBean?.streamSettings?.populateTransportSettings( - profileItem.network.orEmpty(), - profileItem.headerType, - profileItem.host, - profileItem.path, - profileItem.seed, - profileItem.quicSecurity, - profileItem.quicKey, - profileItem.mode, - profileItem.serviceName, - profileItem.authority, - ) + val sni = outboundBean?.streamSettings?.let { + populateTransportSettings( + it, + profileItem.network.orEmpty(), + profileItem.headerType, + profileItem.host, + profileItem.path, + profileItem.seed, + profileItem.quicSecurity, + profileItem.quicKey, + profileItem.mode, + profileItem.serviceName, + profileItem.authority, + profileItem.xhttpMode, + profileItem.xhttpExtra + ) + } - outboundBean?.streamSettings?.populateTlsSettings( - profileItem.security.orEmpty(), - profileItem.insecure == true, - if (profileItem.sni.isNullOrEmpty()) sni else profileItem.sni, - profileItem.fingerPrint, - profileItem.alpn, - profileItem.publicKey, - profileItem.shortId, - profileItem.spiderX, - ) + outboundBean?.streamSettings?.let { + populateTlsSettings( + it, + profileItem.security.orEmpty(), + profileItem.insecure == true, + if (profileItem.sni.isNullOrEmpty()) sni else profileItem.sni, + profileItem.fingerPrint, + profileItem.alpn, + profileItem.publicKey, + profileItem.shortId, + profileItem.spiderX, + ) + } return outboundBean } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/TrojanFmt.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/TrojanFmt.kt index 7ed00a21..48dd8f4e 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/TrojanFmt.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/TrojanFmt.kt @@ -69,29 +69,37 @@ object TrojanFmt : FmtBase() { server.flow = profileItem.flow } - val sni = outboundBean?.streamSettings?.populateTransportSettings( - profileItem.network.orEmpty(), - profileItem.headerType, - profileItem.host, - profileItem.path, - profileItem.seed, - profileItem.quicSecurity, - profileItem.quicKey, - profileItem.mode, - profileItem.serviceName, - profileItem.authority, - ) + val sni = outboundBean?.streamSettings?.let { + populateTransportSettings( + it, + profileItem.network.orEmpty(), + profileItem.headerType, + profileItem.host, + profileItem.path, + profileItem.seed, + profileItem.quicSecurity, + profileItem.quicKey, + profileItem.mode, + profileItem.serviceName, + profileItem.authority, + profileItem.xhttpMode, + profileItem.xhttpExtra + ) + } - outboundBean?.streamSettings?.populateTlsSettings( - profileItem.security.orEmpty(), - profileItem.insecure == true, - if (profileItem.sni.isNullOrEmpty()) sni else profileItem.sni, - profileItem.fingerPrint, - profileItem.alpn, - profileItem.publicKey, - profileItem.shortId, - profileItem.spiderX, - ) + outboundBean?.streamSettings?.let { + populateTlsSettings( + it, + profileItem.security.orEmpty(), + profileItem.insecure == true, + if (profileItem.sni.isNullOrEmpty()) sni else profileItem.sni, + profileItem.fingerPrint, + profileItem.alpn, + profileItem.publicKey, + profileItem.shortId, + profileItem.spiderX, + ) + } return outboundBean } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VlessFmt.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VlessFmt.kt index d6df582c..1438cd7e 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VlessFmt.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VlessFmt.kt @@ -6,7 +6,6 @@ import com.v2ray.ang.dto.ProfileItem import com.v2ray.ang.dto.V2rayConfig.OutboundBean import com.v2ray.ang.extension.idnHost import com.v2ray.ang.handler.MmkvManager -import com.v2ray.ang.util.JsonUtil import com.v2ray.ang.util.Utils import java.net.URI @@ -67,31 +66,37 @@ object VlessFmt : FmtBase() { vnext.users[0].flow = profileItem.flow } - val sni = outboundBean?.streamSettings?.populateTransportSettings( - profileItem.network.orEmpty(), - profileItem.headerType, - profileItem.host, - profileItem.path, - profileItem.seed, - profileItem.quicSecurity, - profileItem.quicKey, - profileItem.mode, - profileItem.serviceName, - profileItem.authority, - ) - outboundBean?.streamSettings?.xhttpSettings?.mode = profileItem.xhttpMode - outboundBean?.streamSettings?.xhttpSettings?.extra = JsonUtil.parseString(profileItem.xhttpExtra) + val sni = outboundBean?.streamSettings?.let { + populateTransportSettings( + it, + profileItem.network.orEmpty(), + profileItem.headerType, + profileItem.host, + profileItem.path, + profileItem.seed, + profileItem.quicSecurity, + profileItem.quicKey, + profileItem.mode, + profileItem.serviceName, + profileItem.authority, + profileItem.xhttpMode, + profileItem.xhttpExtra + ) + } - outboundBean?.streamSettings?.populateTlsSettings( - profileItem.security.orEmpty(), - profileItem.insecure == true, - if (profileItem.sni.isNullOrEmpty()) sni else profileItem.sni, - profileItem.fingerPrint, - profileItem.alpn, - profileItem.publicKey, - profileItem.shortId, - profileItem.spiderX, - ) + outboundBean?.streamSettings?.let { + populateTlsSettings( + it, + profileItem.security.orEmpty(), + profileItem.insecure == true, + if (profileItem.sni.isNullOrEmpty()) sni else profileItem.sni, + profileItem.fingerPrint, + profileItem.alpn, + profileItem.publicKey, + profileItem.shortId, + profileItem.spiderX, + ) + } return outboundBean } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VmessFmt.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VmessFmt.kt index eac159eb..cb157e1e 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VmessFmt.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/VmessFmt.kt @@ -177,29 +177,37 @@ object VmessFmt : FmtBase() { vnext.users[0].security = profileItem.method } - val sni = outboundBean?.streamSettings?.populateTransportSettings( - profileItem.network.orEmpty(), - profileItem.headerType, - profileItem.host, - profileItem.path, - profileItem.seed, - profileItem.quicSecurity, - profileItem.quicKey, - profileItem.mode, - profileItem.serviceName, - profileItem.authority, - ) + val sni = outboundBean?.streamSettings?.let { + populateTransportSettings( + it, + profileItem.network.orEmpty(), + profileItem.headerType, + profileItem.host, + profileItem.path, + profileItem.seed, + profileItem.quicSecurity, + profileItem.quicKey, + profileItem.mode, + profileItem.serviceName, + profileItem.authority, + profileItem.xhttpMode, + profileItem.xhttpExtra + ) + } - outboundBean?.streamSettings?.populateTlsSettings( - profileItem.security.orEmpty(), - profileItem.insecure == true, - if (profileItem.sni.isNullOrEmpty()) sni else profileItem.sni, - profileItem.fingerPrint, - profileItem.alpn, - null, - null, - null - ) + outboundBean?.streamSettings?.let { + populateTlsSettings( + it, + profileItem.security.orEmpty(), + profileItem.insecure == true, + if (profileItem.sni.isNullOrEmpty()) sni else profileItem.sni, + profileItem.fingerPrint, + profileItem.alpn, + null, + null, + null + ) + } return outboundBean } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt index ffd40eda..51c66523 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt @@ -151,7 +151,7 @@ object V2rayConfigManager { } result.status = true - result.content = v2rayConfig.toPrettyPrinting() + result.content = JsonUtil.toJsonPretty(v2rayConfig) ?: "" result.domainPort = if (retMore.first) retMore.second else retOut.second result.guid = guid return result @@ -195,7 +195,7 @@ object V2rayConfigManager { } result.status = true - result.content = v2rayConfig.toPrettyPrinting() + result.content = JsonUtil.toJsonPretty(v2rayConfig) ?: "" result.domainPort = if (retMore.first) retMore.second else retOut.second result.guid = guid return result @@ -726,8 +726,7 @@ object V2rayConfigManager { V2rayConfig.OutboundBean.StreamSettingsBean.SockoptBean( dialerProxy = outbound.tag ) - if (nextNode.configType == EConfigType.WIREGUARD) - { + if (nextNode.configType == EConfigType.WIREGUARD) { domainPort = nextNode.getServerAddressAndPort() } }