Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5daef71147 | ||
|
|
5ffc5ec502 | ||
|
|
35063db3e6 | ||
|
|
868c24bb8b | ||
|
|
7367baffb8 | ||
|
|
819ff2995a | ||
|
|
3b5d04b717 | ||
|
|
b673cd73ac | ||
|
|
649c1a022b | ||
|
|
034e58bc9d |
@@ -11,8 +11,8 @@ android {
|
||||
applicationId = "com.v2ray.ang"
|
||||
minSdk = 21
|
||||
targetSdk = 34
|
||||
versionCode = 599
|
||||
versionName = "1.9.6"
|
||||
versionCode = 602
|
||||
versionName = "1.9.8"
|
||||
multiDexEnabled = true
|
||||
splits {
|
||||
abi {
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
[
|
||||
{
|
||||
"remarks": "Google cn",
|
||||
"outboundTag": "proxy",
|
||||
"domain": [
|
||||
"domain:googleapis.cn",
|
||||
"domain:gstatic.com"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "阻断udp443",
|
||||
"outboundTag": "block",
|
||||
@@ -34,43 +26,27 @@
|
||||
"geosite:private"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "绕过中国IP",
|
||||
"outboundTag": "direct",
|
||||
"ip": [
|
||||
"geoip:cn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "绕过中国域名",
|
||||
"outboundTag": "direct",
|
||||
"domain": [
|
||||
"domain:dns.alidns.com",
|
||||
"domain:doh.pub",
|
||||
"domain:dot.pub",
|
||||
"domain:doh.360.cn",
|
||||
"domain:dot.360.cn",
|
||||
"geosite:cn",
|
||||
"geosite:geolocation-cn"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "绕过中国IP",
|
||||
"outboundTag": "direct",
|
||||
"ip": [
|
||||
"223.5.5.5/32",
|
||||
"223.6.6.6/32",
|
||||
"2400:3200::1/128",
|
||||
"2400:3200:baba::1/128",
|
||||
"119.29.29.29/32",
|
||||
"1.12.12.12/32",
|
||||
"120.53.53.53/32",
|
||||
"2402:4e00::/128",
|
||||
"2402:4e00:1::/128",
|
||||
"180.76.76.76/32",
|
||||
"2400:da00::6666/128",
|
||||
"114.114.114.114/32",
|
||||
"114.114.115.115/32",
|
||||
"180.184.1.1/32",
|
||||
"180.184.2.2/32",
|
||||
"101.226.4.6/32",
|
||||
"218.30.118.6/32",
|
||||
"123.125.81.6/32",
|
||||
"140.207.198.6/32",
|
||||
"geoip:cn"
|
||||
"remarks": "Google CN",
|
||||
"outboundTag": "proxy",
|
||||
"domain": [
|
||||
"domain:googleapis.cn",
|
||||
"domain:gstatic.com"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -78,4 +54,4 @@
|
||||
"port": "0-65535",
|
||||
"outboundTag": "proxy"
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
49
V2rayNG/app/src/main/assets/custom_routing_white_iran
Normal file
49
V2rayNG/app/src/main/assets/custom_routing_white_iran
Normal file
@@ -0,0 +1,49 @@
|
||||
[
|
||||
{
|
||||
"remarks": "Block udp443",
|
||||
"outboundTag": "block",
|
||||
"port": "443",
|
||||
"network": "udp"
|
||||
},
|
||||
{
|
||||
"remarks": "Block ads and trackers",
|
||||
"outboundTag": "block",
|
||||
"domain": [
|
||||
"geosite:category-ads-all"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "Direct LAN IP",
|
||||
"outboundTag": "direct",
|
||||
"ip": [
|
||||
"geoip:private"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "Direct LAN domains",
|
||||
"outboundTag": "direct",
|
||||
"domain": [
|
||||
"geosite:private"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "Bypass Iran domains",
|
||||
"outboundTag": "direct",
|
||||
"domain": [
|
||||
"domain:ir",
|
||||
"geosite:category-ir"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "Bypass Iran IP",
|
||||
"outboundTag": "direct",
|
||||
"ip": [
|
||||
"geoip:ir"
|
||||
]
|
||||
},
|
||||
{
|
||||
"remarks": "Final Agent",
|
||||
"port": "0-65535",
|
||||
"outboundTag": "proxy"
|
||||
}
|
||||
]
|
||||
@@ -199,6 +199,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
|
||||
fun startV2Ray() {
|
||||
if (MmkvManager.getSelectServer().isNullOrEmpty()) {
|
||||
toast(R.string.title_file_chooser)
|
||||
return
|
||||
}
|
||||
V2RayServiceManager.startV2Ray(this)
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.text.TextUtils
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.AppConfig.GEOIP_PRIVATE
|
||||
import com.v2ray.ang.AppConfig.GEOSITE_PRIVATE
|
||||
import com.v2ray.ang.AppConfig.TAG_DIRECT
|
||||
import com.v2ray.ang.dto.RulesetItem
|
||||
import com.v2ray.ang.dto.ServerConfig
|
||||
import com.v2ray.ang.util.MmkvManager.decodeProfileConfig
|
||||
@@ -30,6 +31,7 @@ object SettingsManager {
|
||||
0 -> "custom_routing_white"
|
||||
1 -> "custom_routing_black"
|
||||
2 -> "custom_routing_global"
|
||||
3 -> "custom_routing_white_iran"
|
||||
else -> "custom_routing_white"
|
||||
}
|
||||
val assets = Utils.readTextFromAssets(context, fileName)
|
||||
@@ -111,10 +113,8 @@ object SettingsManager {
|
||||
|
||||
fun routingRulesetsBypassLan(): Boolean {
|
||||
val rulesetItems = MmkvManager.decodeRoutingRulesets()
|
||||
val exist = rulesetItems?.any {
|
||||
it.enabled
|
||||
&& (it.domain?.contains(GEOSITE_PRIVATE) == true
|
||||
|| it.ip?.contains(GEOIP_PRIVATE) == true)
|
||||
val exist = rulesetItems?.filter { it.enabled && it.outboundTag == TAG_DIRECT }?.any {
|
||||
it.domain?.contains(GEOSITE_PRIVATE) == true || it.ip?.contains(GEOIP_PRIVATE) == true
|
||||
}
|
||||
return exist == true
|
||||
}
|
||||
|
||||
104
V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/FmtBase.kt
Normal file
104
V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/FmtBase.kt
Normal file
@@ -0,0 +1,104 @@
|
||||
package com.v2ray.ang.util.fmt
|
||||
|
||||
import android.text.TextUtils
|
||||
import com.v2ray.ang.dto.V2rayConfig
|
||||
import com.v2ray.ang.util.Utils
|
||||
|
||||
open class FmtBase {
|
||||
fun toUri(address: String?, port: Int?, userInfo: String?, dicQuery: HashMap<String, String>?, remark: String): String {
|
||||
val query = if (dicQuery != null)
|
||||
("?" + dicQuery.toList().joinToString(
|
||||
separator = "&",
|
||||
transform = { it.first + "=" + Utils.urlEncode(it.second) }))
|
||||
else ""
|
||||
|
||||
val url = String.format(
|
||||
"%s@%s:%s",
|
||||
Utils.urlEncode(userInfo ?: ""),
|
||||
Utils.getIpv6Address(address),
|
||||
port
|
||||
)
|
||||
|
||||
return "${url}${query}#${Utils.urlEncode(remark)}"
|
||||
}
|
||||
|
||||
fun getStdTransport(outbound: V2rayConfig.OutboundBean, streamSetting: V2rayConfig.OutboundBean.StreamSettingsBean): HashMap<String, String> {
|
||||
val dicQuery = HashMap<String, String>()
|
||||
|
||||
dicQuery["security"] = streamSetting.security.ifEmpty { "none" }
|
||||
(streamSetting.tlsSettings
|
||||
?: streamSetting.realitySettings)?.let { tlsSetting ->
|
||||
if (!TextUtils.isEmpty(tlsSetting.serverName)) {
|
||||
dicQuery["sni"] = tlsSetting.serverName
|
||||
}
|
||||
if (!tlsSetting.alpn.isNullOrEmpty() && tlsSetting.alpn.isNotEmpty()) {
|
||||
dicQuery["alpn"] =
|
||||
Utils.removeWhiteSpace(tlsSetting.alpn.joinToString(",")).orEmpty()
|
||||
}
|
||||
if (!TextUtils.isEmpty(tlsSetting.fingerprint)) {
|
||||
dicQuery["fp"] = tlsSetting.fingerprint.orEmpty()
|
||||
}
|
||||
if (!TextUtils.isEmpty(tlsSetting.publicKey)) {
|
||||
dicQuery["pbk"] = tlsSetting.publicKey.orEmpty()
|
||||
}
|
||||
if (!TextUtils.isEmpty(tlsSetting.shortId)) {
|
||||
dicQuery["sid"] = tlsSetting.shortId.orEmpty()
|
||||
}
|
||||
if (!TextUtils.isEmpty(tlsSetting.spiderX)) {
|
||||
dicQuery["spx"] = tlsSetting.spiderX.orEmpty()
|
||||
}
|
||||
}
|
||||
dicQuery["type"] =
|
||||
streamSetting.network.ifEmpty { V2rayConfig.DEFAULT_NETWORK }
|
||||
|
||||
outbound.getTransportSettingDetails()?.let { transportDetails ->
|
||||
when (streamSetting.network) {
|
||||
"tcp" -> {
|
||||
dicQuery["headerType"] = transportDetails[0].ifEmpty { "none" }
|
||||
if (!TextUtils.isEmpty(transportDetails[1])) {
|
||||
dicQuery["host"] = transportDetails[1]
|
||||
}
|
||||
}
|
||||
|
||||
"kcp" -> {
|
||||
dicQuery["headerType"] = transportDetails[0].ifEmpty { "none" }
|
||||
if (!TextUtils.isEmpty(transportDetails[2])) {
|
||||
dicQuery["seed"] = transportDetails[2]
|
||||
}
|
||||
}
|
||||
|
||||
"ws", "httpupgrade", "splithttp" -> {
|
||||
if (!TextUtils.isEmpty(transportDetails[1])) {
|
||||
dicQuery["host"] = transportDetails[1]
|
||||
}
|
||||
if (!TextUtils.isEmpty(transportDetails[2])) {
|
||||
dicQuery["path"] = transportDetails[2]
|
||||
}
|
||||
}
|
||||
|
||||
"http", "h2" -> {
|
||||
dicQuery["type"] = "http"
|
||||
if (!TextUtils.isEmpty(transportDetails[1])) {
|
||||
dicQuery["host"] = transportDetails[1]
|
||||
}
|
||||
if (!TextUtils.isEmpty(transportDetails[2])) {
|
||||
dicQuery["path"] = transportDetails[2]
|
||||
}
|
||||
}
|
||||
|
||||
"quic" -> {
|
||||
dicQuery["headerType"] = transportDetails[0].ifEmpty { "none" }
|
||||
dicQuery["quicSecurity"] = transportDetails[1]
|
||||
dicQuery["key"] = transportDetails[2]
|
||||
}
|
||||
|
||||
"grpc" -> {
|
||||
dicQuery["mode"] = transportDetails[0]
|
||||
dicQuery["authority"] = transportDetails[1]
|
||||
dicQuery["serviceName"] = transportDetails[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
return dicQuery
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import com.v2ray.ang.util.MmkvManager.settingsStorage
|
||||
import com.v2ray.ang.util.Utils
|
||||
import java.net.URI
|
||||
|
||||
object Hysteria2Fmt {
|
||||
object Hysteria2Fmt : FmtBase() {
|
||||
|
||||
fun parse(str: String): ServerConfig {
|
||||
var allowInsecure = settingsStorage?.decodeBool(AppConfig.PREF_ALLOW_INSECURE) ?: false
|
||||
@@ -51,7 +51,7 @@ object Hysteria2Fmt {
|
||||
val outbound = config.getProxyOutbound() ?: return ""
|
||||
val streamSetting = outbound.streamSettings ?: V2rayConfig.OutboundBean.StreamSettingsBean()
|
||||
|
||||
val remark = "#" + Utils.urlEncode(config.remarks)
|
||||
|
||||
val dicQuery = HashMap<String, String>()
|
||||
dicQuery["security"] = streamSetting.security.ifEmpty { "none" }
|
||||
streamSetting.tlsSettings?.let { tlsSetting ->
|
||||
@@ -68,17 +68,7 @@ object Hysteria2Fmt {
|
||||
dicQuery["obfs-password"] = outbound.settings?.obfsPassword ?: ""
|
||||
}
|
||||
|
||||
val query = "?" + dicQuery.toList().joinToString(
|
||||
separator = "&",
|
||||
transform = { it.first + "=" + it.second })
|
||||
|
||||
val url = String.format(
|
||||
"%s@%s:%s",
|
||||
outbound.getPassword(),
|
||||
Utils.getIpv6Address(outbound.getServerAddress()),
|
||||
outbound.getServerPort()
|
||||
)
|
||||
return url + query + remark
|
||||
return toUri(outbound.getServerAddress(), outbound.getServerPort(), outbound.getPassword(), dicQuery, config.remarks)
|
||||
}
|
||||
|
||||
fun toNativeConfig(config: ServerConfig, socksPort: Int): Hysteria2Bean? {
|
||||
|
||||
@@ -8,7 +8,7 @@ import com.v2ray.ang.extension.idnHost
|
||||
import com.v2ray.ang.util.Utils
|
||||
import java.net.URI
|
||||
|
||||
object ShadowsocksFmt {
|
||||
object ShadowsocksFmt : FmtBase() {
|
||||
fun parse(str: String): ServerConfig? {
|
||||
val config = ServerConfig.create(EConfigType.SHADOWSOCKS)
|
||||
if (!tryResolveResolveSip002(str, config)) {
|
||||
@@ -52,16 +52,10 @@ object ShadowsocksFmt {
|
||||
|
||||
fun toUri(config: ServerConfig): String {
|
||||
val outbound = config.getProxyOutbound() ?: return ""
|
||||
val remark = "#" + Utils.urlEncode(config.remarks)
|
||||
val pw =
|
||||
Utils.encode("${outbound.getSecurityEncryption()}:${outbound.getPassword()}")
|
||||
val url = String.format(
|
||||
"%s@%s:%s",
|
||||
pw,
|
||||
Utils.getIpv6Address(outbound.getServerAddress()),
|
||||
outbound.getServerPort()
|
||||
)
|
||||
return url + remark
|
||||
|
||||
val pw = Utils.encode("${outbound.getSecurityEncryption()}:${outbound.getPassword()}")
|
||||
|
||||
return toUri(outbound.getServerAddress(), outbound.getServerPort(), pw, null, config.remarks)
|
||||
}
|
||||
|
||||
private fun tryResolveResolveSip002(str: String, config: ServerConfig): Boolean {
|
||||
|
||||
@@ -5,7 +5,7 @@ import com.v2ray.ang.dto.ServerConfig
|
||||
import com.v2ray.ang.dto.V2rayConfig
|
||||
import com.v2ray.ang.util.Utils
|
||||
|
||||
object SocksFmt {
|
||||
object SocksFmt : FmtBase() {
|
||||
fun parse(str: String): ServerConfig? {
|
||||
val config = ServerConfig.create(EConfigType.SOCKS)
|
||||
var result = str.replace(EConfigType.SOCKS.protocolScheme, "")
|
||||
@@ -52,18 +52,13 @@ object SocksFmt {
|
||||
|
||||
fun toUri(config: ServerConfig): String {
|
||||
val outbound = config.getProxyOutbound() ?: return ""
|
||||
val remark = "#" + Utils.urlEncode(config.remarks)
|
||||
|
||||
val pw =
|
||||
if (outbound.settings?.servers?.get(0)?.users?.get(0)?.user != null)
|
||||
"${outbound.settings?.servers?.get(0)?.users?.get(0)?.user}:${outbound.getPassword()}"
|
||||
else
|
||||
":"
|
||||
val url = String.format(
|
||||
"%s@%s:%s",
|
||||
Utils.encode(pw),
|
||||
Utils.getIpv6Address(outbound.getServerAddress()),
|
||||
outbound.getServerPort()
|
||||
)
|
||||
return url + remark
|
||||
|
||||
return toUri(outbound.getServerAddress(), outbound.getServerPort(), pw, null, config.remarks)
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import com.v2ray.ang.util.MmkvManager.settingsStorage
|
||||
import com.v2ray.ang.util.Utils
|
||||
import java.net.URI
|
||||
|
||||
object TrojanFmt {
|
||||
object TrojanFmt : FmtBase() {
|
||||
|
||||
fun parse(str: String): ServerConfig {
|
||||
var allowInsecure = settingsStorage?.decodeBool(AppConfig.PREF_ALLOW_INSECURE) ?: false
|
||||
@@ -76,98 +76,15 @@ object TrojanFmt {
|
||||
val outbound = config.getProxyOutbound() ?: return ""
|
||||
val streamSetting = outbound.streamSettings ?: V2rayConfig.OutboundBean.StreamSettingsBean()
|
||||
|
||||
val remark = "#" + Utils.urlEncode(config.remarks)
|
||||
val dicQuery = HashMap<String, String>()
|
||||
|
||||
val dicQuery = getStdTransport(outbound, streamSetting)
|
||||
|
||||
config.outboundBean?.settings?.servers?.get(0)?.flow?.let {
|
||||
if (!TextUtils.isEmpty(it)) {
|
||||
dicQuery["flow"] = it
|
||||
}
|
||||
}
|
||||
|
||||
dicQuery["security"] = streamSetting.security.ifEmpty { "none" }
|
||||
(streamSetting.tlsSettings
|
||||
?: streamSetting.realitySettings)?.let { tlsSetting ->
|
||||
if (!TextUtils.isEmpty(tlsSetting.serverName)) {
|
||||
dicQuery["sni"] = tlsSetting.serverName
|
||||
}
|
||||
if (!tlsSetting.alpn.isNullOrEmpty() && tlsSetting.alpn.isNotEmpty()) {
|
||||
dicQuery["alpn"] =
|
||||
Utils.removeWhiteSpace(tlsSetting.alpn.joinToString(",")).orEmpty()
|
||||
}
|
||||
if (!TextUtils.isEmpty(tlsSetting.fingerprint)) {
|
||||
dicQuery["fp"] = tlsSetting.fingerprint.orEmpty()
|
||||
}
|
||||
if (!TextUtils.isEmpty(tlsSetting.publicKey)) {
|
||||
dicQuery["pbk"] = tlsSetting.publicKey.orEmpty()
|
||||
}
|
||||
if (!TextUtils.isEmpty(tlsSetting.shortId)) {
|
||||
dicQuery["sid"] = tlsSetting.shortId.orEmpty()
|
||||
}
|
||||
if (!TextUtils.isEmpty(tlsSetting.spiderX)) {
|
||||
dicQuery["spx"] = Utils.urlEncode(tlsSetting.spiderX.orEmpty())
|
||||
}
|
||||
}
|
||||
dicQuery["type"] =
|
||||
streamSetting.network.ifEmpty { V2rayConfig.DEFAULT_NETWORK }
|
||||
|
||||
outbound.getTransportSettingDetails()?.let { transportDetails ->
|
||||
when (streamSetting.network) {
|
||||
"tcp" -> {
|
||||
dicQuery["headerType"] = transportDetails[0].ifEmpty { "none" }
|
||||
if (!TextUtils.isEmpty(transportDetails[1])) {
|
||||
dicQuery["host"] = Utils.urlEncode(transportDetails[1])
|
||||
}
|
||||
}
|
||||
|
||||
"kcp" -> {
|
||||
dicQuery["headerType"] = transportDetails[0].ifEmpty { "none" }
|
||||
if (!TextUtils.isEmpty(transportDetails[2])) {
|
||||
dicQuery["seed"] = Utils.urlEncode(transportDetails[2])
|
||||
}
|
||||
}
|
||||
|
||||
"ws", "httpupgrade", "splithttp" -> {
|
||||
if (!TextUtils.isEmpty(transportDetails[1])) {
|
||||
dicQuery["host"] = Utils.urlEncode(transportDetails[1])
|
||||
}
|
||||
if (!TextUtils.isEmpty(transportDetails[2])) {
|
||||
dicQuery["path"] = Utils.urlEncode(transportDetails[2])
|
||||
}
|
||||
}
|
||||
|
||||
"http", "h2" -> {
|
||||
dicQuery["type"] = "http"
|
||||
if (!TextUtils.isEmpty(transportDetails[1])) {
|
||||
dicQuery["host"] = Utils.urlEncode(transportDetails[1])
|
||||
}
|
||||
if (!TextUtils.isEmpty(transportDetails[2])) {
|
||||
dicQuery["path"] = Utils.urlEncode(transportDetails[2])
|
||||
}
|
||||
}
|
||||
|
||||
"quic" -> {
|
||||
dicQuery["headerType"] = transportDetails[0].ifEmpty { "none" }
|
||||
dicQuery["quicSecurity"] = Utils.urlEncode(transportDetails[1])
|
||||
dicQuery["key"] = Utils.urlEncode(transportDetails[2])
|
||||
}
|
||||
|
||||
"grpc" -> {
|
||||
dicQuery["mode"] = transportDetails[0]
|
||||
dicQuery["authority"] = Utils.urlEncode(transportDetails[1])
|
||||
dicQuery["serviceName"] = Utils.urlEncode(transportDetails[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
val query = "?" + dicQuery.toList().joinToString(
|
||||
separator = "&",
|
||||
transform = { it.first + "=" + it.second })
|
||||
|
||||
val url = String.format(
|
||||
"%s@%s:%s",
|
||||
outbound.getPassword(),
|
||||
Utils.getIpv6Address(outbound.getServerAddress()),
|
||||
outbound.getServerPort()
|
||||
)
|
||||
return url + query + remark
|
||||
return toUri(outbound.getServerAddress(), outbound.getServerPort(), outbound.getPassword(), dicQuery, config.remarks)
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import com.v2ray.ang.util.MmkvManager.settingsStorage
|
||||
import com.v2ray.ang.util.Utils
|
||||
import java.net.URI
|
||||
|
||||
object VlessFmt {
|
||||
object VlessFmt : FmtBase() {
|
||||
|
||||
fun parse(str: String): ServerConfig? {
|
||||
var allowInsecure = settingsStorage?.decodeBool(AppConfig.PREF_ALLOW_INSECURE) ?: false
|
||||
@@ -63,8 +63,9 @@ object VlessFmt {
|
||||
val outbound = config.getProxyOutbound() ?: return ""
|
||||
val streamSetting = outbound.streamSettings ?: V2rayConfig.OutboundBean.StreamSettingsBean()
|
||||
|
||||
val remark = "#" + Utils.urlEncode(config.remarks)
|
||||
val dicQuery = HashMap<String, String>()
|
||||
|
||||
val dicQuery = getStdTransport(outbound, streamSetting)
|
||||
|
||||
outbound.settings?.vnext?.get(0)?.users?.get(0)?.flow?.let {
|
||||
if (!TextUtils.isEmpty(it)) {
|
||||
dicQuery["flow"] = it
|
||||
@@ -74,91 +75,6 @@ object VlessFmt {
|
||||
if (outbound.getSecurityEncryption().isNullOrEmpty()) "none"
|
||||
else outbound.getSecurityEncryption().orEmpty()
|
||||
|
||||
|
||||
dicQuery["security"] = streamSetting.security.ifEmpty { "none" }
|
||||
(streamSetting.tlsSettings
|
||||
?: streamSetting.realitySettings)?.let { tlsSetting ->
|
||||
if (!TextUtils.isEmpty(tlsSetting.serverName)) {
|
||||
dicQuery["sni"] = tlsSetting.serverName
|
||||
}
|
||||
if (!tlsSetting.alpn.isNullOrEmpty() && tlsSetting.alpn.isNotEmpty()) {
|
||||
dicQuery["alpn"] =
|
||||
Utils.removeWhiteSpace(tlsSetting.alpn.joinToString(",")).orEmpty()
|
||||
}
|
||||
if (!TextUtils.isEmpty(tlsSetting.fingerprint)) {
|
||||
dicQuery["fp"] = tlsSetting.fingerprint.orEmpty()
|
||||
}
|
||||
if (!TextUtils.isEmpty(tlsSetting.publicKey)) {
|
||||
dicQuery["pbk"] = tlsSetting.publicKey.orEmpty()
|
||||
}
|
||||
if (!TextUtils.isEmpty(tlsSetting.shortId)) {
|
||||
dicQuery["sid"] = tlsSetting.shortId.orEmpty()
|
||||
}
|
||||
if (!TextUtils.isEmpty(tlsSetting.spiderX)) {
|
||||
dicQuery["spx"] = Utils.urlEncode(tlsSetting.spiderX.orEmpty())
|
||||
}
|
||||
}
|
||||
dicQuery["type"] =
|
||||
streamSetting.network.ifEmpty { V2rayConfig.DEFAULT_NETWORK }
|
||||
|
||||
outbound.getTransportSettingDetails()?.let { transportDetails ->
|
||||
when (streamSetting.network) {
|
||||
"tcp" -> {
|
||||
dicQuery["headerType"] = transportDetails[0].ifEmpty { "none" }
|
||||
if (!TextUtils.isEmpty(transportDetails[1])) {
|
||||
dicQuery["host"] = Utils.urlEncode(transportDetails[1])
|
||||
}
|
||||
}
|
||||
|
||||
"kcp" -> {
|
||||
dicQuery["headerType"] = transportDetails[0].ifEmpty { "none" }
|
||||
if (!TextUtils.isEmpty(transportDetails[2])) {
|
||||
dicQuery["seed"] = Utils.urlEncode(transportDetails[2])
|
||||
}
|
||||
}
|
||||
|
||||
"ws", "httpupgrade", "splithttp" -> {
|
||||
if (!TextUtils.isEmpty(transportDetails[1])) {
|
||||
dicQuery["host"] = Utils.urlEncode(transportDetails[1])
|
||||
}
|
||||
if (!TextUtils.isEmpty(transportDetails[2])) {
|
||||
dicQuery["path"] = Utils.urlEncode(transportDetails[2])
|
||||
}
|
||||
}
|
||||
|
||||
"http", "h2" -> {
|
||||
dicQuery["type"] = "http"
|
||||
if (!TextUtils.isEmpty(transportDetails[1])) {
|
||||
dicQuery["host"] = Utils.urlEncode(transportDetails[1])
|
||||
}
|
||||
if (!TextUtils.isEmpty(transportDetails[2])) {
|
||||
dicQuery["path"] = Utils.urlEncode(transportDetails[2])
|
||||
}
|
||||
}
|
||||
|
||||
"quic" -> {
|
||||
dicQuery["headerType"] = transportDetails[0].ifEmpty { "none" }
|
||||
dicQuery["quicSecurity"] = Utils.urlEncode(transportDetails[1])
|
||||
dicQuery["key"] = Utils.urlEncode(transportDetails[2])
|
||||
}
|
||||
|
||||
"grpc" -> {
|
||||
dicQuery["mode"] = transportDetails[0]
|
||||
dicQuery["authority"] = Utils.urlEncode(transportDetails[1])
|
||||
dicQuery["serviceName"] = Utils.urlEncode(transportDetails[2])
|
||||
}
|
||||
}
|
||||
}
|
||||
val query = "?" + dicQuery.toList().joinToString(
|
||||
separator = "&",
|
||||
transform = { it.first + "=" + it.second })
|
||||
|
||||
val url = String.format(
|
||||
"%s@%s:%s",
|
||||
outbound.getPassword(),
|
||||
Utils.getIpv6Address(outbound.getServerAddress()),
|
||||
outbound.getServerPort()
|
||||
)
|
||||
return url + query + remark
|
||||
return toUri(outbound.getServerAddress(), outbound.getServerPort(), outbound.getPassword(), dicQuery, config.remarks)
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import com.v2ray.ang.util.MmkvManager.settingsStorage
|
||||
import com.v2ray.ang.util.Utils
|
||||
import java.net.URI
|
||||
|
||||
object VmessFmt {
|
||||
object VmessFmt : FmtBase() {
|
||||
|
||||
fun parse(str: String): ServerConfig? {
|
||||
if (str.indexOf('?') > 0 && str.indexOf('&') > 0) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import com.v2ray.ang.extension.removeWhiteSpace
|
||||
import com.v2ray.ang.util.Utils
|
||||
import java.net.URI
|
||||
|
||||
object WireguardFmt {
|
||||
object WireguardFmt : FmtBase() {
|
||||
fun parse(str: String): ServerConfig? {
|
||||
val uri = URI(Utils.fixIllegalUrl(str))
|
||||
if (uri.rawQuery != null) {
|
||||
@@ -71,37 +71,22 @@ object WireguardFmt {
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun toUri(config: ServerConfig): String {
|
||||
val outbound = config.getProxyOutbound() ?: return ""
|
||||
|
||||
val remark = "#" + Utils.urlEncode(config.remarks)
|
||||
|
||||
val dicQuery = HashMap<String, String>()
|
||||
dicQuery["publickey"] =
|
||||
Utils.urlEncode(outbound.settings?.peers?.get(0)?.publicKey.toString())
|
||||
dicQuery["publickey"] = outbound.settings?.peers?.get(0)?.publicKey.toString()
|
||||
if (outbound.settings?.reserved != null) {
|
||||
dicQuery["reserved"] = Utils.urlEncode(
|
||||
Utils.removeWhiteSpace(outbound.settings?.reserved?.joinToString(","))
|
||||
.toString()
|
||||
)
|
||||
dicQuery["reserved"] = Utils.removeWhiteSpace(outbound.settings?.reserved?.joinToString(",")).toString()
|
||||
|
||||
}
|
||||
dicQuery["address"] = Utils.urlEncode(
|
||||
Utils.removeWhiteSpace((outbound.settings?.address as List<*>).joinToString(","))
|
||||
.toString()
|
||||
)
|
||||
dicQuery["address"] = Utils.removeWhiteSpace((outbound.settings?.address as List<*>).joinToString(",")).toString()
|
||||
|
||||
if (outbound.settings?.mtu != null) {
|
||||
dicQuery["mtu"] = outbound.settings?.mtu.toString()
|
||||
}
|
||||
val query = "?" + dicQuery.toList().joinToString(
|
||||
separator = "&",
|
||||
transform = { it.first + "=" + it.second })
|
||||
|
||||
val url = String.format(
|
||||
"%s@%s:%s",
|
||||
Utils.urlEncode(outbound.getPassword().toString()),
|
||||
Utils.getIpv6Address(outbound.getServerAddress()),
|
||||
outbound.getServerPort()
|
||||
)
|
||||
return url + query + remark
|
||||
return toUri(outbound.getServerAddress(), outbound.getServerPort(), outbound.getPassword(), dicQuery, config.remarks)
|
||||
}
|
||||
}
|
||||
@@ -127,8 +127,8 @@
|
||||
<string name="title_vpn_settings">تنظیمات VPN</string>
|
||||
<string name="title_pref_per_app_proxy">پروکسی به تفکیک برنامه</string>
|
||||
<string name="summary_pref_per_app_proxy">عمومی: برنامه بررسی شده پروکسی است، اتصال مستقیم بدون بررسی است. \nحالت bypass: برنامه بررسی شده مستقیما متصل است، پراکسی بررسی نشده است. \nگزینهای برای انتخاب خودکار پروکسی برنامه در منو است</string>
|
||||
<string name="title_pref_is_booted">Auto connect at startup</string>
|
||||
<string name="summary_pref_is_booted">Automatically connects to the selected server at startup, which may be unsuccessful</string>
|
||||
<string name="title_pref_is_booted">اتصال خودکار هنگام راه اندازی</string>
|
||||
<string name="summary_pref_is_booted">هنگام راه اندازی به طور خودکار به سرور انتخابی متصل می شود که ممکن است ناموفق باشد</string>
|
||||
|
||||
<string name="title_mux_settings">تنظیمات Mux</string>
|
||||
<string name="title_pref_mux_enabled">فعال کردن Mux</string>
|
||||
@@ -147,8 +147,8 @@
|
||||
|
||||
<string name="title_pref_sniffing_enabled">فعال کردن Sniffing</string>
|
||||
<string name="summary_pref_sniffing_enabled">دامنه sniff را از بسته امتحان کنید (پیشفرض روشن)</string>
|
||||
<string name="title_pref_route_only_enabled">Enable routeOnly</string>
|
||||
<string name="summary_pref_route_only_enabled">Use the sniffed domain name for routing only, and keep the target address as the IP address.</string>
|
||||
<string name="title_pref_route_only_enabled">فعال کردن routeOnly</string>
|
||||
<string name="summary_pref_route_only_enabled">از نام دامنه sniffed فقط برای مسیریابی استفاده کنید و آدرس مورد نظر را به عنوان آدرس IP نگه دارید.</string>
|
||||
|
||||
|
||||
<string name="title_pref_local_dns_enabled">فعال کردن DNS محلی</string>
|
||||
@@ -175,8 +175,8 @@
|
||||
<string name="summary_pref_proxy_sharing_enabled">دستگاههای دیگر میتوانند از طریق socks/http به پراکسی توسط نشانی آیپی شما متصل شوند، فقط در شبکه مورد اعتماد فعال میشوند تا از اتصال غیرمجاز جلوگیری کنند</string>
|
||||
<string name="toast_warning_pref_proxysharing_short">اتصالات از طریق LAN را مجاز کنید، مطمئن شوید که در یک شبکه قابل اعتماد هستید</string>
|
||||
|
||||
<string name="title_pref_allow_insecure">allowInsecure</string>
|
||||
<string name="summary_pref_allow_insecure">هنگام استفاده از TLS، به طور پیشفرض allowInsecure فعال است</string>
|
||||
<string name="title_pref_allow_insecure">موز ناامن</string>
|
||||
<string name="summary_pref_allow_insecure">هنگام استفاده از TLS، به طور پیشفرض مجوز ناامن فعال است</string>
|
||||
|
||||
<string name="title_pref_socks_port">پورت پروکسی SOCKS5</string>
|
||||
<string name="summary_pref_socks_port">پورت پروکسی SOCKS5</string>
|
||||
@@ -200,12 +200,12 @@
|
||||
|
||||
<string name="title_privacy_policy">حریم خصوصی</string>
|
||||
<string name="title_about">درباره</string>
|
||||
<string name="title_source_code">Source code</string>
|
||||
<string name="title_tg_channel">Telegram channel</string>
|
||||
<string name="title_configuration_backup">Backup configuration</string>
|
||||
<string name="summary_configuration_backup">Storage location: [%s], The backup will be cleared after uninstalling the app or clearing the storage</string>
|
||||
<string name="title_configuration_restore">Restore configuration</string>
|
||||
<string name="title_configuration_share">Share configuration</string>
|
||||
<string name="title_source_code">کد منبع</string>
|
||||
<string name="title_tg_channel">کانال تلگرام</string>
|
||||
<string name="title_configuration_backup">پشتیبانگیری از پیکربندی</string>
|
||||
<string name="summary_configuration_backup">محل ذخیره سازی: [%s], پس از حذف نصب برنامه یا پاک کردن فضای ذخیره سازی، نسخه پشتیبان پاک می شود</string>
|
||||
<string name="title_configuration_restore">بازیابی پیکربندی</string>
|
||||
<string name="title_configuration_share">اشتراکگذاری پیکربندی</string>
|
||||
<string name="title_pref_promotion">تبلیغات</string>
|
||||
<string name="summary_pref_promotion">تبلیغات، برای جزئیات بیشتر کلیک کنید (کمک مالی کنید تا حذف شود)</string>
|
||||
|
||||
@@ -252,14 +252,14 @@
|
||||
<string name="routing_settings_title">تنظیمات مسیریابی</string>
|
||||
<string name="routing_settings_tips">با کاما (,) از هم جدا شوند، ذخیره کردن فراموش نشود</string>
|
||||
<string name="routing_settings_save">ذخیره</string>
|
||||
<string name="routing_settings_delete">پاک کردن</string>
|
||||
<string name="routing_settings_rule_title">Routing Rule Settings</string>
|
||||
<string name="routing_settings_add_rule">Add rule</string>
|
||||
<string name="routing_settings_import_rulesets">Import ruleset</string>
|
||||
<string name="routing_settings_import_rulesets_tip">Existing rulesets will be deleted, are you sure to continue?</string>
|
||||
<string name="routing_settings_import_rulesets_from_clipboard">Import ruleset from clipboard</string>
|
||||
<string name="routing_settings_export_rulesets_to_clipboard">Export ruleset to clipboard</string>
|
||||
<string name="routing_settings_locked">Locked, keep this rule when import presets</string>
|
||||
<string name="routing_settings_delete">حذف</string>
|
||||
<string name="routing_settings_rule_title">تنظیمات قانون مسیریابی</string>
|
||||
<string name="routing_settings_add_rule">اضافه کردن قانون</string>
|
||||
<string name="routing_settings_import_rulesets">وارد کردن مجموعه قوانین</string>
|
||||
<string name="routing_settings_import_rulesets_tip">مجموعه قوانین موجود حذف خواهند شد، آیا مطمئن هستید که ادامه می دهید؟</string>
|
||||
<string name="routing_settings_import_rulesets_from_clipboard">وارد کردن مجموعه قوانین از کلیپ بورد</string>
|
||||
<string name="routing_settings_export_rulesets_to_clipboard">صادر کردن مجموعه قوانین به کلیپ بورد</string>
|
||||
<string name="routing_settings_locked">قفل است، این قانون را هنگام وارد کردن از پیش تنظیمها حفظ کنید</string>
|
||||
|
||||
<string name="connection_test_pending">اتصال را بررسی کنید</string>
|
||||
<string name="connection_test_testing">در حال آزمایش...</string>
|
||||
@@ -301,4 +301,11 @@
|
||||
<item>Dark</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="preset_rulesets">
|
||||
<item>لیست سفید چین</item>
|
||||
<item>لیست سیاه چین</item>
|
||||
<item>جهانی(Global)</item>
|
||||
<item>ایران</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -306,6 +306,7 @@
|
||||
<item>绕过大陆(Whitelist)</item>
|
||||
<item>黑名单(Blacklist)</item>
|
||||
<item>全局(Global)</item>
|
||||
<item>伊朗(Iran)</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -308,6 +308,7 @@
|
||||
<item>繞過大陸(Whitelist)</item>
|
||||
<item>黑名單(Blacklist)</item>
|
||||
<item>全域(Global)</item>
|
||||
<item>伊朗(Iran)</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -318,6 +318,7 @@
|
||||
<item>China Whitelist</item>
|
||||
<item>China Blacklist</item>
|
||||
<item>Global</item>
|
||||
<item>Iran Whitelist</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
[versions]
|
||||
activityKtx = "1.9.2"
|
||||
activityKtx = "1.9.3"
|
||||
appcompat = "1.7.0"
|
||||
cardview = "1.0.0"
|
||||
constraintlayout = "2.1.4"
|
||||
core = "3.5.3"
|
||||
editorkit = "2.9.0"
|
||||
flexbox = "3.0.0"
|
||||
fragmentKtx = "1.8.3"
|
||||
fragmentKtx = "1.8.4"
|
||||
gson = "2.11.0"
|
||||
junit = "4.13.2"
|
||||
kotlinReflect = "2.0.20"
|
||||
kotlinxCoroutinesCore = "1.9.0"
|
||||
legacySupportV4 = "1.0.0"
|
||||
lifecycleViewmodelKtx = "2.8.5"
|
||||
lifecycleViewmodelKtx = "2.8.6"
|
||||
material = "1.12.0"
|
||||
mmkvStatic = "1.3.9"
|
||||
multidex = "2.0.1"
|
||||
|
||||
Reference in New Issue
Block a user