Skip to content

Commit a1b5813

Browse files
committed
anytls share link
1 parent 56f90f2 commit a1b5813

4 files changed

Lines changed: 60 additions & 10 deletions

File tree

app/src/main/java/io/nekohasekai/sagernet/database/ProxyEntity.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,11 @@ import io.nekohasekai.sagernet.fmt.tuic.toUri
3030
import io.nekohasekai.sagernet.fmt.v2ray.*
3131
import io.nekohasekai.sagernet.fmt.wireguard.WireGuardBean
3232
import io.nekohasekai.sagernet.ktx.app
33-
import io.nekohasekai.sagernet.ktx.applyDefaultValues
3433
import io.nekohasekai.sagernet.ui.profile.*
3534
import moe.matsuri.nb4a.SingBoxOptions.MultiplexOptions
3635
import moe.matsuri.nb4a.proxy.anytls.AnyTLSBean
3736
import moe.matsuri.nb4a.proxy.anytls.AnyTLSSettingsActivity
37+
import moe.matsuri.nb4a.proxy.anytls.toUri
3838
import moe.matsuri.nb4a.proxy.config.ConfigBean
3939
import moe.matsuri.nb4a.proxy.config.ConfigSettingActivity
4040
import moe.matsuri.nb4a.proxy.neko.*
@@ -98,10 +98,8 @@ data class ProxyEntity(
9898

9999
val chainName by lazy { app.getString(R.string.proxy_chain) }
100100

101-
private val placeHolderBean = SOCKSBean().applyDefaultValues()
102-
103101
@JvmField
104-
val CREATOR = object : Serializable.CREATOR<ProxyEntity>() {
102+
val CREATOR = object : CREATOR<ProxyEntity>() {
105103

106104
override fun newInstance(): ProxyEntity {
107105
return ProxyEntity()
@@ -241,7 +239,6 @@ data class ProxyEntity(
241239
is SSHBean -> false
242240
is WireGuardBean -> false
243241
is ShadowTLSBean -> false
244-
is AnyTLSBean -> false
245242
is NekoBean -> nekoBean!!.haveStandardLink()
246243
is ConfigBean -> false
247244
else -> true
@@ -259,6 +256,7 @@ data class ProxyEntity(
259256
is NaiveBean -> toUri()
260257
is HysteriaBean -> toUri()
261258
is TuicBean -> toUri()
259+
is AnyTLSBean -> toUri()
262260
is NekoBean -> shareLink()
263261
else -> toUniversalLink()
264262
}

app/src/main/java/io/nekohasekai/sagernet/ktx/Formats.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import io.nekohasekai.sagernet.fmt.tuic.parseTuic
1515
import io.nekohasekai.sagernet.fmt.trojan_go.parseTrojanGo
1616
import io.nekohasekai.sagernet.fmt.v2ray.parseV2Ray
1717
import moe.matsuri.nb4a.plugin.NekoPluginManager
18+
import moe.matsuri.nb4a.proxy.anytls.parseAnytls
1819
import moe.matsuri.nb4a.proxy.neko.NekoJSInterface
1920
import moe.matsuri.nb4a.proxy.neko.parseShareLink
2021
import moe.matsuri.nb4a.utils.JavaUtil.gson
@@ -203,6 +204,13 @@ suspend fun parseProxies(text: String): List<AbstractBean> {
203204
}.onFailure {
204205
Logs.w(it)
205206
}
207+
} else if (startsWith("anytls://")) {
208+
Logs.d("Try parse anytls link: $this")
209+
runCatching {
210+
entities.add(parseAnytls(this))
211+
}.onFailure {
212+
Logs.w(it)
213+
}
206214
} else { // Neko Plugins
207215
NekoPluginManager.getProtocols().forEach { obj ->
208216
obj.protocolConfig.optJSONArray("links")?.forEach { _, any ->
@@ -228,12 +236,12 @@ suspend fun parseProxies(text: String): List<AbstractBean> {
228236
for (link in linksByLine) {
229237
link.parseLink(entitiesByLine)
230238
}
231-
var isBadLink = false
239+
// var isBadLink = false
232240
if (entities.onEach { it.initializeDefaultValues() }.size == entitiesByLine.onEach { it.initializeDefaultValues() }.size) run test@{
233241
entities.forEachIndexed { index, bean ->
234242
val lineBean = entitiesByLine[index]
235243
if (bean == lineBean && bean.displayName() != lineBean.displayName()) {
236-
isBadLink = true
244+
// isBadLink = true
237245
return@test
238246
}
239247
}

app/src/main/java/io/nekohasekai/sagernet/ui/ConfigurationFragment.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1661,8 +1661,8 @@ class ConfigurationFragment @JvmOverloads constructor(
16611661
try {
16621662
currentName = entity.displayName()!!
16631663
when (item.itemId) {
1664-
R.id.action_standard_qr -> showCode(entity.toStdLink()!!)
1665-
R.id.action_standard_clipboard -> export(entity.toStdLink()!!)
1664+
R.id.action_standard_qr -> showCode(entity.toStdLink())
1665+
R.id.action_standard_clipboard -> export(entity.toStdLink())
16661666
R.id.action_universal_qr -> showCode(entity.requireBean().toUniversalLink())
16671667
R.id.action_universal_clipboard -> export(
16681668
entity.requireBean().toUniversalLink()

app/src/main/java/moe/matsuri/nb4a/proxy/anytls/AnyTLSFmt.kt

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package moe.matsuri.nb4a.proxy.anytls
22

33
import io.nekohasekai.sagernet.ktx.blankAsNull
4+
import io.nekohasekai.sagernet.ktx.linkBuilder
5+
import io.nekohasekai.sagernet.ktx.toLink
6+
import io.nekohasekai.sagernet.ktx.urlSafe
47
import moe.matsuri.nb4a.SingBoxOptions
58
import moe.matsuri.nb4a.utils.listByLineOrComma
9+
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
610

711
fun buildSingBoxOutboundAnyTLSBean(bean: AnyTLSBean): SingBoxOptions.Outbound_AnyTLSOptions {
812
return SingBoxOptions.Outbound_AnyTLSOptions().apply {
@@ -34,4 +38,44 @@ fun buildSingBoxOutboundAnyTLSBean(bean: AnyTLSBean): SingBoxOptions.Outbound_An
3438
}
3539
}
3640
}
37-
}
41+
}
42+
43+
fun AnyTLSBean.toUri(): String {
44+
val builder = linkBuilder()
45+
.host(serverAddress)
46+
.port(serverPort)
47+
.username(password)
48+
if (!name.isNullOrBlank()) {
49+
builder.encodedFragment(name.urlSafe())
50+
}
51+
if (allowInsecure) {
52+
builder.addQueryParameter("insecure", "1")
53+
}
54+
if (!sni.isNullOrBlank()) {
55+
builder.addQueryParameter("sni", sni)
56+
}
57+
if (!utlsFingerprint.isNullOrBlank()) {
58+
builder.addQueryParameter("fp", utlsFingerprint)
59+
}
60+
return builder.toLink("anytls")
61+
}
62+
63+
fun parseAnytls(url: String): AnyTLSBean {
64+
// https://github.com/anytls/anytls-go/blob/main/docs/uri_scheme.md
65+
val link = url.replace("anytls://", "https://").toHttpUrlOrNull() ?: error(
66+
"invalid anytls link $url"
67+
)
68+
return AnyTLSBean().apply {
69+
serverAddress = link.host
70+
serverPort = link.port
71+
name = link.fragment
72+
password = link.username
73+
sni = link.queryParameter("sni") ?: ""
74+
link.queryParameter("insecure")?.also {
75+
allowInsecure = it == "1" || it == "true"
76+
}
77+
link.queryParameter("fp")?.let {
78+
utlsFingerprint = it
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)