Merge pull request #1555 from yuhan6665/ss-fix
Fix ss2022 import for multi clients format
This commit is contained in:
@@ -6,6 +6,7 @@ import android.widget.Toast
|
|||||||
import com.v2ray.ang.AngApplication
|
import com.v2ray.ang.AngApplication
|
||||||
import me.drakeet.support.toast.ToastCompat
|
import me.drakeet.support.toast.ToastCompat
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
import java.net.URI
|
||||||
import java.net.URLConnection
|
import java.net.URLConnection
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,3 +75,6 @@ private fun Float.toShortString(): String {
|
|||||||
|
|
||||||
val URLConnection.responseLength: Long
|
val URLConnection.responseLength: Long
|
||||||
get() = if (Build.VERSION.SDK_INT >= 24) contentLengthLong else contentLength.toLong()
|
get() = if (Build.VERSION.SDK_INT >= 24) contentLengthLong else contentLength.toLong()
|
||||||
|
|
||||||
|
val URI.idnHost: String
|
||||||
|
get() = (host!!).replace("[", "").replace("]", "")
|
||||||
@@ -18,6 +18,7 @@ import com.v2ray.ang.dto.V2rayConfig.Companion.TLS
|
|||||||
import com.v2ray.ang.util.MmkvManager.KEY_SELECTED_SERVER
|
import com.v2ray.ang.util.MmkvManager.KEY_SELECTED_SERVER
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import com.v2ray.ang.extension.idnHost
|
||||||
|
|
||||||
object AngConfigManager {
|
object AngConfigManager {
|
||||||
private val mainStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_MAIN, MMKV.MULTI_PROCESS_MODE) }
|
private val mainStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_MAIN, MMKV.MULTI_PROCESS_MODE) }
|
||||||
@@ -53,27 +54,31 @@ object AngConfigManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun copyLegacySettings(sharedPreferences: SharedPreferences) {
|
private fun copyLegacySettings(sharedPreferences: SharedPreferences) {
|
||||||
listOf(AppConfig.PREF_MODE,
|
listOf(
|
||||||
AppConfig.PREF_REMOTE_DNS,
|
AppConfig.PREF_MODE,
|
||||||
AppConfig.PREF_DOMESTIC_DNS,
|
AppConfig.PREF_REMOTE_DNS,
|
||||||
// AppConfig.PREF_LOCAL_DNS_PORT,
|
AppConfig.PREF_DOMESTIC_DNS,
|
||||||
// AppConfig.PREF_SOCKS_PORT,
|
AppConfig.PREF_LOCAL_DNS_PORT,
|
||||||
// AppConfig.PREF_HTTP_PORT,
|
// AppConfig.PREF_SOCKS_PORT,
|
||||||
// AppConfig.PREF_LOGLEVEL,
|
// AppConfig.PREF_HTTP_PORT,
|
||||||
AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
|
// AppConfig.PREF_LOGLEVEL,
|
||||||
AppConfig.PREF_ROUTING_MODE,
|
AppConfig.PREF_ROUTING_DOMAIN_STRATEGY,
|
||||||
AppConfig.PREF_V2RAY_ROUTING_AGENT,
|
AppConfig.PREF_ROUTING_MODE,
|
||||||
AppConfig.PREF_V2RAY_ROUTING_BLOCKED,
|
AppConfig.PREF_V2RAY_ROUTING_AGENT,
|
||||||
AppConfig.PREF_V2RAY_ROUTING_DIRECT,).forEach { key ->
|
AppConfig.PREF_V2RAY_ROUTING_BLOCKED,
|
||||||
|
AppConfig.PREF_V2RAY_ROUTING_DIRECT,
|
||||||
|
).forEach { key ->
|
||||||
settingsStorage?.encode(key, sharedPreferences.getString(key, null))
|
settingsStorage?.encode(key, sharedPreferences.getString(key, null))
|
||||||
}
|
}
|
||||||
listOf(AppConfig.PREF_SPEED_ENABLED,
|
listOf(
|
||||||
AppConfig.PREF_PROXY_SHARING,
|
AppConfig.PREF_SPEED_ENABLED,
|
||||||
AppConfig.PREF_LOCAL_DNS_ENABLED,
|
AppConfig.PREF_PROXY_SHARING,
|
||||||
// AppConfig.PREF_ALLOW_INSECURE,
|
AppConfig.PREF_LOCAL_DNS_ENABLED,
|
||||||
// AppConfig.PREF_PREFER_IPV6,
|
// AppConfig.PREF_ALLOW_INSECURE,
|
||||||
AppConfig.PREF_PER_APP_PROXY,
|
// AppConfig.PREF_PREFER_IPV6,
|
||||||
AppConfig.PREF_BYPASS_APPS,).forEach { key ->
|
AppConfig.PREF_PER_APP_PROXY,
|
||||||
|
AppConfig.PREF_BYPASS_APPS,
|
||||||
|
).forEach { key ->
|
||||||
settingsStorage?.encode(key, sharedPreferences.getBoolean(key, false))
|
settingsStorage?.encode(key, sharedPreferences.getBoolean(key, false))
|
||||||
}
|
}
|
||||||
settingsStorage?.encode(AppConfig.PREF_SNIFFING_ENABLED, sharedPreferences.getBoolean(AppConfig.PREF_SNIFFING_ENABLED, true))
|
settingsStorage?.encode(AppConfig.PREF_SNIFFING_ENABLED, sharedPreferences.getBoolean(AppConfig.PREF_SNIFFING_ENABLED, true))
|
||||||
@@ -213,35 +218,37 @@ object AngConfigManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (str.startsWith(EConfigType.SHADOWSOCKS.protocolScheme)) {
|
} else if (str.startsWith(EConfigType.SHADOWSOCKS.protocolScheme)) {
|
||||||
var result = str.replace(EConfigType.SHADOWSOCKS.protocolScheme, "")
|
|
||||||
val indexSplit = result.indexOf("#")
|
|
||||||
config = ServerConfig.create(EConfigType.SHADOWSOCKS)
|
config = ServerConfig.create(EConfigType.SHADOWSOCKS)
|
||||||
if (indexSplit > 0) {
|
if (!tryResolveResolveSip002(str, config)) {
|
||||||
try {
|
var result = str.replace(EConfigType.SHADOWSOCKS.protocolScheme, "")
|
||||||
config.remarks = Utils.urlDecode(result.substring(indexSplit + 1, result.length))
|
val indexSplit = result.indexOf("#")
|
||||||
} catch (e: Exception) {
|
if (indexSplit > 0) {
|
||||||
e.printStackTrace()
|
try {
|
||||||
|
config.remarks = Utils.urlDecode(result.substring(indexSplit + 1, result.length))
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
|
||||||
|
result = result.substring(0, indexSplit)
|
||||||
}
|
}
|
||||||
|
|
||||||
result = result.substring(0, indexSplit)
|
//part decode
|
||||||
}
|
val indexS = result.indexOf("@")
|
||||||
|
result = if (indexS > 0) {
|
||||||
|
Utils.decode(result.substring(0, indexS)) + result.substring(indexS, result.length)
|
||||||
|
} else {
|
||||||
|
Utils.decode(result)
|
||||||
|
}
|
||||||
|
|
||||||
//part decode
|
val legacyPattern = "^(.+?):(.*)@(.+?):(\\d+?)/?$".toRegex()
|
||||||
val indexS = result.indexOf("@")
|
val match = legacyPattern.matchEntire(result) ?: return R.string.toast_incorrect_protocol
|
||||||
result = if (indexS > 0) {
|
|
||||||
Utils.decode(result.substring(0, indexS)) + result.substring(indexS, result.length)
|
|
||||||
} else {
|
|
||||||
Utils.decode(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
val legacyPattern = "^(.+?):(.*)@(.+?):(\\d+?)/?$".toRegex()
|
config.outboundBean?.settings?.servers?.get(0)?.let { server ->
|
||||||
val match = legacyPattern.matchEntire(result) ?: return R.string.toast_incorrect_protocol
|
server.address = match.groupValues[3].removeSurrounding("[", "]")
|
||||||
|
server.port = match.groupValues[4].toInt()
|
||||||
config.outboundBean?.settings?.servers?.get(0)?.let { server ->
|
server.password = match.groupValues[2]
|
||||||
server.address = match.groupValues[3].removeSurrounding("[", "]")
|
server.method = match.groupValues[1].lowercase()
|
||||||
server.port = match.groupValues[4].toInt()
|
}
|
||||||
server.password = match.groupValues[2]
|
|
||||||
server.method = match.groupValues[1].lowercase()
|
|
||||||
}
|
}
|
||||||
} else if (str.startsWith(EConfigType.SOCKS.protocolScheme)) {
|
} else if (str.startsWith(EConfigType.SOCKS.protocolScheme)) {
|
||||||
var result = str.replace(EConfigType.SOCKS.protocolScheme, "")
|
var result = str.replace(EConfigType.SOCKS.protocolScheme, "")
|
||||||
@@ -279,9 +286,9 @@ object AngConfigManager {
|
|||||||
} else if (str.startsWith(EConfigType.TROJAN.protocolScheme)) {
|
} else if (str.startsWith(EConfigType.TROJAN.protocolScheme)) {
|
||||||
val uri = URI(str)
|
val uri = URI(str)
|
||||||
config = ServerConfig.create(EConfigType.TROJAN)
|
config = ServerConfig.create(EConfigType.TROJAN)
|
||||||
config.remarks = uri.fragment ?: ""
|
config.remarks = Utils.urlDecode(uri.fragment ?: "")
|
||||||
config.outboundBean?.settings?.servers?.get(0)?.let { server ->
|
config.outboundBean?.settings?.servers?.get(0)?.let { server ->
|
||||||
server.address = uri.host
|
server.address = uri.idnHost
|
||||||
server.port = uri.port
|
server.port = uri.port
|
||||||
server.password = uri.userInfo
|
server.password = uri.userInfo
|
||||||
}
|
}
|
||||||
@@ -298,9 +305,9 @@ object AngConfigManager {
|
|||||||
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
|
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
|
||||||
config = ServerConfig.create(EConfigType.VLESS)
|
config = ServerConfig.create(EConfigType.VLESS)
|
||||||
val streamSetting = config.outboundBean?.streamSettings ?: return -1
|
val streamSetting = config.outboundBean?.streamSettings ?: return -1
|
||||||
config.remarks = uri.fragment ?: ""
|
config.remarks = Utils.urlDecode(uri.fragment ?: "")
|
||||||
config.outboundBean?.settings?.vnext?.get(0)?.let { vnext ->
|
config.outboundBean?.settings?.vnext?.get(0)?.let { vnext ->
|
||||||
vnext.address = uri.host
|
vnext.address = uri.idnHost
|
||||||
vnext.port = uri.port
|
vnext.port = uri.port
|
||||||
vnext.users[0].id = uri.userInfo
|
vnext.users[0].id = uri.userInfo
|
||||||
vnext.users[0].encryption = queryParam["encryption"] ?: "none"
|
vnext.users[0].encryption = queryParam["encryption"] ?: "none"
|
||||||
@@ -342,9 +349,9 @@ object AngConfigManager {
|
|||||||
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
|
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
|
||||||
|
|
||||||
val streamSetting = config.outboundBean?.streamSettings ?: return false
|
val streamSetting = config.outboundBean?.streamSettings ?: return false
|
||||||
config.remarks = uri.fragment
|
config.remarks = Utils.urlDecode(uri.fragment ?: "")
|
||||||
config.outboundBean.settings?.vnext?.get(0)?.let { vnext ->
|
config.outboundBean.settings?.vnext?.get(0)?.let { vnext ->
|
||||||
vnext.address = uri.host
|
vnext.address = uri.idnHost
|
||||||
vnext.port = uri.port
|
vnext.port = uri.port
|
||||||
vnext.users[0].id = uuid
|
vnext.users[0].id = uuid
|
||||||
vnext.users[0].encryption = DEFAULT_SECURITY
|
vnext.users[0].encryption = DEFAULT_SECURITY
|
||||||
@@ -388,6 +395,38 @@ object AngConfigManager {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun tryResolveResolveSip002(str: String, config: ServerConfig): Boolean {
|
||||||
|
val uri = URI(str.replace(" ", "%20"))
|
||||||
|
config.remarks = Utils.urlDecode(uri.fragment ?: "")
|
||||||
|
|
||||||
|
val method: String
|
||||||
|
val password: String
|
||||||
|
if (uri.userInfo.contains(":")) {
|
||||||
|
val arrUserInfo = uri.userInfo.split(":").map { it.trim() }
|
||||||
|
if (arrUserInfo.count() != 2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
method = arrUserInfo[0]
|
||||||
|
password = Utils.urlDecode(arrUserInfo[1])
|
||||||
|
} else {
|
||||||
|
val base64Decode = Utils.decode(uri.userInfo)
|
||||||
|
val arrUserInfo = base64Decode.split(":").map { it.trim() }
|
||||||
|
if (arrUserInfo.count() != 2 && arrUserInfo.count() != 3) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
method = arrUserInfo[0]
|
||||||
|
password = base64Decode.substringAfter(":")
|
||||||
|
}
|
||||||
|
|
||||||
|
config.outboundBean?.settings?.servers?.get(0)?.let { server ->
|
||||||
|
server.address = uri.idnHost
|
||||||
|
server.port = uri.port
|
||||||
|
server.password = password
|
||||||
|
server.method = method
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* share config
|
* share config
|
||||||
*/
|
*/
|
||||||
@@ -501,7 +540,7 @@ object AngConfigManager {
|
|||||||
|
|
||||||
val url = String.format("%s@%s:%s",
|
val url = String.format("%s@%s:%s",
|
||||||
outbound.getPassword(),
|
outbound.getPassword(),
|
||||||
outbound.getServerAddress(),
|
Utils.getIpv6Address(outbound.getServerAddress()!!),
|
||||||
outbound.getServerPort())
|
outbound.getServerPort())
|
||||||
url + query + remark
|
url + query + remark
|
||||||
}
|
}
|
||||||
@@ -515,7 +554,7 @@ object AngConfigManager {
|
|||||||
}
|
}
|
||||||
val url = String.format("%s@%s:%s",
|
val url = String.format("%s@%s:%s",
|
||||||
outbound.getPassword(),
|
outbound.getPassword(),
|
||||||
outbound.getServerAddress(),
|
Utils.getIpv6Address(outbound.getServerAddress()!!),
|
||||||
outbound.getServerPort())
|
outbound.getServerPort())
|
||||||
url + query + remark
|
url + query + remark
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -477,5 +477,13 @@ object Utils {
|
|||||||
it.bufferedReader().readText()
|
it.bufferedReader().readText()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getIpv6Address(address: String): String {
|
||||||
|
return if (isIpv6Address(address)) {
|
||||||
|
String.format("[%s]", address)
|
||||||
|
} else {
|
||||||
|
address
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,14 +8,15 @@
|
|||||||
<item>zero</item>
|
<item>zero</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="ss_securitys" translatable="false">
|
<string-array name="ss_securitys" translatable="false">
|
||||||
<item>aes-256-cfb</item>
|
|
||||||
<item>aes-128-cfb</item>
|
|
||||||
<item>chacha20</item>
|
|
||||||
<item>chacha20-ietf</item>
|
|
||||||
<item>aes-256-gcm</item>
|
<item>aes-256-gcm</item>
|
||||||
<item>aes-128-gcm</item>
|
<item>aes-128-gcm</item>
|
||||||
<item>chacha20-poly1305</item>
|
<item>chacha20-poly1305</item>
|
||||||
<item>chacha20-ietf-poly1305</item>
|
<item>chacha20-ietf-poly1305</item>
|
||||||
|
<item>none</item>
|
||||||
|
<item>plain</item>
|
||||||
|
<item>2022-blake3-aes-128-gcm</item>
|
||||||
|
<item>2022-blake3-aes-256-gcm</item>
|
||||||
|
<item>2022-blake3-chacha20-poly1305</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
<string-array name="networks" translatable="false">
|
<string-array name="networks" translatable="false">
|
||||||
|
|||||||
Reference in New Issue
Block a user