From 5bf7c98cd313fff0ab863bbe9c6b4fb57256f610 Mon Sep 17 00:00:00 2001 From: 2dust <31833384+2dust@users.noreply.github.com> Date: Fri, 18 Apr 2025 20:02:55 +0800 Subject: [PATCH] Refactor outbound related code --- .../java/com/v2ray/ang/dto/V2rayConfig.kt | 48 ---- .../main/java/com/v2ray/ang/fmt/FmtBase.kt | 151 ------------ .../main/java/com/v2ray/ang/fmt/HttpFmt.kt | 3 +- .../java/com/v2ray/ang/fmt/Hysteria2Fmt.kt | 3 +- .../java/com/v2ray/ang/fmt/ShadowsocksFmt.kt | 31 +-- .../main/java/com/v2ray/ang/fmt/SocksFmt.kt | 3 +- .../main/java/com/v2ray/ang/fmt/TrojanFmt.kt | 31 +-- .../main/java/com/v2ray/ang/fmt/VlessFmt.kt | 31 +-- .../main/java/com/v2ray/ang/fmt/VmessFmt.kt | 31 +-- .../java/com/v2ray/ang/fmt/WireguardFmt.kt | 3 +- .../v2ray/ang/handler/V2rayConfigManager.kt | 224 ++++++++++++++++-- .../main/java/com/v2ray/ang/util/HttpUtil.kt | 2 +- 12 files changed, 228 insertions(+), 333 deletions(-) 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 f4dedf22..0d08df47 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 @@ -2,10 +2,6 @@ package com.v2ray.ang.dto import com.google.gson.annotations.SerializedName import com.v2ray.ang.AppConfig -import com.v2ray.ang.dto.V2rayConfig.OutboundBean.OutSettingsBean.ServersBean -import com.v2ray.ang.dto.V2rayConfig.OutboundBean.OutSettingsBean.VnextBean -import com.v2ray.ang.dto.V2rayConfig.OutboundBean.OutSettingsBean.VnextBean.UsersBean -import com.v2ray.ang.dto.V2rayConfig.OutboundBean.OutSettingsBean.WireGuardBean import com.v2ray.ang.util.Utils data class V2rayConfig( @@ -70,50 +66,6 @@ data class V2rayConfig( val sendThrough: String? = null, var mux: MuxBean? = MuxBean(false) ) { - companion object { - fun create(configType: EConfigType): OutboundBean? { - return when (configType) { - EConfigType.VMESS, - EConfigType.VLESS -> - return OutboundBean( - protocol = configType.name.lowercase(), - settings = OutSettingsBean( - vnext = listOf( - VnextBean( - users = listOf(UsersBean()) - ) - ) - ), - streamSettings = StreamSettingsBean() - ) - - EConfigType.SHADOWSOCKS, - EConfigType.SOCKS, - EConfigType.HTTP, - EConfigType.TROJAN, - EConfigType.HYSTERIA2 -> - return OutboundBean( - protocol = configType.name.lowercase(), - settings = OutSettingsBean( - servers = listOf(ServersBean()) - ), - streamSettings = StreamSettingsBean() - ) - - EConfigType.WIREGUARD -> - return OutboundBean( - protocol = configType.name.lowercase(), - settings = OutSettingsBean( - secretKey = "", - peers = listOf(WireGuardBean()) - ) - ) - - EConfigType.CUSTOM -> null - } - } - } - data class OutSettingsBean( var vnext: List? = null, var fragment: FragmentBean? = null, 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 9cea5544..cc9a70ff 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,22 +1,9 @@ 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 @@ -162,144 +149,6 @@ 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 - } - } } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/HttpFmt.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/HttpFmt.kt index faac0230..4163737e 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/HttpFmt.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/HttpFmt.kt @@ -4,6 +4,7 @@ import com.v2ray.ang.dto.EConfigType import com.v2ray.ang.dto.ProfileItem import com.v2ray.ang.dto.V2rayConfig.OutboundBean import com.v2ray.ang.extension.isNotNullEmpty +import com.v2ray.ang.handler.V2rayConfigManager object HttpFmt : FmtBase() { /** @@ -13,7 +14,7 @@ object HttpFmt : FmtBase() { * @return the converted OutboundBean object, or null if conversion fails */ fun toOutbound(profileItem: ProfileItem): OutboundBean? { - val outboundBean = OutboundBean.create(EConfigType.HTTP) + val outboundBean = V2rayConfigManager.createOutbound(EConfigType.HTTP) outboundBean?.settings?.servers?.first()?.let { server -> server.address = profileItem.server.orEmpty() diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/Hysteria2Fmt.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/Hysteria2Fmt.kt index 7a6abe08..80d127fb 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/Hysteria2Fmt.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/Hysteria2Fmt.kt @@ -9,6 +9,7 @@ import com.v2ray.ang.dto.V2rayConfig.OutboundBean import com.v2ray.ang.extension.idnHost import com.v2ray.ang.extension.isNotNullEmpty import com.v2ray.ang.handler.MmkvManager +import com.v2ray.ang.handler.V2rayConfigManager import com.v2ray.ang.util.Utils import java.net.URI @@ -144,7 +145,7 @@ object Hysteria2Fmt : FmtBase() { * @return the converted OutboundBean object, or null if conversion fails */ fun toOutbound(profileItem: ProfileItem): OutboundBean? { - val outboundBean = OutboundBean.create(EConfigType.HYSTERIA2) + val outboundBean = V2rayConfigManager.createOutbound(EConfigType.HYSTERIA2) return outboundBean } } \ No newline at end of file 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 e3c0edc5..e41e707e 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 @@ -7,6 +7,7 @@ import com.v2ray.ang.dto.NetworkType import com.v2ray.ang.dto.ProfileItem import com.v2ray.ang.dto.V2rayConfig.OutboundBean import com.v2ray.ang.extension.idnHost +import com.v2ray.ang.handler.V2rayConfigManager import com.v2ray.ang.util.Utils import java.net.URI @@ -131,7 +132,7 @@ object ShadowsocksFmt : FmtBase() { * @return the converted OutboundBean object, or null if conversion fails */ fun toOutbound(profileItem: ProfileItem): OutboundBean? { - val outboundBean = OutboundBean.create(EConfigType.SHADOWSOCKS) + val outboundBean = V2rayConfigManager.createOutbound(EConfigType.SHADOWSOCKS) outboundBean?.settings?.servers?.first()?.let { server -> server.address = profileItem.server.orEmpty() @@ -141,35 +142,11 @@ object ShadowsocksFmt : FmtBase() { } 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 - ) + V2rayConfigManager.populateTransportSettings(it, profileItem) } 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, - ) + V2rayConfigManager.populateTlsSettings(it, profileItem, sni) } return outboundBean diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/SocksFmt.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/SocksFmt.kt index f37030c2..39013e4b 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/SocksFmt.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/SocksFmt.kt @@ -5,6 +5,7 @@ import com.v2ray.ang.dto.ProfileItem import com.v2ray.ang.dto.V2rayConfig.OutboundBean import com.v2ray.ang.extension.idnHost import com.v2ray.ang.extension.isNotNullEmpty +import com.v2ray.ang.handler.V2rayConfigManager import com.v2ray.ang.util.Utils import java.net.URI @@ -60,7 +61,7 @@ object SocksFmt : FmtBase() { * @return the converted OutboundBean object, or null if conversion fails */ fun toOutbound(profileItem: ProfileItem): OutboundBean? { - val outboundBean = OutboundBean.create(EConfigType.SOCKS) + val outboundBean = V2rayConfigManager.createOutbound(EConfigType.SOCKS) outboundBean?.settings?.servers?.first()?.let { server -> server.address = profileItem.server.orEmpty() 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 f9c06299..efd83f9e 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 @@ -7,6 +7,7 @@ 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.handler.V2rayConfigManager import com.v2ray.ang.util.Utils import java.net.URI @@ -60,7 +61,7 @@ object TrojanFmt : FmtBase() { * @return the converted OutboundBean object, or null if conversion fails */ fun toOutbound(profileItem: ProfileItem): OutboundBean? { - val outboundBean = OutboundBean.create(EConfigType.TROJAN) + val outboundBean = V2rayConfigManager.createOutbound(EConfigType.TROJAN) outboundBean?.settings?.servers?.first()?.let { server -> server.address = profileItem.server.orEmpty() @@ -70,35 +71,11 @@ object TrojanFmt : FmtBase() { } 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 - ) + V2rayConfigManager.populateTransportSettings(it, profileItem) } 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, - ) + V2rayConfigManager.populateTlsSettings(it, profileItem, sni) } 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 ffa8f28e..fe835ad3 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,6 +6,7 @@ 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.handler.V2rayConfigManager import com.v2ray.ang.util.Utils import java.net.URI @@ -56,7 +57,7 @@ object VlessFmt : FmtBase() { * @return the converted OutboundBean object, or null if conversion fails */ fun toOutbound(profileItem: ProfileItem): OutboundBean? { - val outboundBean = OutboundBean.create(EConfigType.VLESS) + val outboundBean = V2rayConfigManager.createOutbound(EConfigType.VLESS) outboundBean?.settings?.vnext?.first()?.let { vnext -> vnext.address = profileItem.server.orEmpty() @@ -67,35 +68,11 @@ object VlessFmt : FmtBase() { } 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 - ) + V2rayConfigManager.populateTransportSettings(it, profileItem) } 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, - ) + V2rayConfigManager.populateTlsSettings(it, profileItem, sni) } 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 3e56b84e..002a75db 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 @@ -11,6 +11,7 @@ import com.v2ray.ang.dto.VmessQRCode import com.v2ray.ang.extension.idnHost import com.v2ray.ang.extension.isNotNullEmpty import com.v2ray.ang.handler.MmkvManager +import com.v2ray.ang.handler.V2rayConfigManager import com.v2ray.ang.util.JsonUtil import com.v2ray.ang.util.Utils import java.net.URI @@ -168,7 +169,7 @@ object VmessFmt : FmtBase() { * @return the converted OutboundBean object, or null if conversion fails */ fun toOutbound(profileItem: ProfileItem): OutboundBean? { - val outboundBean = OutboundBean.create(EConfigType.VMESS) + val outboundBean = V2rayConfigManager.createOutbound(EConfigType.VMESS) outboundBean?.settings?.vnext?.first()?.let { vnext -> vnext.address = profileItem.server.orEmpty() @@ -178,35 +179,11 @@ object VmessFmt : FmtBase() { } 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 - ) + V2rayConfigManager.populateTransportSettings(it, profileItem) } 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 - ) + V2rayConfigManager.populateTlsSettings(it, profileItem, sni) } return outboundBean diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/WireguardFmt.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/WireguardFmt.kt index e2bc5f90..10d4992a 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/WireguardFmt.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/fmt/WireguardFmt.kt @@ -7,6 +7,7 @@ import com.v2ray.ang.dto.ProfileItem import com.v2ray.ang.dto.V2rayConfig.OutboundBean import com.v2ray.ang.extension.idnHost import com.v2ray.ang.extension.removeWhiteSpace +import com.v2ray.ang.handler.V2rayConfigManager import com.v2ray.ang.util.Utils import java.net.URI @@ -105,7 +106,7 @@ object WireguardFmt : FmtBase() { * @return the converted OutboundBean object, or null if conversion fails */ fun toOutbound(profileItem: ProfileItem): OutboundBean? { - val outboundBean = OutboundBean.create(EConfigType.WIREGUARD) + val outboundBean = V2rayConfigManager.createOutbound(EConfigType.WIREGUARD) outboundBean?.settings?.let { wireguard -> wireguard.secretKey = profileItem.secretKey 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 42ac0a3e..6110f600 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 @@ -36,6 +36,9 @@ import com.v2ray.ang.dto.NetworkType import com.v2ray.ang.dto.ProfileItem import com.v2ray.ang.dto.RulesetItem import com.v2ray.ang.dto.V2rayConfig +import com.v2ray.ang.dto.V2rayConfig.OutboundBean +import com.v2ray.ang.dto.V2rayConfig.OutboundBean.OutSettingsBean +import com.v2ray.ang.dto.V2rayConfig.OutboundBean.StreamSettingsBean import com.v2ray.ang.dto.V2rayConfig.RoutingBean.RulesBean import com.v2ray.ang.extension.isNotNullEmpty import com.v2ray.ang.fmt.HttpFmt @@ -733,27 +736,6 @@ object V2rayConfigManager { return returnPair } - /** - * Retrieves the proxy outbound configuration for the given profile item. - * - * @param profileItem The profile item for which to get the proxy outbound configuration. - * @return The proxy outbound configuration as a V2rayConfig.OutboundBean, or null if not found. - */ - fun getProxyOutbound(profileItem: ProfileItem): V2rayConfig.OutboundBean? { - return when (profileItem.configType) { - EConfigType.VMESS -> VmessFmt.toOutbound(profileItem) - EConfigType.CUSTOM -> null - EConfigType.SHADOWSOCKS -> ShadowsocksFmt.toOutbound(profileItem) - EConfigType.SOCKS -> SocksFmt.toOutbound(profileItem) - EConfigType.VLESS -> VlessFmt.toOutbound(profileItem) - EConfigType.TROJAN -> TrojanFmt.toOutbound(profileItem) - EConfigType.WIREGUARD -> WireguardFmt.toOutbound(profileItem) - EConfigType.HYSTERIA2 -> Hysteria2Fmt.toOutbound(profileItem) - EConfigType.HTTP -> HttpFmt.toOutbound(profileItem) - } - - } - private fun resolveProxyDomainsToHosts(v2rayConfig: V2rayConfig) { val proxyOutboundList = v2rayConfig.getAllProxyOutbound() val dns = v2rayConfig.dns ?: return @@ -787,4 +769,204 @@ object V2rayConfigManager { dns.hosts = newHosts } + + /** + * Retrieves the proxy outbound configuration for the given profile item. + * + * @param profileItem The profile item for which to get the proxy outbound configuration. + * @return The proxy outbound configuration as a V2rayConfig.OutboundBean, or null if not found. + */ + private fun getProxyOutbound(profileItem: ProfileItem): V2rayConfig.OutboundBean? { + return when (profileItem.configType) { + EConfigType.VMESS -> VmessFmt.toOutbound(profileItem) + EConfigType.CUSTOM -> null + EConfigType.SHADOWSOCKS -> ShadowsocksFmt.toOutbound(profileItem) + EConfigType.SOCKS -> SocksFmt.toOutbound(profileItem) + EConfigType.VLESS -> VlessFmt.toOutbound(profileItem) + EConfigType.TROJAN -> TrojanFmt.toOutbound(profileItem) + EConfigType.WIREGUARD -> WireguardFmt.toOutbound(profileItem) + EConfigType.HYSTERIA2 -> Hysteria2Fmt.toOutbound(profileItem) + EConfigType.HTTP -> HttpFmt.toOutbound(profileItem) + } + } + + fun createOutbound(configType: EConfigType): OutboundBean? { + return when (configType) { + EConfigType.VMESS, + EConfigType.VLESS -> + return OutboundBean( + protocol = configType.name.lowercase(), + settings = OutSettingsBean( + vnext = listOf( + OutSettingsBean.VnextBean( + users = listOf(OutSettingsBean.VnextBean.UsersBean()) + ) + ) + ), + streamSettings = StreamSettingsBean() + ) + + EConfigType.SHADOWSOCKS, + EConfigType.SOCKS, + EConfigType.HTTP, + EConfigType.TROJAN, + EConfigType.HYSTERIA2 -> + return OutboundBean( + protocol = configType.name.lowercase(), + settings = OutSettingsBean( + servers = listOf(OutSettingsBean.ServersBean()) + ), + streamSettings = StreamSettingsBean() + ) + + EConfigType.WIREGUARD -> + return OutboundBean( + protocol = configType.name.lowercase(), + settings = OutSettingsBean( + secretKey = "", + peers = listOf(OutSettingsBean.WireGuardBean()) + ) + ) + + EConfigType.CUSTOM -> null + } + } + + fun populateTransportSettings(streamSettings: StreamSettingsBean, profileItem: ProfileItem): String? { + val transport = profileItem.network.orEmpty() + val headerType = profileItem.headerType + val host = profileItem.host + val path = profileItem.path + val seed = profileItem.seed +// val quicSecurity = profileItem.quicSecurity +// val key = profileItem.quicKey + val mode = profileItem.mode + val serviceName = profileItem.serviceName + val authority = profileItem.authority + val xhttpMode = profileItem.xhttpMode + val xhttpExtra = profileItem.xhttpExtra + + var sni: String? = null + streamSettings.network = if (transport.isEmpty()) NetworkType.TCP.type else transport + when (streamSettings.network) { + NetworkType.TCP.type -> { + val tcpSetting = StreamSettingsBean.TcpSettingsBean() + if (headerType == AppConfig.HEADER_TYPE_HTTP) { + tcpSetting.header.type = AppConfig.HEADER_TYPE_HTTP + if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(path)) { + val requestObj = StreamSettingsBean.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 = StreamSettingsBean.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 = StreamSettingsBean.WsSettingsBean() + wssetting.headers.Host = host.orEmpty() + sni = host + wssetting.path = path ?: "/" + streamSettings.wsSettings = wssetting + } + + NetworkType.HTTP_UPGRADE.type -> { + val httpupgradeSetting = StreamSettingsBean.HttpupgradeSettingsBean() + httpupgradeSetting.host = host.orEmpty() + sni = host + httpupgradeSetting.path = path ?: "/" + streamSettings.httpupgradeSettings = httpupgradeSetting + } + + NetworkType.XHTTP.type -> { + val xhttpSetting = StreamSettingsBean.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 = StreamSettingsBean.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 = StreamSettingsBean.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, profileItem: ProfileItem, sniExt: String?) { + val streamSecurity = profileItem.security.orEmpty() + val allowInsecure = profileItem.insecure == true + val sni = if (profileItem.sni.isNullOrEmpty()) sniExt else profileItem.sni + val fingerprint = profileItem.fingerPrint + val alpns = profileItem.alpn + val publicKey = profileItem.publicKey + val shortId = profileItem.shortId + val spiderX = profileItem.spiderX + + streamSettings.security = if (streamSecurity.isEmpty()) null else streamSecurity + if (streamSettings.security == null) return + val tlsSetting = StreamSettingsBean.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 + } + } } diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/util/HttpUtil.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/util/HttpUtil.kt index d9c3d86b..371fa509 100644 --- a/V2rayNG/app/src/main/java/com/v2ray/ang/util/HttpUtil.kt +++ b/V2rayNG/app/src/main/java/com/v2ray/ang/util/HttpUtil.kt @@ -9,8 +9,8 @@ import com.v2ray.ang.util.Utils.urlDecode import java.io.IOException import java.net.HttpURLConnection import java.net.IDN -import java.net.InetAddress import java.net.Inet6Address +import java.net.InetAddress import java.net.InetSocketAddress import java.net.Proxy import java.net.URL