feat: add sharelink for TUIC

This commit is contained in:
HystericalDragon 2023-08-13 20:33:35 +08:00 committed by arm64v8a
parent e300558912
commit 9b49ffd20e
3 changed files with 63 additions and 2 deletions

View File

@ -24,6 +24,7 @@ import io.nekohasekai.sagernet.fmt.trojan_go.TrojanGoBean
import io.nekohasekai.sagernet.fmt.trojan_go.buildTrojanGoConfig import io.nekohasekai.sagernet.fmt.trojan_go.buildTrojanGoConfig
import io.nekohasekai.sagernet.fmt.trojan_go.toUri import io.nekohasekai.sagernet.fmt.trojan_go.toUri
import io.nekohasekai.sagernet.fmt.tuic.TuicBean import io.nekohasekai.sagernet.fmt.tuic.TuicBean
import io.nekohasekai.sagernet.fmt.tuic.toUri
import io.nekohasekai.sagernet.fmt.tuic.buildTuicConfig import io.nekohasekai.sagernet.fmt.tuic.buildTuicConfig
import io.nekohasekai.sagernet.fmt.v2ray.* import io.nekohasekai.sagernet.fmt.v2ray.*
import io.nekohasekai.sagernet.fmt.wireguard.WireGuardBean import io.nekohasekai.sagernet.fmt.wireguard.WireGuardBean
@ -225,7 +226,6 @@ data class ProxyEntity(
fun haveStandardLink(): Boolean { fun haveStandardLink(): Boolean {
return when (requireBean()) { return when (requireBean()) {
is TuicBean -> false
is SSHBean -> false is SSHBean -> false
is WireGuardBean -> false is WireGuardBean -> false
is ShadowTLSBean -> false is ShadowTLSBean -> false
@ -245,6 +245,7 @@ data class ProxyEntity(
is TrojanGoBean -> toUri() is TrojanGoBean -> toUri()
is NaiveBean -> toUri() is NaiveBean -> toUri()
is HysteriaBean -> toUri() is HysteriaBean -> toUri()
is TuicBean -> toUri()
is NekoBean -> shareLink() is NekoBean -> shareLink()
else -> toUniversalLink() else -> toUniversalLink()
} }

View File

@ -1,7 +1,7 @@
package io.nekohasekai.sagernet.fmt.tuic package io.nekohasekai.sagernet.fmt.tuic
import io.nekohasekai.sagernet.fmt.LOCALHOST import io.nekohasekai.sagernet.fmt.LOCALHOST
import io.nekohasekai.sagernet.ktx.isIpAddress import io.nekohasekai.sagernet.ktx.*
import moe.matsuri.nb4a.SingBoxOptions import moe.matsuri.nb4a.SingBoxOptions
import moe.matsuri.nb4a.utils.JavaUtil import moe.matsuri.nb4a.utils.JavaUtil
import moe.matsuri.nb4a.utils.Util import moe.matsuri.nb4a.utils.Util
@ -9,6 +9,58 @@ import moe.matsuri.nb4a.utils.listByLineOrComma
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import java.io.File import java.io.File
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
fun parseTuic(url: String): TuicBean {
// https://github.com/daeuniverse/dae/discussions/182
var link = url.replace("tuic://", "https://").toHttpUrlOrNull() ?: error(
"invalid tuic link $url"
)
return TuicBean().apply {
protocolVersion = 5
name = link.fragment
uuid = link.username
token = link.password
serverAddress = link.host
serverPort = link.port
link.queryParameter("sni")?.let {
sni = it
}
link.queryParameter("congestion_control")?.let {
congestionController = it
}
link.queryParameter("udp_relay_mode")?.let {
udpRelayMode = it
}
link.queryParameter("alpn")?.let {
alpn = it
}
link.queryParameter("allow_insecure")?.let {
if (it == "1") allowInsecure = true
}
link.queryParameter("disable_sni")?.let {
if (it == "1") disableSNI =true
}
}
}
fun TuicBean.toUri(): String {
val builder = linkBuilder().username(uuid).password(token).host(serverAddress).port(serverPort)
builder.addQueryParameter("congestion_control", congestionController)
builder.addQueryParameter("udp_relay_mode", udpRelayMode)
if (sni.isNotBlank()) builder.addQueryParameter("sni", sni)
if (alpn.isNotBlank()) builder.addQueryParameter("alpn", alpn)
if (allowInsecure) builder.addQueryParameter("allow_insecure", "1")
if (disableSNI) builder.addQueryParameter("disable_sni", "1")
if (name.isNotBlank()) builder.encodedFragment(name.urlSafe())
return builder.toLink("tuic")
}
fun buildSingBoxOutboundTuicBean(bean: TuicBean): SingBoxOptions.Outbound_TUICOptions { fun buildSingBoxOutboundTuicBean(bean: TuicBean): SingBoxOptions.Outbound_TUICOptions {
return SingBoxOptions.Outbound_TUICOptions().apply { return SingBoxOptions.Outbound_TUICOptions().apply {

View File

@ -10,6 +10,7 @@ import io.nekohasekai.sagernet.fmt.parseUniversal
import io.nekohasekai.sagernet.fmt.shadowsocks.parseShadowsocks import io.nekohasekai.sagernet.fmt.shadowsocks.parseShadowsocks
import io.nekohasekai.sagernet.fmt.socks.parseSOCKS import io.nekohasekai.sagernet.fmt.socks.parseSOCKS
import io.nekohasekai.sagernet.fmt.trojan.parseTrojan import io.nekohasekai.sagernet.fmt.trojan.parseTrojan
import io.nekohasekai.sagernet.fmt.tuic.parseTuic
import io.nekohasekai.sagernet.fmt.trojan_go.parseTrojanGo import io.nekohasekai.sagernet.fmt.trojan_go.parseTrojanGo
import io.nekohasekai.sagernet.fmt.v2ray.parseV2Ray import io.nekohasekai.sagernet.fmt.v2ray.parseV2Ray
import moe.matsuri.nb4a.plugin.NekoPluginManager import moe.matsuri.nb4a.plugin.NekoPluginManager
@ -187,6 +188,13 @@ suspend fun parseProxies(text: String): List<AbstractBean> {
}.onFailure { }.onFailure {
Logs.w(it) Logs.w(it)
} }
} else if (startsWith("tuic://")) {
Logs.d("Try parse TUIC link: $this")
runCatching {
entities.add(parseTuic(this))
}.onFailure {
Logs.w(it)
}
} else { // Neko Plugins } else { // Neko Plugins
NekoPluginManager.getProtocols().forEach { obj -> NekoPluginManager.getProtocols().forEach { obj ->
obj.protocolConfig.optJSONArray("links")?.forEach { _, any -> obj.protocolConfig.optJSONArray("links")?.forEach { _, any ->