mirror of
https://github.com/MatsuriDayo/NekoBoxForAndroid.git
synced 2025-12-19 14:40:06 +08:00
update
This commit is contained in:
parent
3270d7e282
commit
dfb81814d1
@ -255,7 +255,7 @@ data class ProxyEntity(
|
|||||||
|
|
||||||
return with(requireBean()) {
|
return with(requireBean()) {
|
||||||
StringBuilder().apply {
|
StringBuilder().apply {
|
||||||
val config = buildConfig(this@ProxyEntity)
|
val config = buildConfig(this@ProxyEntity, forExport = true)
|
||||||
append(config.config)
|
append(config.config)
|
||||||
|
|
||||||
if (!config.externalIndex.all { it.chain.isEmpty() }) {
|
if (!config.externalIndex.all { it.chain.isEmpty() }) {
|
||||||
|
|||||||
@ -26,9 +26,10 @@ import io.nekohasekai.sagernet.fmt.wireguard.buildSingBoxOutboundWireguardBean
|
|||||||
import io.nekohasekai.sagernet.ktx.isIpAddress
|
import io.nekohasekai.sagernet.ktx.isIpAddress
|
||||||
import io.nekohasekai.sagernet.ktx.mkPort
|
import io.nekohasekai.sagernet.ktx.mkPort
|
||||||
import io.nekohasekai.sagernet.utils.PackageCache
|
import io.nekohasekai.sagernet.utils.PackageCache
|
||||||
import moe.matsuri.nb4a.DNS.applyDNSNetworkSettings
|
|
||||||
import moe.matsuri.nb4a.DNS.makeSingBoxRule
|
|
||||||
import moe.matsuri.nb4a.SingBoxOptions.*
|
import moe.matsuri.nb4a.SingBoxOptions.*
|
||||||
|
import moe.matsuri.nb4a.applyDNSNetworkSettings
|
||||||
|
import moe.matsuri.nb4a.checkEmpty
|
||||||
|
import moe.matsuri.nb4a.makeSingBoxRule
|
||||||
import moe.matsuri.nb4a.plugin.Plugins
|
import moe.matsuri.nb4a.plugin.Plugins
|
||||||
import moe.matsuri.nb4a.proxy.config.ConfigBean
|
import moe.matsuri.nb4a.proxy.config.ConfigBean
|
||||||
import moe.matsuri.nb4a.proxy.shadowtls.ShadowTLSBean
|
import moe.matsuri.nb4a.proxy.shadowtls.ShadowTLSBean
|
||||||
@ -77,7 +78,7 @@ fun mergeJSON(j: String, to: MutableMap<String, Any>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun buildConfig(
|
fun buildConfig(
|
||||||
proxy: ProxyEntity, forTest: Boolean = false
|
proxy: ProxyEntity, forTest: Boolean = false, forExport: Boolean = false
|
||||||
): ConfigBuildResult {
|
): ConfigBuildResult {
|
||||||
|
|
||||||
if (proxy.type == TYPE_CONFIG) {
|
if (proxy.type == TYPE_CONFIG) {
|
||||||
@ -98,6 +99,7 @@ fun buildConfig(
|
|||||||
val trafficMap = HashMap<String, List<ProxyEntity>>()
|
val trafficMap = HashMap<String, List<ProxyEntity>>()
|
||||||
val tagMap = HashMap<Long, String>()
|
val tagMap = HashMap<Long, String>()
|
||||||
val globalOutbounds = ArrayList<Long>()
|
val globalOutbounds = ArrayList<Long>()
|
||||||
|
val selectorNames = ArrayList<String>()
|
||||||
val group = SagerDatabase.groupDao.getById(proxy.groupId)
|
val group = SagerDatabase.groupDao.getById(proxy.groupId)
|
||||||
var optionsToMerge = ""
|
var optionsToMerge = ""
|
||||||
|
|
||||||
@ -116,6 +118,17 @@ fun buildConfig(
|
|||||||
return mutableListOf(this)
|
return mutableListOf(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun selectorName(name_: String): String {
|
||||||
|
var name = name_
|
||||||
|
var count = 0
|
||||||
|
while (selectorNames.contains(name)) {
|
||||||
|
count++
|
||||||
|
name = "$name_-$count"
|
||||||
|
}
|
||||||
|
selectorNames.add(name)
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
fun ProxyEntity.resolveChain(): MutableList<ProxyEntity> {
|
fun ProxyEntity.resolveChain(): MutableList<ProxyEntity> {
|
||||||
val frontProxy = group?.frontProxy?.let { SagerDatabase.proxyDao.getById(it) }
|
val frontProxy = group?.frontProxy?.let { SagerDatabase.proxyDao.getById(it) }
|
||||||
val landingProxy = group?.landingProxy?.let { SagerDatabase.proxyDao.getById(it) }
|
val landingProxy = group?.landingProxy?.let { SagerDatabase.proxyDao.getById(it) }
|
||||||
@ -133,8 +146,8 @@ fun buildConfig(
|
|||||||
val extraProxies =
|
val extraProxies =
|
||||||
if (forTest) mapOf() else SagerDatabase.proxyDao.getEntities(extraRules.mapNotNull { rule ->
|
if (forTest) mapOf() else SagerDatabase.proxyDao.getEntities(extraRules.mapNotNull { rule ->
|
||||||
rule.outbound.takeIf { it > 0 && it != proxy.id }
|
rule.outbound.takeIf { it > 0 && it != proxy.id }
|
||||||
}.toHashSet().toList()).associate { it.id to it }
|
}.toHashSet().toList()).associateBy { it.id }
|
||||||
val buildSelector = !forTest && group?.isSelector == true
|
val buildSelector = !forTest && group?.isSelector == true && !forExport
|
||||||
val uidListDNSRemote = mutableListOf<Int>()
|
val uidListDNSRemote = mutableListOf<Int>()
|
||||||
val uidListDNSDirect = mutableListOf<Int>()
|
val uidListDNSDirect = mutableListOf<Int>()
|
||||||
val domainListDNSRemote = mutableListOf<String>()
|
val domainListDNSRemote = mutableListOf<String>()
|
||||||
@ -328,6 +341,11 @@ fun buildConfig(
|
|||||||
tagOut = TAG_PROXY
|
tagOut = TAG_PROXY
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// selector human readable name
|
||||||
|
if (buildSelector && index == 0) {
|
||||||
|
tagOut = selectorName(bean.displayName())
|
||||||
|
}
|
||||||
|
|
||||||
// chain rules
|
// chain rules
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
// chain route/proxy rules
|
// chain route/proxy rules
|
||||||
@ -495,26 +513,25 @@ fun buildConfig(
|
|||||||
|
|
||||||
// apply user rules
|
// apply user rules
|
||||||
for (rule in extraRules) {
|
for (rule in extraRules) {
|
||||||
val _uidList = rule.packages.map {
|
if (rule.packages.isNotEmpty()) {
|
||||||
|
PackageCache.awaitLoadSync()
|
||||||
|
}
|
||||||
|
val uidList2 = rule.packages.map {
|
||||||
|
if (!isVPN) {
|
||||||
|
alerts.add(0 to rule.displayName())
|
||||||
|
}
|
||||||
PackageCache[it]?.takeIf { uid -> uid >= 1000 }
|
PackageCache[it]?.takeIf { uid -> uid >= 1000 }
|
||||||
}.toHashSet().filterNotNull()
|
}.toHashSet().filterNotNull()
|
||||||
|
|
||||||
if (rule.packages.isNotEmpty()) {
|
val ruleObj = Rule_DefaultOptions().apply {
|
||||||
if (!isVPN) {
|
if (uidList2.isNotEmpty()) {
|
||||||
alerts.add(0 to rule.displayName())
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
route.rules.add(Rule_DefaultOptions().apply {
|
|
||||||
if (rule.packages.isNotEmpty()) {
|
|
||||||
PackageCache.awaitLoadSync()
|
PackageCache.awaitLoadSync()
|
||||||
user_id = _uidList
|
user_id = uidList2
|
||||||
}
|
}
|
||||||
|
var domainList2: List<String>? = null
|
||||||
var _domainList: List<String>? = null
|
|
||||||
if (rule.domains.isNotBlank()) {
|
if (rule.domains.isNotBlank()) {
|
||||||
_domainList = rule.domains.split("\n")
|
domainList2 = rule.domains.split("\n")
|
||||||
makeSingBoxRule(_domainList, false)
|
makeSingBoxRule(domainList2, false)
|
||||||
}
|
}
|
||||||
if (rule.ip.isNotBlank()) {
|
if (rule.ip.isNotBlank()) {
|
||||||
makeSingBoxRule(rule.ip.split("\n"), true)
|
makeSingBoxRule(rule.ip.split("\n"), true)
|
||||||
@ -554,13 +571,13 @@ fun buildConfig(
|
|||||||
// also bypass lookup
|
// also bypass lookup
|
||||||
// cannot use other outbound profile to lookup...
|
// cannot use other outbound profile to lookup...
|
||||||
if (rule.outbound == -1L) {
|
if (rule.outbound == -1L) {
|
||||||
uidListDNSDirect += _uidList
|
uidListDNSDirect += uidList2
|
||||||
if (_domainList != null) domainListDNSDirect += _domainList
|
if (domainList2 != null) domainListDNSDirect += domainList2
|
||||||
} else if (rule.outbound == 0L) {
|
} else if (rule.outbound == 0L) {
|
||||||
uidListDNSRemote += _uidList
|
uidListDNSRemote += uidList2
|
||||||
if (_domainList != null) domainListDNSRemote += _domainList
|
if (domainList2 != null) domainListDNSRemote += domainList2
|
||||||
} else if (rule.outbound == -2L) {
|
} else if (rule.outbound == -2L) {
|
||||||
if (_domainList != null) domainListDNSBlock += _domainList
|
if (domainList2 != null) domainListDNSBlock += domainList2
|
||||||
}
|
}
|
||||||
|
|
||||||
outbound = when (val outId = rule.outbound) {
|
outbound = when (val outId = rule.outbound) {
|
||||||
@ -570,7 +587,11 @@ fun buildConfig(
|
|||||||
else -> if (outId == proxy.id) TAG_PROXY else tagMap[outId]
|
else -> if (outId == proxy.id) TAG_PROXY else tagMap[outId]
|
||||||
?: throw Exception("invalid rule")
|
?: throw Exception("invalid rule")
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
|
||||||
|
if (!ruleObj.checkEmpty()) {
|
||||||
|
route.rules.add(ruleObj)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (freedom in arrayOf(TAG_DIRECT, TAG_BYPASS)) outbounds.add(Outbound().apply {
|
for (freedom in arrayOf(TAG_DIRECT, TAG_BYPASS)) outbounds.add(Outbound().apply {
|
||||||
@ -683,8 +704,9 @@ fun buildConfig(
|
|||||||
|
|
||||||
// dns object user rules
|
// dns object user rules
|
||||||
if (enableDnsRouting) {
|
if (enableDnsRouting) {
|
||||||
|
val dnsRuleObj = mutableListOf<DNSRule_DefaultOptions>()
|
||||||
if (uidListDNSRemote.isNotEmpty()) {
|
if (uidListDNSRemote.isNotEmpty()) {
|
||||||
dns.rules.add(
|
dnsRuleObj.add(
|
||||||
DNSRule_DefaultOptions().apply {
|
DNSRule_DefaultOptions().apply {
|
||||||
user_id = uidListDNSRemote.toHashSet().toList()
|
user_id = uidListDNSRemote.toHashSet().toList()
|
||||||
server = if (useFakeDns) "dns-fake" else "dns-remote"
|
server = if (useFakeDns) "dns-fake" else "dns-remote"
|
||||||
@ -692,7 +714,7 @@ fun buildConfig(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (domainListDNSRemote.isNotEmpty()) {
|
if (domainListDNSRemote.isNotEmpty()) {
|
||||||
dns.rules.add(
|
dnsRuleObj.add(
|
||||||
DNSRule_DefaultOptions().apply {
|
DNSRule_DefaultOptions().apply {
|
||||||
makeSingBoxRule(domainListDNSRemote.toHashSet().toList())
|
makeSingBoxRule(domainListDNSRemote.toHashSet().toList())
|
||||||
server = if (useFakeDns) "dns-fake" else "dns-remote"
|
server = if (useFakeDns) "dns-fake" else "dns-remote"
|
||||||
@ -700,7 +722,7 @@ fun buildConfig(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (uidListDNSDirect.isNotEmpty()) {
|
if (uidListDNSDirect.isNotEmpty()) {
|
||||||
dns.rules.add(
|
dnsRuleObj.add(
|
||||||
DNSRule_DefaultOptions().apply {
|
DNSRule_DefaultOptions().apply {
|
||||||
user_id = uidListDNSDirect.toHashSet().toList()
|
user_id = uidListDNSDirect.toHashSet().toList()
|
||||||
server = "dns-direct"
|
server = "dns-direct"
|
||||||
@ -708,7 +730,7 @@ fun buildConfig(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (domainListDNSDirect.isNotEmpty()) {
|
if (domainListDNSDirect.isNotEmpty()) {
|
||||||
dns.rules.add(
|
dnsRuleObj.add(
|
||||||
DNSRule_DefaultOptions().apply {
|
DNSRule_DefaultOptions().apply {
|
||||||
makeSingBoxRule(domainListDNSDirect.toHashSet().toList())
|
makeSingBoxRule(domainListDNSDirect.toHashSet().toList())
|
||||||
server = "dns-direct"
|
server = "dns-direct"
|
||||||
@ -716,7 +738,7 @@ fun buildConfig(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (domainListDNSBlock.isNotEmpty()) {
|
if (domainListDNSBlock.isNotEmpty()) {
|
||||||
dns.rules.add(
|
dnsRuleObj.add(
|
||||||
DNSRule_DefaultOptions().apply {
|
DNSRule_DefaultOptions().apply {
|
||||||
makeSingBoxRule(domainListDNSBlock.toHashSet().toList())
|
makeSingBoxRule(domainListDNSBlock.toHashSet().toList())
|
||||||
server = "dns-block"
|
server = "dns-block"
|
||||||
@ -724,6 +746,9 @@ fun buildConfig(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
dnsRuleObj.forEach {
|
||||||
|
if (!it.checkEmpty()) dns.rules.add(it)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable DNS for test
|
// Disable DNS for test
|
||||||
@ -774,6 +799,7 @@ fun buildConfig(
|
|||||||
dns.rules.add(DNSRule_DefaultOptions().apply {
|
dns.rules.add(DNSRule_DefaultOptions().apply {
|
||||||
inbound = listOf("tun-in")
|
inbound = listOf("tun-in")
|
||||||
server = "dns-fake"
|
server = "dns-fake"
|
||||||
|
disable_cache = true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -199,7 +199,7 @@ object RawUpdater : GroupUpdater() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
suspend fun parseRaw(text: String): List<AbstractBean>? {
|
suspend fun parseRaw(text: String, fileName: String = ""): List<AbstractBean>? {
|
||||||
|
|
||||||
val proxies = mutableListOf<AbstractBean>()
|
val proxies = mutableListOf<AbstractBean>()
|
||||||
|
|
||||||
@ -399,7 +399,10 @@ object RawUpdater : GroupUpdater() {
|
|||||||
} else if (text.contains("[Interface]")) {
|
} else if (text.contains("[Interface]")) {
|
||||||
// wireguard
|
// wireguard
|
||||||
try {
|
try {
|
||||||
proxies.addAll(parseWireGuard(text))
|
proxies.addAll(parseWireGuard(text).map {
|
||||||
|
if (fileName.isNotBlank()) it.name = fileName
|
||||||
|
it
|
||||||
|
})
|
||||||
return proxies
|
return proxies
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Logs.w(e)
|
Logs.w(e)
|
||||||
@ -442,9 +445,7 @@ object RawUpdater : GroupUpdater() {
|
|||||||
val bean = WireGuardBean().applyDefaultValues()
|
val bean = WireGuardBean().applyDefaultValues()
|
||||||
val localAddresses = iface.getAll("Address")
|
val localAddresses = iface.getAll("Address")
|
||||||
if (localAddresses.isNullOrEmpty()) error("Empty address in 'Interface' selection")
|
if (localAddresses.isNullOrEmpty()) error("Empty address in 'Interface' selection")
|
||||||
bean.localAddress = localAddresses.flatMap { it.split(",") }.let { address ->
|
bean.localAddress = localAddresses.flatMap { it.split(",") }.joinToString("\n")
|
||||||
address.joinToString("\n") { it.substringBefore("/") }
|
|
||||||
}
|
|
||||||
bean.privateKey = iface["PrivateKey"]
|
bean.privateKey = iface["PrivateKey"]
|
||||||
val peers = ini.getAll("Peer")
|
val peers = ini.getAll("Peer")
|
||||||
if (peers.isNullOrEmpty()) error("Missing 'Peer' selections")
|
if (peers.isNullOrEmpty()) error("Missing 'Peer' selections")
|
||||||
|
|||||||
@ -225,51 +225,52 @@ class ConfigurationFragment @JvmOverloads constructor(
|
|||||||
return super.onKeyDown(ketCode, event)
|
return super.onKeyDown(ketCode, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
val importFile = registerForActivityResult(ActivityResultContracts.GetContent()) { file ->
|
private val importFile =
|
||||||
if (file != null) runOnDefaultDispatcher {
|
registerForActivityResult(ActivityResultContracts.GetContent()) { file ->
|
||||||
try {
|
if (file != null) runOnDefaultDispatcher {
|
||||||
val fileName = requireContext().contentResolver.query(file, null, null, null, null)
|
try {
|
||||||
?.use { cursor ->
|
val fileName =
|
||||||
cursor.moveToFirst()
|
requireContext().contentResolver.query(file, null, null, null, null)
|
||||||
cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)
|
?.use { cursor ->
|
||||||
.let(cursor::getString)
|
cursor.moveToFirst()
|
||||||
|
cursor.getColumnIndexOrThrow(OpenableColumns.DISPLAY_NAME)
|
||||||
|
.let(cursor::getString)
|
||||||
|
}
|
||||||
|
val proxies = mutableListOf<AbstractBean>()
|
||||||
|
if (fileName != null && fileName.endsWith(".zip")) {
|
||||||
|
// try parse wireguard zip
|
||||||
|
val zip =
|
||||||
|
ZipInputStream(requireContext().contentResolver.openInputStream(file)!!)
|
||||||
|
while (true) {
|
||||||
|
val entry = zip.nextEntry ?: break
|
||||||
|
if (entry.isDirectory) continue
|
||||||
|
val fileText = zip.bufferedReader().readText()
|
||||||
|
RawUpdater.parseRaw(fileText, entry.name)
|
||||||
|
?.let { pl -> proxies.addAll(pl) }
|
||||||
|
zip.closeEntry()
|
||||||
|
}
|
||||||
|
zip.closeQuietly()
|
||||||
|
} else {
|
||||||
|
val fileText =
|
||||||
|
requireContext().contentResolver.openInputStream(file)!!.use {
|
||||||
|
it.bufferedReader().readText()
|
||||||
|
}
|
||||||
|
RawUpdater.parseRaw(fileText, fileName ?: "")
|
||||||
|
?.let { pl -> proxies.addAll(pl) }
|
||||||
}
|
}
|
||||||
|
if (proxies.isEmpty()) onMainDispatcher {
|
||||||
val proxies = mutableListOf<AbstractBean>()
|
snackbar(getString(R.string.no_proxies_found_in_file)).show()
|
||||||
if (fileName != null && fileName.endsWith(".zip")) {
|
} else import(proxies)
|
||||||
// try parse wireguard zip
|
} catch (e: SubscriptionFoundException) {
|
||||||
|
(requireActivity() as MainActivity).importSubscription(Uri.parse(e.link))
|
||||||
val zip =
|
} catch (e: Exception) {
|
||||||
ZipInputStream(requireContext().contentResolver.openInputStream(file)!!)
|
Logs.w(e)
|
||||||
while (true) {
|
onMainDispatcher {
|
||||||
val entry = zip.nextEntry ?: break
|
snackbar(e.readableMessage).show()
|
||||||
if (entry.isDirectory) continue
|
|
||||||
val fileText = zip.bufferedReader().readText()
|
|
||||||
RawUpdater.parseRaw(fileText)?.let { pl -> proxies.addAll(pl) }
|
|
||||||
zip.closeEntry()
|
|
||||||
}
|
}
|
||||||
zip.closeQuietly()
|
|
||||||
} else {
|
|
||||||
val fileText = requireContext().contentResolver.openInputStream(file)!!.use {
|
|
||||||
it.bufferedReader().readText()
|
|
||||||
}
|
|
||||||
RawUpdater.parseRaw(fileText)?.let { pl -> proxies.addAll(pl) }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proxies.isEmpty()) onMainDispatcher {
|
|
||||||
snackbar(getString(R.string.no_proxies_found_in_file)).show()
|
|
||||||
} else import(proxies)
|
|
||||||
} catch (e: SubscriptionFoundException) {
|
|
||||||
(requireActivity() as MainActivity).importSubscription(Uri.parse(e.link))
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Logs.w(e)
|
|
||||||
|
|
||||||
onMainDispatcher {
|
|
||||||
snackbar(e.readableMessage).show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun import(proxies: List<AbstractBean>) {
|
suspend fun import(proxies: List<AbstractBean>) {
|
||||||
val targetId = DataStore.selectedGroupForImport()
|
val targetId = DataStore.selectedGroupForImport()
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import android.webkit.*
|
|||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.afollestad.materialdialogs.input.input
|
import com.afollestad.materialdialogs.input.input
|
||||||
|
import io.nekohasekai.sagernet.BuildConfig
|
||||||
import io.nekohasekai.sagernet.R
|
import io.nekohasekai.sagernet.R
|
||||||
import io.nekohasekai.sagernet.database.DataStore
|
import io.nekohasekai.sagernet.database.DataStore
|
||||||
import io.nekohasekai.sagernet.databinding.LayoutWebviewBinding
|
import io.nekohasekai.sagernet.databinding.LayoutWebviewBinding
|
||||||
@ -32,6 +33,7 @@ class WebviewFragment : ToolbarFragment(R.layout.layout_webview), Toolbar.OnMenu
|
|||||||
val binding = LayoutWebviewBinding.bind(view)
|
val binding = LayoutWebviewBinding.bind(view)
|
||||||
|
|
||||||
// webview
|
// webview
|
||||||
|
WebView.setWebContentsDebuggingEnabled(BuildConfig.DEBUG)
|
||||||
mWebView = binding.webview
|
mWebView = binding.webview
|
||||||
mWebView.settings.domStorageEnabled = true
|
mWebView.settings.domStorageEnabled = true
|
||||||
mWebView.settings.javaScriptEnabled = true
|
mWebView.settings.javaScriptEnabled = true
|
||||||
|
|||||||
@ -1,86 +0,0 @@
|
|||||||
package moe.matsuri.nb4a
|
|
||||||
|
|
||||||
import io.nekohasekai.sagernet.database.DataStore
|
|
||||||
|
|
||||||
object DNS {
|
|
||||||
fun SingBoxOptions.DNSServerOptions.applyDNSNetworkSettings(isDirect: Boolean) {
|
|
||||||
if (isDirect) {
|
|
||||||
if (DataStore.dnsNetwork.contains("NoDirectIPv4")) this.strategy = "ipv6_only"
|
|
||||||
if (DataStore.dnsNetwork.contains("NoDirectIPv6")) this.strategy = "ipv4_only"
|
|
||||||
} else {
|
|
||||||
if (DataStore.dnsNetwork.contains("NoRemoteIPv4")) this.strategy = "ipv6_only"
|
|
||||||
if (DataStore.dnsNetwork.contains("NoRemoteIPv6")) this.strategy = "ipv4_only"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun SingBoxOptions.DNSRule_DefaultOptions.makeSingBoxRule(list: List<String>) {
|
|
||||||
geosite = mutableListOf<String>()
|
|
||||||
domain = mutableListOf<String>()
|
|
||||||
domain_suffix = mutableListOf<String>()
|
|
||||||
domain_regex = mutableListOf<String>()
|
|
||||||
domain_keyword = mutableListOf<String>()
|
|
||||||
list.forEach {
|
|
||||||
if (it.startsWith("geosite:")) {
|
|
||||||
geosite.plusAssign(it.removePrefix("geosite:"))
|
|
||||||
} else if (it.startsWith("full:")) {
|
|
||||||
domain.plusAssign(it.removePrefix("full:"))
|
|
||||||
} else if (it.startsWith("domain:")) {
|
|
||||||
domain_suffix.plusAssign(it.removePrefix("domain:"))
|
|
||||||
} else if (it.startsWith("regexp:")) {
|
|
||||||
domain_regex.plusAssign(it.removePrefix("regexp:"))
|
|
||||||
} else if (it.startsWith("keyword:")) {
|
|
||||||
domain_keyword.plusAssign(it.removePrefix("keyword:"))
|
|
||||||
} else {
|
|
||||||
domain.plusAssign(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (geosite?.isEmpty() == true) geosite = null
|
|
||||||
if (domain?.isEmpty() == true) domain = null
|
|
||||||
if (domain_suffix?.isEmpty() == true) domain_suffix = null
|
|
||||||
if (domain_regex?.isEmpty() == true) domain_regex = null
|
|
||||||
if (domain_keyword?.isEmpty() == true) domain_keyword = null
|
|
||||||
}
|
|
||||||
|
|
||||||
fun SingBoxOptions.Rule_DefaultOptions.makeSingBoxRule(list: List<String>, isIP: Boolean) {
|
|
||||||
if (isIP) {
|
|
||||||
ip_cidr = mutableListOf<String>()
|
|
||||||
geoip = mutableListOf<String>()
|
|
||||||
} else {
|
|
||||||
geosite = mutableListOf<String>()
|
|
||||||
domain = mutableListOf<String>()
|
|
||||||
domain_suffix = mutableListOf<String>()
|
|
||||||
domain_regex = mutableListOf<String>()
|
|
||||||
domain_keyword = mutableListOf<String>()
|
|
||||||
}
|
|
||||||
list.forEach {
|
|
||||||
if (isIP) {
|
|
||||||
if (it.startsWith("geoip:")) {
|
|
||||||
geoip.plusAssign(it.removePrefix("geoip:"))
|
|
||||||
} else {
|
|
||||||
ip_cidr.plusAssign(it)
|
|
||||||
}
|
|
||||||
return@forEach
|
|
||||||
}
|
|
||||||
if (it.startsWith("geosite:")) {
|
|
||||||
geosite.plusAssign(it.removePrefix("geosite:"))
|
|
||||||
} else if (it.startsWith("full:")) {
|
|
||||||
domain.plusAssign(it.removePrefix("full:"))
|
|
||||||
} else if (it.startsWith("domain:")) {
|
|
||||||
domain_suffix.plusAssign(it.removePrefix("domain:"))
|
|
||||||
} else if (it.startsWith("regexp:")) {
|
|
||||||
domain_regex.plusAssign(it.removePrefix("regexp:"))
|
|
||||||
} else if (it.startsWith("keyword:")) {
|
|
||||||
domain_keyword.plusAssign(it.removePrefix("keyword:"))
|
|
||||||
} else {
|
|
||||||
domain.plusAssign(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ip_cidr?.isEmpty() == true) ip_cidr = null
|
|
||||||
if (geoip?.isEmpty() == true) geoip = null
|
|
||||||
if (geosite?.isEmpty() == true) geosite = null
|
|
||||||
if (domain?.isEmpty() == true) domain = null
|
|
||||||
if (domain_suffix?.isEmpty() == true) domain_suffix = null
|
|
||||||
if (domain_regex?.isEmpty() == true) domain_regex = null
|
|
||||||
if (domain_keyword?.isEmpty() == true) domain_keyword = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
106
app/src/main/java/moe/matsuri/nb4a/SingBoxOptionsUtil.kt
Normal file
106
app/src/main/java/moe/matsuri/nb4a/SingBoxOptionsUtil.kt
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
package moe.matsuri.nb4a
|
||||||
|
|
||||||
|
import io.nekohasekai.sagernet.database.DataStore
|
||||||
|
|
||||||
|
fun SingBoxOptions.DNSServerOptions.applyDNSNetworkSettings(isDirect: Boolean) {
|
||||||
|
if (isDirect) {
|
||||||
|
if (DataStore.dnsNetwork.contains("NoDirectIPv4")) this.strategy = "ipv6_only"
|
||||||
|
if (DataStore.dnsNetwork.contains("NoDirectIPv6")) this.strategy = "ipv4_only"
|
||||||
|
} else {
|
||||||
|
if (DataStore.dnsNetwork.contains("NoRemoteIPv4")) this.strategy = "ipv6_only"
|
||||||
|
if (DataStore.dnsNetwork.contains("NoRemoteIPv6")) this.strategy = "ipv4_only"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun SingBoxOptions.DNSRule_DefaultOptions.makeSingBoxRule(list: List<String>) {
|
||||||
|
geosite = mutableListOf<String>()
|
||||||
|
domain = mutableListOf<String>()
|
||||||
|
domain_suffix = mutableListOf<String>()
|
||||||
|
domain_regex = mutableListOf<String>()
|
||||||
|
domain_keyword = mutableListOf<String>()
|
||||||
|
list.forEach {
|
||||||
|
if (it.startsWith("geosite:")) {
|
||||||
|
geosite.plusAssign(it.removePrefix("geosite:"))
|
||||||
|
} else if (it.startsWith("full:")) {
|
||||||
|
domain.plusAssign(it.removePrefix("full:"))
|
||||||
|
} else if (it.startsWith("domain:")) {
|
||||||
|
domain_suffix.plusAssign(it.removePrefix("domain:"))
|
||||||
|
} else if (it.startsWith("regexp:")) {
|
||||||
|
domain_regex.plusAssign(it.removePrefix("regexp:"))
|
||||||
|
} else if (it.startsWith("keyword:")) {
|
||||||
|
domain_keyword.plusAssign(it.removePrefix("keyword:"))
|
||||||
|
} else {
|
||||||
|
domain.plusAssign(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (geosite?.isEmpty() == true) geosite = null
|
||||||
|
if (domain?.isEmpty() == true) domain = null
|
||||||
|
if (domain_suffix?.isEmpty() == true) domain_suffix = null
|
||||||
|
if (domain_regex?.isEmpty() == true) domain_regex = null
|
||||||
|
if (domain_keyword?.isEmpty() == true) domain_keyword = null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun SingBoxOptions.DNSRule_DefaultOptions.checkEmpty(): Boolean {
|
||||||
|
if (geosite?.isNotEmpty() == true) return false
|
||||||
|
if (domain?.isNotEmpty() == true) return false
|
||||||
|
if (domain_suffix?.isNotEmpty() == true) return false
|
||||||
|
if (domain_regex?.isNotEmpty() == true) return false
|
||||||
|
if (domain_keyword?.isNotEmpty() == true) return false
|
||||||
|
if (user_id?.isNotEmpty() == true) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun SingBoxOptions.Rule_DefaultOptions.makeSingBoxRule(list: List<String>, isIP: Boolean) {
|
||||||
|
if (isIP) {
|
||||||
|
ip_cidr = mutableListOf<String>()
|
||||||
|
geoip = mutableListOf<String>()
|
||||||
|
} else {
|
||||||
|
geosite = mutableListOf<String>()
|
||||||
|
domain = mutableListOf<String>()
|
||||||
|
domain_suffix = mutableListOf<String>()
|
||||||
|
domain_regex = mutableListOf<String>()
|
||||||
|
domain_keyword = mutableListOf<String>()
|
||||||
|
}
|
||||||
|
list.forEach {
|
||||||
|
if (isIP) {
|
||||||
|
if (it.startsWith("geoip:")) {
|
||||||
|
geoip.plusAssign(it.removePrefix("geoip:"))
|
||||||
|
} else {
|
||||||
|
ip_cidr.plusAssign(it)
|
||||||
|
}
|
||||||
|
return@forEach
|
||||||
|
}
|
||||||
|
if (it.startsWith("geosite:")) {
|
||||||
|
geosite.plusAssign(it.removePrefix("geosite:"))
|
||||||
|
} else if (it.startsWith("full:")) {
|
||||||
|
domain.plusAssign(it.removePrefix("full:"))
|
||||||
|
} else if (it.startsWith("domain:")) {
|
||||||
|
domain_suffix.plusAssign(it.removePrefix("domain:"))
|
||||||
|
} else if (it.startsWith("regexp:")) {
|
||||||
|
domain_regex.plusAssign(it.removePrefix("regexp:"))
|
||||||
|
} else if (it.startsWith("keyword:")) {
|
||||||
|
domain_keyword.plusAssign(it.removePrefix("keyword:"))
|
||||||
|
} else {
|
||||||
|
domain.plusAssign(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ip_cidr?.isEmpty() == true) ip_cidr = null
|
||||||
|
if (geoip?.isEmpty() == true) geoip = null
|
||||||
|
if (geosite?.isEmpty() == true) geosite = null
|
||||||
|
if (domain?.isEmpty() == true) domain = null
|
||||||
|
if (domain_suffix?.isEmpty() == true) domain_suffix = null
|
||||||
|
if (domain_regex?.isEmpty() == true) domain_regex = null
|
||||||
|
if (domain_keyword?.isEmpty() == true) domain_keyword = null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun SingBoxOptions.Rule_DefaultOptions.checkEmpty(): Boolean {
|
||||||
|
if (ip_cidr?.isNotEmpty() == true) return false
|
||||||
|
if (geoip?.isNotEmpty() == true) return false
|
||||||
|
if (geosite?.isNotEmpty() == true) return false
|
||||||
|
if (domain?.isNotEmpty() == true) return false
|
||||||
|
if (domain_suffix?.isNotEmpty() == true) return false
|
||||||
|
if (domain_regex?.isNotEmpty() == true) return false
|
||||||
|
if (domain_keyword?.isNotEmpty() == true) return false
|
||||||
|
if (user_id?.isNotEmpty() == true) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
source ../buildScript/init/env_ndk.sh
|
source ../buildScript/init/env_ndk.sh
|
||||||
|
|
||||||
[ $rel ] || sed -i "s/buildDate .*/buildDate := \"`date +'%Y%m%d'`\"/g" date.go
|
[ $rel ] || sed -i "s/buildDate .*/buildDate := `date +'%Y%m%d'`/g" date.go
|
||||||
|
|
||||||
BUILD=".build"
|
BUILD=".build"
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
package libcore
|
package libcore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var outdated string
|
var outdated string
|
||||||
|
|
||||||
func GetBuildTime() int64 {
|
func GetBuildTime() int64 {
|
||||||
buildDate := "20230327"
|
buildDate := 20230330
|
||||||
buildTime, _ := time.Parse("20060102", buildDate)
|
buildTime, _ := time.Parse("20060102", strconv.Itoa(buildDate))
|
||||||
return buildTime.Unix()
|
return buildTime.Unix()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -105,11 +105,11 @@ func verifyAPK() {
|
|||||||
for sc.Scan() {
|
for sc.Scan() {
|
||||||
line := sc.Text()
|
line := sc.Text()
|
||||||
if strings.HasSuffix(line, "/base.apk") {
|
if strings.HasSuffix(line, "/base.apk") {
|
||||||
apkPath = line[strings.Index(line, "/data/"):]
|
apkPath = line[strings.Index(line, "/"):]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
|
||||||
certs, err := apkverifier.ExtractCerts(apkPath, nil)
|
certs, err := apkverifier.ExtractCerts(apkPath, nil)
|
||||||
if certs == nil || err != nil {
|
if certs == nil || err != nil {
|
||||||
outdated = fmt.Sprintf("verifyAPK: no certificate: %v", err)
|
outdated = fmt.Sprintf("verifyAPK: no certificate: %v", err)
|
||||||
@ -128,7 +128,7 @@ func verifyAPK() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
outdated = fmt.Sprintf("verifyAPK: unknown signer")
|
outdated = "verifyAPK: unknown signer"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user