@@ -54,7 +54,6 @@
|
||||
"users": [
|
||||
{
|
||||
"id": "a3482e88-686a-4a58-8126-99c9df64b7bf",
|
||||
"alterId": 64,
|
||||
"security": "auto",
|
||||
"level": 8
|
||||
}
|
||||
|
||||
@@ -89,7 +89,6 @@ data class V2rayConfig(
|
||||
var users: List<UsersBean>) {
|
||||
|
||||
data class UsersBean(var id: String = "",
|
||||
var alterId: Int? = null,
|
||||
var security: String = DEFAULT_SECURITY,
|
||||
var level: Int = DEFAULT_LEVEL,
|
||||
var encryption: String = "",
|
||||
|
||||
@@ -5,7 +5,7 @@ data class VmessQRCode(var v: String = "",
|
||||
var add: String = "",
|
||||
var port: String = "",
|
||||
var id: String = "",
|
||||
var aid: String = "",
|
||||
var aid: String = "0",
|
||||
var net: String = "",
|
||||
var type: String = "",
|
||||
var host: String = "",
|
||||
|
||||
@@ -40,7 +40,6 @@ import libv2ray.Libv2ray
|
||||
import me.drakeet.support.toast.ToastCompat
|
||||
import rx.Observable
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
import java.net.URL
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener {
|
||||
@@ -109,16 +108,16 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
}
|
||||
|
||||
private fun setupViewModelObserver() {
|
||||
mainViewModel.updateListAction.observe(this, {
|
||||
mainViewModel.updateListAction.observe(this) {
|
||||
val index = it ?: return@observe
|
||||
if (index >= 0) {
|
||||
adapter.notifyItemChanged(index)
|
||||
} else {
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
})
|
||||
mainViewModel.updateTestResultAction.observe(this, { binding.tvTestState.text = it })
|
||||
mainViewModel.isRunning.observe(this, {
|
||||
}
|
||||
mainViewModel.updateTestResultAction.observe(this) { binding.tvTestState.text = it }
|
||||
mainViewModel.isRunning.observe(this) {
|
||||
val isRunning = it ?: return@observe
|
||||
adapter.isRunning = isRunning
|
||||
if (isRunning) {
|
||||
@@ -131,7 +130,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
binding.layoutTest.isFocusable = false
|
||||
}
|
||||
hideCircle()
|
||||
})
|
||||
}
|
||||
mainViewModel.startListenBroadcast()
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
|
||||
if (holder is MainViewHolder) {
|
||||
val guid = mActivity.mainViewModel.serverList.getOrNull(position) ?: return
|
||||
val config = mActivity.mainViewModel.serversCache.getOrElse(guid, { MmkvManager.decodeServerConfig(guid) })?: return
|
||||
val config = mActivity.mainViewModel.serversCache.getOrElse(guid) { MmkvManager.decodeServerConfig(guid) } ?: return
|
||||
val outbound = config.getProxyOutbound()
|
||||
val aff = MmkvManager.decodeServerAffiliationInfo(guid)
|
||||
|
||||
@@ -69,13 +69,17 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
||||
}
|
||||
|
||||
var shareOptions = share_method.asList()
|
||||
if (config.configType == EConfigType.CUSTOM) {
|
||||
holder.itemMainBinding.tvType.text = mActivity.getString(R.string.server_customize_config)
|
||||
shareOptions = shareOptions.takeLast(1)
|
||||
} else if (config.configType == EConfigType.VLESS) {
|
||||
holder.itemMainBinding.tvType.text = config.configType.name
|
||||
} else {
|
||||
holder.itemMainBinding.tvType.text = config.configType.name.lowercase()
|
||||
when (config.configType) {
|
||||
EConfigType.CUSTOM -> {
|
||||
holder.itemMainBinding.tvType.text = mActivity.getString(R.string.server_customize_config)
|
||||
shareOptions = shareOptions.takeLast(1)
|
||||
}
|
||||
EConfigType.VLESS -> {
|
||||
holder.itemMainBinding.tvType.text = config.configType.name
|
||||
}
|
||||
else -> {
|
||||
holder.itemMainBinding.tvType.text = config.configType.name.lowercase()
|
||||
}
|
||||
}
|
||||
holder.itemMainBinding.tvStatistics.text = "${outbound?.getServerAddress()} : ${outbound?.getServerPort()}"
|
||||
|
||||
|
||||
@@ -66,8 +66,8 @@ class PerAppProxyActivity : BaseActivity() {
|
||||
one.isSelected = 0
|
||||
}
|
||||
}
|
||||
val comparator = object : Comparator<AppInfo> {
|
||||
override fun compare(p1: AppInfo, p2: AppInfo): Int = when {
|
||||
val comparator = Comparator<AppInfo> { p1, p2 ->
|
||||
when {
|
||||
p1.isSelected > p2.isSelected -> -1
|
||||
p1.isSelected == p2.isSelected -> 0
|
||||
else -> 1
|
||||
|
||||
@@ -128,7 +128,6 @@ class ServerActivity : BaseActivity() {
|
||||
et_address.text = Utils.getEditable(outbound.getServerAddress().orEmpty())
|
||||
et_port.text = Utils.getEditable(outbound.getServerPort()?.toString() ?: DEFAULT_PORT.toString())
|
||||
et_id.text = Utils.getEditable(outbound.getPassword().orEmpty())
|
||||
et_alterId?.text = Utils.getEditable(outbound.settings?.vnext?.get(0)?.users?.get(0)?.alterId.toString())
|
||||
if (config.configType == EConfigType.SOCKS) {
|
||||
et_security.text = Utils.getEditable(outbound.settings?.servers?.get(0)?.users?.get(0)?.user.orEmpty())
|
||||
} else if (config.configType == EConfigType.VLESS) {
|
||||
@@ -170,7 +169,6 @@ class ServerActivity : BaseActivity() {
|
||||
et_address.text = null
|
||||
et_port.text = Utils.getEditable(DEFAULT_PORT.toString())
|
||||
et_id.text = null
|
||||
et_alterId?.text = Utils.getEditable("0")
|
||||
sp_security?.setSelection(0)
|
||||
sp_network?.setSelection(0)
|
||||
|
||||
@@ -207,13 +205,6 @@ class ServerActivity : BaseActivity() {
|
||||
toast(R.string.server_lab_id)
|
||||
return false
|
||||
}
|
||||
et_alterId?.let {
|
||||
val alterId = Utils.parseInt(et_alterId.text.toString())
|
||||
if (alterId < 0) {
|
||||
toast(R.string.server_lab_alterid)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
config.remarks = et_remarks.text.toString().trim()
|
||||
config.outboundBean?.settings?.vnext?.get(0)?.let { vnext ->
|
||||
@@ -237,13 +228,11 @@ class ServerActivity : BaseActivity() {
|
||||
vnext.port = port
|
||||
vnext.users[0].id = et_id.text.toString().trim()
|
||||
if (config.configType == EConfigType.VMESS) {
|
||||
vnext.users[0].alterId = Utils.parseInt(et_alterId.text.toString())
|
||||
vnext.users[0].security = securitys[sp_security.selectedItemPosition]
|
||||
} else if (config.configType == EConfigType.VLESS) {
|
||||
vnext.users[0].encryption = et_security.text.toString().trim()
|
||||
if (streamSecuritys[sp_stream_security.selectedItemPosition] == XTLS) {
|
||||
// vnext.users[0].flow = if (flows[sp_flow.selectedItemPosition].isBlank()) V2rayConfig.DEFAULT_FLOW
|
||||
// else flows[sp_flow.selectedItemPosition]
|
||||
// vnext.users[0].flow = flows[sp_flow.selectedItemPosition].ifBlank { V2rayConfig.DEFAULT_FLOW }
|
||||
} else {
|
||||
vnext.users[0].flow = ""
|
||||
}
|
||||
@@ -272,7 +261,7 @@ class ServerActivity : BaseActivity() {
|
||||
|
||||
private fun saveStreamSettings(streamSetting: V2rayConfig.OutboundBean.StreamSettingsBean, config: ServerConfig) {
|
||||
val network = if (sp_network != null) networks[sp_network.selectedItemPosition] else DEFAULT_NETWORK
|
||||
val type = if (sp_header_type != null) transportTypes(network)[sp_header_type.selectedItemPosition] else "";
|
||||
val type = if (sp_header_type != null) transportTypes(network)[sp_header_type.selectedItemPosition] else ""
|
||||
val requestHost = if (et_request_host != null) et_request_host.text.toString().trim() else ""
|
||||
val path = if (et_path != null) et_path.text.toString().trim() else ""
|
||||
var sni = streamSetting.populateTransportSettings(
|
||||
|
||||
@@ -17,7 +17,6 @@ import com.v2ray.ang.dto.V2rayConfig.Companion.DEFAULT_SECURITY
|
||||
import com.v2ray.ang.dto.V2rayConfig.Companion.TLS
|
||||
import com.v2ray.ang.util.MmkvManager.KEY_SELECTED_SERVER
|
||||
import java.net.URI
|
||||
import java.net.URLDecoder
|
||||
import java.util.*
|
||||
|
||||
object AngConfigManager {
|
||||
@@ -103,7 +102,6 @@ object AngConfigManager {
|
||||
vnext.port = vmessBean.port
|
||||
vnext.users[0].id = vmessBean.id
|
||||
if (config.configType == EConfigType.VMESS) {
|
||||
vnext.users[0].alterId = vmessBean.alterId
|
||||
vnext.users[0].security = vmessBean.security
|
||||
} else if (config.configType == EConfigType.VLESS) {
|
||||
vnext.users[0].encryption = vmessBean.security
|
||||
@@ -139,7 +137,7 @@ object AngConfigManager {
|
||||
// vmessBean.allowInsecure.toBoolean()
|
||||
// }
|
||||
streamSetting.populateTlsSettings(vmessBean.streamSecurity, false,
|
||||
sni)//if (vmessBean.sni.isNotBlank()) vmessBean.sni else sni)
|
||||
sni)//vmessBean.sni.ifBlank { sni })
|
||||
}
|
||||
}
|
||||
val key = MmkvManager.encodeServerConfig(vmessBean.guid, config)
|
||||
@@ -196,7 +194,6 @@ object AngConfigManager {
|
||||
if (TextUtils.isEmpty(vmessQRCode.add)
|
||||
|| TextUtils.isEmpty(vmessQRCode.port)
|
||||
|| TextUtils.isEmpty(vmessQRCode.id)
|
||||
|| TextUtils.isEmpty(vmessQRCode.aid)
|
||||
|| TextUtils.isEmpty(vmessQRCode.net)
|
||||
) {
|
||||
return R.string.toast_incorrect_protocol
|
||||
@@ -208,7 +205,6 @@ object AngConfigManager {
|
||||
vnext.port = Utils.parseInt(vmessQRCode.port)
|
||||
vnext.users[0].id = vmessQRCode.id
|
||||
vnext.users[0].encryption = DEFAULT_SECURITY
|
||||
vnext.users[0].alterId = Utils.parseInt(vmessQRCode.aid)
|
||||
}
|
||||
val sni = streamSetting.populateTransportSettings(vmessQRCode.net, vmessQRCode.type, vmessQRCode.host,
|
||||
vmessQRCode.path, vmessQRCode.path, vmessQRCode.host, vmessQRCode.path, vmessQRCode.type, vmessQRCode.path)
|
||||
@@ -292,16 +288,14 @@ object AngConfigManager {
|
||||
var sni = ""
|
||||
uri.rawQuery?.let { rawQuery ->
|
||||
val queryParam = rawQuery.split("&")
|
||||
.map { it.split("=").let { (k, v) -> k to URLDecoder.decode(v, "utf-8")!! } }
|
||||
.toMap()
|
||||
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
|
||||
sni = queryParam["sni"] ?: ""
|
||||
}
|
||||
config.outboundBean?.streamSettings?.populateTlsSettings(TLS, allowInsecure, sni)
|
||||
} else if (str.startsWith(EConfigType.VLESS.protocolScheme)) {
|
||||
val uri = URI(str)
|
||||
val queryParam = uri.rawQuery.split("&")
|
||||
.map { it.split("=").let { (k, v) -> k to URLDecoder.decode(v, "utf-8")!! } }
|
||||
.toMap()
|
||||
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
|
||||
config = ServerConfig.create(EConfigType.VLESS)
|
||||
val streamSetting = config.outboundBean?.streamSettings ?: return -1
|
||||
config.remarks = uri.fragment ?: ""
|
||||
@@ -339,14 +333,13 @@ object AngConfigManager {
|
||||
return runCatching {
|
||||
val uri = URI(uriString)
|
||||
check(uri.scheme == "vmess")
|
||||
val (_, protocol, tlsStr, uuid, alterId) =
|
||||
Regex("(tcp|http|ws|kcp|quic|grpc)(\\+tls)?:([0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12})-([0-9]+)")
|
||||
val (_, protocol, tlsStr, uuid) =
|
||||
Regex("(tcp|http|ws|kcp|quic|grpc)(\\+tls)?:([0-9a-z]{8}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{4}-[0-9a-z]{12})")
|
||||
.matchEntire(uri.userInfo)?.groupValues
|
||||
?: error("parse user info fail.")
|
||||
val tls = tlsStr.isNotBlank()
|
||||
val queryParam = uri.rawQuery.split("&")
|
||||
.map { it.split("=").let { (k, v) -> k to URLDecoder.decode(v, "utf-8")!! } }
|
||||
.toMap()
|
||||
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
|
||||
|
||||
val streamSetting = config.outboundBean?.streamSettings ?: return false
|
||||
config.remarks = uri.fragment
|
||||
@@ -355,7 +348,6 @@ object AngConfigManager {
|
||||
vnext.port = uri.port
|
||||
vnext.users[0].id = uuid
|
||||
vnext.users[0].encryption = DEFAULT_SECURITY
|
||||
vnext.users[0].alterId = alterId.toInt()
|
||||
}
|
||||
|
||||
val sni = streamSetting.populateTransportSettings(protocol, queryParam["type"],
|
||||
@@ -392,7 +384,6 @@ object AngConfigManager {
|
||||
vnext.port = Utils.parseInt(arr22[1])
|
||||
vnext.users[0].id = arr21[1]
|
||||
vnext.users[0].encryption = arr21[0]
|
||||
vnext.users[0].alterId = 0
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -413,7 +404,6 @@ object AngConfigManager {
|
||||
vmessQRCode.add = outbound.getServerAddress().orEmpty()
|
||||
vmessQRCode.port = outbound.getServerPort().toString()
|
||||
vmessQRCode.id = outbound.getPassword().orEmpty()
|
||||
vmessQRCode.aid = outbound.settings?.vnext?.get(0)?.users?.get(0)?.alterId.toString()
|
||||
vmessQRCode.net = streamSetting.network
|
||||
vmessQRCode.tls = streamSetting.security
|
||||
vmessQRCode.sni = streamSetting.tlsSettings?.serverName.orEmpty()
|
||||
@@ -455,28 +445,24 @@ object AngConfigManager {
|
||||
}
|
||||
dicQuery["encryption"] = if (outbound.getSecurityEncryption().isNullOrEmpty()) "none"
|
||||
else outbound.getSecurityEncryption().orEmpty()
|
||||
dicQuery["security"] = if (streamSetting.security.isEmpty()) "none"
|
||||
else streamSetting.security
|
||||
dicQuery["security"] = streamSetting.security.ifEmpty { "none" }
|
||||
(streamSetting.tlsSettings?: streamSetting.xtlsSettings)?.let { tlsSetting ->
|
||||
if (!TextUtils.isEmpty(tlsSetting.serverName)) {
|
||||
dicQuery["sni"] = tlsSetting.serverName
|
||||
}
|
||||
}
|
||||
dicQuery["type"] = if (streamSetting.network.isEmpty()) V2rayConfig.DEFAULT_NETWORK
|
||||
else streamSetting.network
|
||||
dicQuery["type"] = streamSetting.network.ifEmpty { V2rayConfig.DEFAULT_NETWORK }
|
||||
|
||||
outbound.getTransportSettingDetails()?.let { transportDetails ->
|
||||
when (streamSetting.network) {
|
||||
"tcp" -> {
|
||||
dicQuery["headerType"] = if (transportDetails[0].isEmpty()) "none"
|
||||
else transportDetails[0]
|
||||
dicQuery["headerType"] = transportDetails[0].ifEmpty { "none" }
|
||||
if (!TextUtils.isEmpty(transportDetails[1])) {
|
||||
dicQuery["host"] = Utils.urlEncode(transportDetails[1])
|
||||
}
|
||||
}
|
||||
"kcp" -> {
|
||||
dicQuery["headerType"] = if (transportDetails[0].isEmpty()) "none"
|
||||
else transportDetails[0]
|
||||
dicQuery["headerType"] = transportDetails[0].ifEmpty { "none" }
|
||||
if (!TextUtils.isEmpty(transportDetails[2])) {
|
||||
dicQuery["seed"] = Utils.urlEncode(transportDetails[2])
|
||||
}
|
||||
@@ -499,8 +485,7 @@ object AngConfigManager {
|
||||
}
|
||||
}
|
||||
"quic" -> {
|
||||
dicQuery["headerType"] = if (transportDetails[0].isEmpty()) "none"
|
||||
else transportDetails[0]
|
||||
dicQuery["headerType"] = transportDetails[0].ifEmpty { "none" }
|
||||
dicQuery["quicSecurity"] = Utils.urlEncode(transportDetails[1])
|
||||
dicQuery["key"] = Utils.urlEncode(transportDetails[2])
|
||||
}
|
||||
|
||||
@@ -42,11 +42,7 @@ object MmkvManager {
|
||||
}
|
||||
|
||||
fun encodeServerConfig(guid: String, config: ServerConfig): String {
|
||||
val key = if (guid.isBlank()) {
|
||||
Utils.getUuid()
|
||||
} else {
|
||||
guid
|
||||
}
|
||||
val key = guid.ifBlank { Utils.getUuid() }
|
||||
serverStorage?.encode(key, Gson().toJson(config))
|
||||
val serverList= decodeServerList()
|
||||
if (!serverList.contains(key)) {
|
||||
|
||||
@@ -62,11 +62,11 @@ object Utils {
|
||||
* parseInt
|
||||
*/
|
||||
fun parseInt(str: String): Int {
|
||||
try {
|
||||
return Integer.parseInt(str)
|
||||
return try {
|
||||
Integer.parseInt(str)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return 0
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,12 +74,12 @@ object Utils {
|
||||
* get text from clipboard
|
||||
*/
|
||||
fun getClipboard(context: Context): String {
|
||||
try {
|
||||
return try {
|
||||
val cmb = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||
return cmb.primaryClip?.getItemAt(0)?.text.toString()
|
||||
cmb.primaryClip?.getItemAt(0)?.text.toString()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return ""
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,11 +126,11 @@ object Utils {
|
||||
* base64 encode
|
||||
*/
|
||||
fun encode(text: String): String {
|
||||
try {
|
||||
return Base64.encodeToString(text.toByteArray(charset("UTF-8")), Base64.NO_WRAP)
|
||||
return try {
|
||||
Base64.encodeToString(text.toByteArray(charset("UTF-8")), Base64.NO_WRAP)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return ""
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,12 +172,12 @@ object Utils {
|
||||
fun createQRCode(text: String, size: Int = 800): Bitmap? {
|
||||
try {
|
||||
val hints = HashMap<EncodeHintType, String>()
|
||||
hints.put(EncodeHintType.CHARACTER_SET, "utf-8")
|
||||
hints[EncodeHintType.CHARACTER_SET] = "utf-8"
|
||||
val bitMatrix = QRCodeWriter().encode(text,
|
||||
BarcodeFormat.QR_CODE, size, size, hints)
|
||||
val pixels = IntArray(size * size)
|
||||
for (y in 0..size - 1) {
|
||||
for (x in 0..size - 1) {
|
||||
for (y in 0 until size) {
|
||||
for (x in 0 until size) {
|
||||
if (bitMatrix.get(x, y)) {
|
||||
pixels[y * size + x] = 0xff000000.toInt()
|
||||
} else {
|
||||
@@ -222,7 +222,7 @@ object Utils {
|
||||
}
|
||||
|
||||
// addr = addr.toLowerCase()
|
||||
var octets = addr.split('.').toTypedArray()
|
||||
val octets = addr.split('.').toTypedArray()
|
||||
if (octets.size == 4) {
|
||||
if(octets[3].indexOf(":") > 0) {
|
||||
addr = addr.substring(0, addr.indexOf(":"))
|
||||
@@ -302,29 +302,29 @@ object Utils {
|
||||
* uuid
|
||||
*/
|
||||
fun getUuid(): String {
|
||||
try {
|
||||
return UUID.randomUUID().toString().replace("-", "")
|
||||
return try {
|
||||
UUID.randomUUID().toString().replace("-", "")
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return ""
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
fun urlDecode(url: String): String {
|
||||
try {
|
||||
return URLDecoder.decode(url, "UTF-8")
|
||||
return try {
|
||||
URLDecoder.decode(url, "UTF-8")
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return url
|
||||
url
|
||||
}
|
||||
}
|
||||
|
||||
fun urlEncode(url: String): String {
|
||||
try {
|
||||
return URLEncoder.encode(url, "UTF-8")
|
||||
return try {
|
||||
URLEncoder.encode(url, "UTF-8")
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
return url
|
||||
url
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,7 +401,7 @@ object Utils {
|
||||
val allText = process.inputStream.bufferedReader().use { it.readText() }
|
||||
if (allText.isNotBlank()) {
|
||||
val tempInfo = allText.substring(allText.indexOf("min/avg/max/mdev") + 19)
|
||||
val temps = tempInfo.split("/".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray()
|
||||
val temps = tempInfo.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
if (temps.count() > 0 && temps[0].length < 10) {
|
||||
return temps[0].toFloat().toInt().toString() + "ms"
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ object V2rayConfigUtil {
|
||||
//val httpPort = Utils.parseInt(settingsStorage?.decodeString(AppConfig.PREF_HTTP_PORT) ?: AppConfig.PORT_HTTP)
|
||||
|
||||
v2rayConfig.inbounds.forEach { curInbound ->
|
||||
if (!(settingsStorage?.decodeBool(AppConfig.PREF_PROXY_SHARING) ?: false)) {
|
||||
if (settingsStorage?.decodeBool(AppConfig.PREF_PROXY_SHARING) != true) {
|
||||
//bind all inbounds to localhost if the user requests
|
||||
curInbound.listen = "127.0.0.1"
|
||||
}
|
||||
@@ -187,7 +187,7 @@ object V2rayConfigUtil {
|
||||
val rulesIP = V2rayConfig.RoutingBean.RulesBean()
|
||||
rulesIP.type = "field"
|
||||
rulesIP.outboundTag = tag
|
||||
rulesIP.ip = ArrayList<String>()
|
||||
rulesIP.ip = ArrayList()
|
||||
rulesIP.ip?.add("geoip:$code")
|
||||
v2rayConfig.routing.rules.add(rulesIP)
|
||||
}
|
||||
@@ -197,7 +197,7 @@ object V2rayConfigUtil {
|
||||
val rulesDomain = V2rayConfig.RoutingBean.RulesBean()
|
||||
rulesDomain.type = "field"
|
||||
rulesDomain.outboundTag = tag
|
||||
rulesDomain.domain = ArrayList<String>()
|
||||
rulesDomain.domain = ArrayList()
|
||||
rulesDomain.domain?.add("geosite:$code")
|
||||
v2rayConfig.routing.rules.add(rulesDomain)
|
||||
}
|
||||
@@ -214,13 +214,13 @@ object V2rayConfigUtil {
|
||||
val rulesDomain = V2rayConfig.RoutingBean.RulesBean()
|
||||
rulesDomain.type = "field"
|
||||
rulesDomain.outboundTag = tag
|
||||
rulesDomain.domain = ArrayList<String>()
|
||||
rulesDomain.domain = ArrayList()
|
||||
|
||||
//IP
|
||||
val rulesIP = V2rayConfig.RoutingBean.RulesBean()
|
||||
rulesIP.type = "field"
|
||||
rulesIP.outboundTag = tag
|
||||
rulesIP.ip = ArrayList<String>()
|
||||
rulesIP.ip = ArrayList()
|
||||
|
||||
userRule.split(",").map { it.trim() }.forEach {
|
||||
if (Utils.isIpAddress(it) || it.startsWith("geoip:")) {
|
||||
@@ -364,7 +364,7 @@ object V2rayConfigUtil {
|
||||
}
|
||||
|
||||
// hardcode googleapi rule to fix play store problems
|
||||
hosts.put("domain:googleapis.cn", "googleapis.com")
|
||||
hosts["domain:googleapis.cn"] = "googleapis.com"
|
||||
|
||||
// DNS dns对象
|
||||
v2rayConfig.dns = V2rayConfig.DnsBean(
|
||||
@@ -393,14 +393,22 @@ object V2rayConfigUtil {
|
||||
if (outbound.streamSettings?.network == DEFAULT_NETWORK
|
||||
&& outbound.streamSettings?.tcpSettings?.header?.type == HTTP) {
|
||||
val path = outbound.streamSettings?.tcpSettings?.header?.request?.path
|
||||
val Host = outbound.streamSettings?.tcpSettings?.header?.request?.headers?.Host
|
||||
val host = outbound.streamSettings?.tcpSettings?.header?.request?.headers?.Host
|
||||
|
||||
val requestString: String by lazy {
|
||||
"""{"version":"1.1","method":"GET","headers":{"User-Agent":["Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36","Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46"],"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}}"""
|
||||
}
|
||||
outbound.streamSettings?.tcpSettings?.header?.request = Gson().fromJson(requestString, V2rayConfig.OutboundBean.StreamSettingsBean.TcpSettingsBean.HeaderBean.RequestBean::class.java)
|
||||
outbound.streamSettings?.tcpSettings?.header?.request?.path = path!!
|
||||
outbound.streamSettings?.tcpSettings?.header?.request?.headers?.Host = Host!!
|
||||
outbound.streamSettings?.tcpSettings?.header?.request = Gson().fromJson(
|
||||
requestString,
|
||||
V2rayConfig.OutboundBean.StreamSettingsBean.TcpSettingsBean.HeaderBean.RequestBean::class.java
|
||||
)
|
||||
outbound.streamSettings?.tcpSettings?.header?.request?.path =
|
||||
if (path.isNullOrEmpty()) {
|
||||
listOf("/")
|
||||
} else {
|
||||
path
|
||||
}
|
||||
outbound.streamSettings?.tcpSettings?.header?.request?.headers?.Host = host!!
|
||||
}
|
||||
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -95,7 +95,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
|
||||
getApplication<AngApplication>().toast(R.string.connection_test_testing)
|
||||
for (guid in serverList) {
|
||||
serversCache.getOrElse(guid, { MmkvManager.decodeServerConfig(guid) })?.getProxyOutbound()?.let { outbound ->
|
||||
serversCache.getOrElse(guid) { MmkvManager.decodeServerConfig(guid) }?.getProxyOutbound()?.let { outbound ->
|
||||
val serverAddress = outbound.getServerAddress()
|
||||
val serverPort = outbound.getServerPort()
|
||||
if (serverAddress != null && serverPort != null) {
|
||||
|
||||
@@ -46,7 +46,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
|
||||
AppConfig.PREF_BYPASS_APPS, -> {
|
||||
settingsStorage?.encode(key, sharedPreferences.getBoolean(key, false))
|
||||
}
|
||||
AppConfig.PREF_SNIFFING_ENABLED, -> {
|
||||
AppConfig.PREF_SNIFFING_ENABLED -> {
|
||||
settingsStorage?.encode(key, sharedPreferences.getBoolean(key, true))
|
||||
}
|
||||
AppConfig.PREF_PER_APP_PROXY_SET -> {
|
||||
|
||||
@@ -98,26 +98,6 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tv_alterId"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/server_lab_alterid" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/et_alterId"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/edit_height"
|
||||
android:inputType="number" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
<string name="server_lab_address">地址(address)</string>
|
||||
<string name="server_lab_port">端口(port)</string>
|
||||
<string name="server_lab_id">用户ID(id)</string>
|
||||
<string name="server_lab_alterid">额外ID(alterId)</string>
|
||||
<string name="server_lab_security">加密方式(security)</string>
|
||||
<string name="server_lab_network">传输协议(network)</string>
|
||||
<string name="server_lab_more_function">功能设置(不清楚则保持默认值)</string>
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
<string name="server_lab_address">位址</string>
|
||||
<string name="server_lab_port">埠</string>
|
||||
<string name="server_lab_id">使用者識別碼</string>
|
||||
<string name="server_lab_alterid">AlterId</string>
|
||||
<string name="server_lab_security">安全性</string>
|
||||
<string name="server_lab_network">網路</string>
|
||||
<string name="server_lab_more_function">更多功能</string>
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
<string name="server_lab_address">address</string>
|
||||
<string name="server_lab_port">port</string>
|
||||
<string name="server_lab_id">id</string>
|
||||
<string name="server_lab_alterid">alterId</string>
|
||||
<string name="server_lab_security">security</string>
|
||||
<string name="server_lab_network">Network</string>
|
||||
<string name="server_lab_more_function">more function</string>
|
||||
|
||||
Reference in New Issue
Block a user