1
0
mirror of https://github.com/MGislv/NekoX.git synced 2024-06-30 10:14:04 +00:00

Support add clash url as subscription

This commit is contained in:
世界 2021-02-17 14:28:33 +08:00
parent bc2261efd9
commit 06df6a63dd
No known key found for this signature in database
GPG Key ID: CD109927C34A63C4
8 changed files with 158 additions and 19 deletions

View File

@ -1,8 +1,8 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
def verName = "7.4.2-rc06"
def verCode = 186
def verName = "7.4.2-rc07"
def verCode = 188
def officialVer = "7.4.2"
def officialCode = 2227
@ -85,6 +85,7 @@ dependencies {
implementation 'cn.hutool:hutool-crypto:5.5.8'
implementation 'cn.hutool:hutool-http:5.5.8'
implementation 'org.yaml:snakeyaml:1.27'
implementation 'com.jakewharton:process-phoenix:2.0.0'
implementation project(":openpgp-api")
@ -138,7 +139,7 @@ pwd = pwd ?: System.getenv("ALIAS_PASS")
android {
compileSdkVersion 30
buildToolsVersion '30.0.3'
ndkVersion rootProject.ext.ndkVersion
ndkVersion '21.3.6528147'
defaultConfig.applicationId = "nekox.messenger"

View File

@ -32,16 +32,17 @@ import org.telegram.messenger.R
init {
add(NoPlugin)
addAll(ApplicationLoader.applicationContext.packageManager.queryIntentContentProviders(
Intent(PluginContract.ACTION_NATIVE_PLUGIN), PackageManager.GET_META_DATA).map { NativePlugin(it) })
Intent(PluginContract.ACTION_NATIVE_PLUGIN), PackageManager.GET_META_DATA)
.map { NativePlugin(it) })
}
val lookup = mutableMapOf<String, Plugin>().apply {
for (plugin in this@PluginList) {
fun check(old: Plugin?) = check(old == null || old === plugin) { LocaleController.formatString("SSPluginConflictingName",R.string.SSPluginConflictingName,plugin.id) }
check(put(plugin.id, plugin))
for (alias in plugin.idAliases) check(put(alias, plugin))
}
}
val lookupNames get() = lookup.values.map {
if (it.label.isNotBlank() && it.id.isNotBlank()) {
"${it.label} (${it.id})"

View File

@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import cn.hutool.core.codec.Base64
import com.github.shadowsocks.plugin.PluginConfiguration
import com.github.shadowsocks.plugin.PluginManager
import com.github.shadowsocks.plugin.PluginOptions
import com.v2ray.ang.V2RayConfig.SS_PROTOCOL
import kotlinx.coroutines.runBlocking
import okhttp3.HttpUrl
@ -106,16 +107,29 @@ class ShadowsocksLoader {
val pl = PluginConfiguration(plugin)
if (pl.selected.contains("v2ray") && pl.selected != "v2ray") {
if (pl.selected.contains("v2ray") && pl.selected != "v2ray-plugin") {
pl.pluginsOptions["v2ray"] = pl.getOptions()
pl.pluginsOptions["v2ray-plugin"] = pl.getOptions().apply { id = "v2ray-plugin" }
pl.pluginsOptions.remove(pl.selected)
pl.selected = "v2ray"
pl.selected = "v2ray-plugin"
// reslove v2ray plugin
}
if (pl.selected == "obfs") {
pl.pluginsOptions["obfs-local"] = pl.getOptions().apply { id = "obfs-local" }
pl.pluginsOptions.remove(pl.selected)
pl.selected = "obfs-local"
// reslove clash obfs
}
plugin = pl.toString()
}
override fun equals(other: Any?): Boolean {
@ -150,6 +164,23 @@ class ShadowsocksLoader {
companion object {
fun parseJson(ssObj: JSONObject): Bean {
var pluginStr = ""
val pId = ssObj.optString("plugin")
if (!pId.isNullOrBlank()) {
val plugin = PluginOptions(pId, ssObj.optString("plugin_opts"))
pluginStr = plugin.toString(false)
}
return Bean(
ssObj.getString("server"),
ssObj.getInt("server_port"),
ssObj.getString("password"),
ssObj.getString("method"),
pluginStr,
ssObj.optString("remarks")
)
}
fun parse(url: String): Bean {
if (url.contains("@")) {
@ -157,7 +188,7 @@ class ShadowsocksLoader {
// ss-android style
val link = url.replace(SS_PROTOCOL, "https://").toHttpUrlOrNull()
?: error("invalid ss-android link $url")
?: error("invalid ss-android link $url")
if (link.password.isNotBlank()) {

View File

@ -99,7 +99,7 @@ class ShadowsocksRLoader {
var remarks: String? = null
) {
val hash = (host + remotePort + password + protocol + obfs + method).hashCode()
val hash get() = (host + remotePort + password + protocol + obfs + method).hashCode()
override fun equals(other: Any?): Boolean {
return super.equals(other) || (other is Bean && hash == other.hash)

View File

@ -1,3 +1,5 @@
@file:Suppress("UNCHECKED_CAST")
package tw.nekomimi.nekogram.utils
import android.Manifest
@ -20,20 +22,28 @@ import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.Toast
import androidx.core.view.setPadding
import com.github.shadowsocks.plugin.PluginOptions
import com.google.zxing.*
import com.google.zxing.common.GlobalHistogramBinarizer
import com.google.zxing.qrcode.QRCodeReader
import com.google.zxing.qrcode.QRCodeWriter
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import com.v2ray.ang.V2RayConfig
import com.v2ray.ang.V2RayConfig.SSR_PROTOCOL
import com.v2ray.ang.V2RayConfig.SS_PROTOCOL
import com.v2ray.ang.V2RayConfig.TROJAN_PROTOCOL
import com.v2ray.ang.V2RayConfig.VMESS1_PROTOCOL
import com.v2ray.ang.V2RayConfig.VMESS_PROTOCOL
import com.v2ray.ang.dto.AngConfig
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.json.JSONArray
import org.json.JSONException
import org.telegram.messenger.*
import org.telegram.messenger.browser.Browser
import org.yaml.snakeyaml.Yaml
import tw.nekomimi.nekogram.BottomBuilder
import tw.nekomimi.nekogram.ShadowsocksLoader
import tw.nekomimi.nekogram.ShadowsocksRLoader
import tw.nekomimi.nekogram.utils.AlertUtil.showToast
import java.io.File
import java.net.NetworkInterface
@ -66,17 +76,113 @@ object ProxyUtil {
fun parseProxies(_text: String): MutableList<String> {
val text = runCatching {
String(Base64.decode(_text, Base64.NO_PADDING))
}.recover {
_text
}.getOrThrow()
val proxies = mutableListOf<String>()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try {
// sip008
val ssArray = JSONArray(text)
for (index in 0..ssArray.length()) {
proxies.add(ShadowsocksLoader.Bean.parseJson(ssArray.getJSONObject(index)).toString())
}
return proxies
} catch (ignored: JSONException) {
}
if (text.contains("proxies:\n")) {
// clash
for (proxy in (Yaml().loadAs(text, Map::class.java)["proxies"] as List<Map<String, Any?>>)) {
val type = proxy["type"] as String
when (type) {
"ss" -> {
var pluginStr = ""
if (proxy.contains("plugin")) {
val opts = PluginOptions()
opts.id = proxy["plugin"] as String
opts.putAll(proxy["plugin-opts"] as Map<String, String?>)
pluginStr = opts.toString(false)
}
proxies.add(ShadowsocksLoader.Bean(
proxy["server"] as String,
proxy["port"] as Int,
proxy["password"] as String,
proxy["cipher"] as String,
pluginStr,
proxy["name"] as String
).toString())
}
"vmess" -> {
val opts = AngConfig.VmessBean()
for (opt in proxy) {
when (opt.key) {
"name" -> opts.remarks = opt.value as String
"server" -> opts.address = opt.value as String
"port" -> opts.port = opt.value as Int
"uuid" -> opts.id = opt.value as String
"alterId" -> opts.alterId = opt.value as Int
"cipher" -> opts.security = opt.value as String
"network" -> opts.network = opt.value as String
"tls" -> opts.streamSecurity = if (opt.value?.toString() == "true") "tls" else opts.streamSecurity
"ws-path" -> opts.path = opt.value as String
"servername" -> opts.requestHost = opt.value as String
"h2-opts" -> for (h2Opt in (opt.value as Map<String, Any>)) {
when (h2Opt.key) {
"host" -> opts.requestHost = (h2Opt.value as List<String>).first()
"path" -> opts.path = h2Opt.value as String
}
}
"http-opts" -> for (httpOpt in (opt.value as Map<String, Any>)) {
when (httpOpt.key) {
"path" -> opts.path = (httpOpt.value as List<String>).first()
}
}
}
}
proxies.add(opts.toString())
}
"trojan" -> {
val opts = AngConfig.VmessBean()
opts.configType = V2RayConfig.EConfigType.Trojan
for (opt in proxy) {
when (opt.key) {
"name" -> opts.remarks = opt.value as String
"server" -> opts.address = opt.value as String
"port" -> opts.port = opt.value as Int
"password" -> opts.id = opt.value as String
"sni" -> opts.requestHost = opt.value as String
}
}
proxies.add(opts.toString())
}
"ssr" -> {
val opts = ShadowsocksRLoader.Bean()
for (opt in proxy) {
when (opt.key) {
"name" -> opts.remarks = opt.value as String
"server" -> opts.host = opt.value as String
"port" -> opts.remotePort = opt.value as Int
"cipher" -> opts.method = opt.value as String
"password" -> opts.password = opt.value as String
"obfs" -> opts.obfs = opt.value as String
"protocol" -> opts.protocol = opt.value as String
"obfs-param" -> opts.obfs_param = opt.value as String
"protocol-param" -> opts.protocol_param = opt.value as String
}
}
proxies.add(opts.toString())
}
}
}
return proxies
}
}
text.split('\n').map { it.split(" ") }.forEach {
it.forEach { line ->

View File

@ -16,7 +16,7 @@ buildscript {
}
}
static String detectNdkVersion() {
/*static String detectNdkVersion() {
def version = "21.3.6528147"
@ -40,7 +40,7 @@ ext {
ndkVersion = detectNdkVersion()
}
}*/
allprojects {
repositories {

View File

@ -7,7 +7,7 @@ plugins {
android {
ndkVersion = rootProject.extra.get("ndkVersion").toString()
ndkVersion = "21.3.6528147"
compileSdkVersion(30)
defaultConfig {

View File

@ -4,8 +4,8 @@ plugins {
android {
compileSdkVersion 30
buildToolsVersion '30.0.2'
ndkVersion rootProject.ext.ndkVersion
buildToolsVersion '30.0.3'
ndkVersion "21.3.6528147"
defaultConfig {
minSdkVersion 16