mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-01 12:43:56 +08:00
🎄 Sync 2026-05-06 19:35:12
This commit is contained in:
1 parent
17a7679f9b
commit
80959a4700
50 files changed
+1787
-626
No files matched your search
@@ -23,6 +23,7 @@ local uci = api.uci
|
||||
local fs = api.fs
|
||||
local log = api.log
|
||||
local i18n = api.i18n
|
||||
local lyaml = require "lyaml"
|
||||
|
||||
local has_ss = api.is_finded("ss-redir")
|
||||
local has_ss_rust = api.is_finded("sslocal")
|
||||
@@ -477,6 +478,292 @@ local function set_ss_implementation(ss_type, result)
|
||||
return result
|
||||
end
|
||||
|
||||
local function parseClashNode(node, add_mode, group, sub_cfg)
|
||||
local sub_allowinsecure = DEFAULT_ALLOWINSECURE
|
||||
local sub_ss_type = DEFAULT_SS_TYPE
|
||||
local sub_trojan_type = DEFAULT_TROJAN_TYPE
|
||||
local sub_vmess_type = DEFAULT_VMESS_TYPE
|
||||
local sub_vless_type = DEFAULT_VLESS_TYPE
|
||||
local sub_hysteria2_type = DEFAULT_HYSTERIA2_TYPE
|
||||
if sub_cfg then
|
||||
if sub_cfg.allowInsecure and sub_cfg.allowInsecure ~= "1" then
|
||||
sub_allowinsecure = nil
|
||||
end
|
||||
local ss_type = sub_cfg.ss_type or "global"
|
||||
if ss_type ~= "global" and core_has[ss_type] then
|
||||
sub_ss_type = ss_type
|
||||
end
|
||||
local trojan_type = sub_cfg.trojan_type or "global"
|
||||
if trojan_type ~= "global" and core_has[trojan_type] then
|
||||
sub_trojan_type = trojan_type
|
||||
end
|
||||
local vmess_type = sub_cfg.vmess_type or "global"
|
||||
if vmess_type ~= "global" and core_has[vmess_type] then
|
||||
sub_vmess_type = vmess_type
|
||||
end
|
||||
local vless_type = sub_cfg.vless_type or "global"
|
||||
if vless_type ~= "global" and core_has[vless_type] then
|
||||
sub_vless_type = vless_type
|
||||
end
|
||||
local hysteria2_type = sub_cfg.hysteria2_type or "global"
|
||||
if hysteria2_type ~= "global" and core_has[hysteria2_type] then
|
||||
sub_hysteria2_type = hysteria2_type
|
||||
end
|
||||
end
|
||||
local result = {
|
||||
timeout = 60,
|
||||
add_mode = add_mode, -- `0` for manual configuration, `1` for import, `2` for subscription
|
||||
group = group
|
||||
}
|
||||
result.remarks = node.name
|
||||
result.address = node.server
|
||||
result.port = node.port
|
||||
|
||||
if node.type == 'ss' then
|
||||
result = set_ss_implementation(sub_ss_type, result)
|
||||
if not result then return nil end
|
||||
result.method = node.cipher
|
||||
result.password = node.password
|
||||
if node.plugin == "obfs" then
|
||||
result.plugin = "obfs-local"
|
||||
elseif node.plugin == "v2ray-plugin" then
|
||||
result.plugin = "v2ray-plugin"
|
||||
end
|
||||
if node["plugin-opts"] then
|
||||
if node.plugin == "obfs" then
|
||||
local plugin_opts = ""
|
||||
local opts_mode = node["plugin-opts"].mode
|
||||
if opts_mode then
|
||||
plugin_opts = plugin_opts .. "obfs=" .. opts_mode .. ";"
|
||||
end
|
||||
local opts_host = node["plugin-opts"].host
|
||||
if opts_host then
|
||||
plugin_opts = plugin_opts .. "obfs-host=" .. opts_host
|
||||
end
|
||||
result.plugin_opts = plugin_opts
|
||||
elseif node.plugin == "v2ray-plugin" then
|
||||
local plugin_opts = ""
|
||||
local opts_mode = node["plugin-opts"].mode
|
||||
local opts_tls = node["plugin-opts"].tls
|
||||
if opts_tls then
|
||||
plugin_opts = plugin_opts .. "tls;"
|
||||
end
|
||||
local opts_skip_cert_verify = node["plugin-opts"]["skip-cert-verify"]
|
||||
local opts_host = node["plugin-opts"].host
|
||||
if opts_host then
|
||||
plugin_opts = plugin_opts .. "host=" .. opts_host .. ";"
|
||||
end
|
||||
local opts_path = node["plugin-opts"].path
|
||||
local opts_mux = node["plugin-opts"].mux
|
||||
if node["plugin-opts"].headers then
|
||||
--todo
|
||||
end
|
||||
result.plugin_opts = plugin_opts
|
||||
end
|
||||
end
|
||||
elseif node.type == 'ssr' then
|
||||
if not has_ssr then
|
||||
log(2, i18n.translatef("Skipping the %s node is due to incompatibility with the %s core program or incorrect node usage type settings.", "SSR", "shadowsocksr-libev"))
|
||||
return nil
|
||||
end
|
||||
result.type = "SSR"
|
||||
result.method = node.cipher
|
||||
result.password = node.password
|
||||
result.obfs = node.obfs
|
||||
result.protocol = node.protocol
|
||||
result.obfs_param = node["obfs-param"]
|
||||
result.protocol_param = node["protocol-param"]
|
||||
elseif node.type == 'vmess' then
|
||||
if sub_vmess_type == "sing-box" and has_singbox then
|
||||
result.type = 'sing-box'
|
||||
elseif sub_vmess_type == "xray" and has_xray then
|
||||
result.type = "Xray"
|
||||
else
|
||||
log(2, i18n.translatef("Skipping the %s node is due to incompatibility with the %s core program or incorrect node usage type settings.", "VMess", "VMess"))
|
||||
return nil
|
||||
end
|
||||
result.protocol = 'vmess'
|
||||
result.uuid = node.uuid
|
||||
result.alter_id = node.alterId
|
||||
result.security = node.cipher or "auto"
|
||||
result.tcp_fast_open = node.tfo
|
||||
result.tls = "0"
|
||||
if node.tls then
|
||||
result.tls = "1"
|
||||
result.tls_serverName = node.servername or ""
|
||||
local insecure = node["skip-cert-verify"]
|
||||
result.tls_allowInsecure = insecure and "1" or "0"
|
||||
if sub_allowinsecure then
|
||||
result.tls_allowInsecure = "1"
|
||||
end
|
||||
end
|
||||
result.transport = node.network and string.lower(node.network) or "tcp"
|
||||
if result.type == "sing-box" and result.transport == "raw" then
|
||||
result.transport = "tcp"
|
||||
elseif result.type == "Xray" and result.transport == "tcp" then
|
||||
result.transport = "raw"
|
||||
end
|
||||
if result.transport == 'ws' then
|
||||
local ws_opts = node["ws-opts"]
|
||||
if ws_opts then
|
||||
if ws_opts.headers then
|
||||
result.ws_host = ws_opts.headers.Host or ws_opts.headers.host
|
||||
end
|
||||
if ws_opts.path then
|
||||
result.ws_path = ws_opts.path
|
||||
if ws_opts["max-early-data"] then
|
||||
if result.type == "sing-box" then
|
||||
result.ws_enableEarlyData = "1"
|
||||
result.ws_maxEarlyData = tonumber(ws_opts["max-early-data"])
|
||||
result.ws_earlyDataHeaderName = "Sec-WebSocket-Protocol"
|
||||
elseif result.type == "Xray" then
|
||||
result.ws_path = result.ws_path .. "?ed=" .. ws_opts["max-early-data"]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif result.transport == 'h2' then
|
||||
local h2_opts = node["h2-opts"]
|
||||
if h2_opts then
|
||||
if result.type == "sing-box" then
|
||||
result.http_path = h2_opts.path
|
||||
result.http_host = h2_opts.host
|
||||
elseif result.type == "Xray" then
|
||||
result.xhttp_mode = "stream-one"
|
||||
result.xhttp_path = h2_opts.path
|
||||
result.xhttp_host = h2_opts.host
|
||||
end
|
||||
end
|
||||
elseif result.transport == 'grpc' then
|
||||
local grpc_opts = node["grpc-opts"]
|
||||
if grpc_opts then
|
||||
result.grpc_serviceName = grpc_opts["grpc-service-name"]
|
||||
end
|
||||
end
|
||||
elseif node.type == 'vless' then
|
||||
if sub_vless_type == "sing-box" and has_singbox then
|
||||
result.type = 'sing-box'
|
||||
elseif sub_vless_type == "xray" and has_xray then
|
||||
result.type = "Xray"
|
||||
else
|
||||
log(2, i18n.translatef("Skipping the %s node is due to incompatibility with the %s core program or incorrect node usage type settings.", "VLESS", "VLESS"))
|
||||
return nil
|
||||
end
|
||||
result.protocol = "vless"
|
||||
result.uuid = node.uuid
|
||||
result.tcp_fast_open = node.tfo
|
||||
result.encryption = node.cipher or "none"
|
||||
result.flow = node.flow
|
||||
result.tls = "0"
|
||||
if node.tls then
|
||||
result.tls = "1"
|
||||
result.tls_serverName = node.servername or ""
|
||||
local insecure = node["skip-cert-verify"]
|
||||
result.tls_allowInsecure = insecure and "1" or "0"
|
||||
if sub_allowinsecure then
|
||||
result.tls_allowInsecure = "1"
|
||||
end
|
||||
end
|
||||
result.transport = node.network and string.lower(node.network) or "tcp"
|
||||
if result.type == "sing-box" and result.transport == "raw" then
|
||||
result.transport = "tcp"
|
||||
elseif result.type == "Xray" and result.transport == "tcp" then
|
||||
result.transport = "raw"
|
||||
end
|
||||
if result.transport == 'ws' then
|
||||
local ws_opts = node["ws-opts"]
|
||||
if ws_opts then
|
||||
if ws_opts.headers then
|
||||
result.ws_host = ws_opts.headers.Host or ws_opts.headers.host
|
||||
end
|
||||
if ws_opts.path then
|
||||
result.ws_path = ws_opts.path
|
||||
if ws_opts["max-early-data"] then
|
||||
if result.type == "sing-box" then
|
||||
result.ws_enableEarlyData = "1"
|
||||
result.ws_maxEarlyData = tonumber(ws_opts["max-early-data"])
|
||||
result.ws_earlyDataHeaderName = "Sec-WebSocket-Protocol"
|
||||
elseif result.type == "Xray" then
|
||||
result.ws_path = result.ws_path .. "?ed=" .. ws_opts["max-early-data"]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif node.type == 'trojan' then
|
||||
if sub_trojan_type == "sing-box" and has_singbox then
|
||||
result.type = 'sing-box'
|
||||
result.protocol = 'trojan'
|
||||
elseif sub_trojan_type == "xray" and has_xray then
|
||||
result.type = 'Xray'
|
||||
result.protocol = 'trojan'
|
||||
else
|
||||
log(2, i18n.translatef("Skipping the %s node is due to incompatibility with the %s core program or incorrect node usage type settings.", "Trojan", "Trojan"))
|
||||
return nil
|
||||
end
|
||||
result.password = node.password
|
||||
result.tls = '1'
|
||||
result.tls_serverName = node.sni or ""
|
||||
local insecure = node["skip-cert-verify"]
|
||||
result.tls_allowInsecure = insecure and "1" or "0"
|
||||
if sub_allowinsecure then
|
||||
result.tls_allowInsecure = "1"
|
||||
end
|
||||
if node.alpn then
|
||||
--todo
|
||||
end
|
||||
if node.network == "grpc" then
|
||||
if node["grpc-opts"] then
|
||||
result.grpc_serviceName = node["grpc-opts"]["grpc-service-name"]
|
||||
end
|
||||
elseif node.network == "ws" then
|
||||
local ws_opts = node["ws-opts"]
|
||||
if ws_opts then
|
||||
result.ws_path = ws_opts.path
|
||||
if ws_opts.headers then
|
||||
result.ws_host = ws_opts.headers.Host or ws_opts.headers.host
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif node.type == 'anytls' then
|
||||
if has_singbox then
|
||||
result.type = 'sing-box'
|
||||
result.protocol = "anytls"
|
||||
else
|
||||
log(2, i18n.translatef("Skip the %s node because the %s core program is not installed.", "AnyTLS", "AnyTLS", "Sing-Box 1.12"))
|
||||
return nil
|
||||
end
|
||||
result.password = node.password
|
||||
result.tls = '1'
|
||||
result.tls_serverName = node.sni or ""
|
||||
local insecure = node["skip-cert-verify"]
|
||||
result.tls_allowInsecure = insecure and "1" or "0"
|
||||
if sub_allowinsecure then
|
||||
result.tls_allowInsecure = "1"
|
||||
end
|
||||
end
|
||||
if not result.remarks or result.remarks == "" then
|
||||
if result.address and result.port then
|
||||
result.remarks = result.address .. ':' .. result.port
|
||||
else
|
||||
result.remarks = "NULL"
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
-- Processing Clash data
|
||||
local function processClashData(content, add_mode, group, sub_cfg)
|
||||
local results = {}
|
||||
for i, node in ipairs(content.proxies or {}) do
|
||||
local result = parseClashNode(node, add_mode, group, sub_cfg)
|
||||
if result then
|
||||
table.insert(results, result)
|
||||
end
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
-- Processing data
|
||||
local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
--log(2, content, add_mode, group)
|
||||
@@ -650,9 +937,14 @@ local function processData(szType, content, add_mode, group, sub_cfg)
|
||||
result.httpupgrade_host = info.host
|
||||
result.httpupgrade_path = info.path
|
||||
end
|
||||
if not info.security then result.security = "auto" end
|
||||
result.security = info.security or info.scy or "auto"
|
||||
if info.tls == "tls" or info.tls == "1" then
|
||||
result.tls = "1"
|
||||
result.alpn = info.alpn
|
||||
if info.fp and info.fp ~= "" then
|
||||
result.utls = "1"
|
||||
result.fingerprint = info.fp
|
||||
end
|
||||
result.tls_serverName = (info.sni and info.sni ~= "") and info.sni or info.host
|
||||
result.tls_pinSHA256 = info.pcs
|
||||
result.tls_CertByName = info.vcn
|
||||
@@ -2001,7 +2293,7 @@ local function parse_link(raw, add_mode, group, sub_cfg)
|
||||
if sub_cfg then
|
||||
cfgid = sub_cfg[".name"]
|
||||
end
|
||||
local nodes, szType
|
||||
local nodes, szType, clashTable
|
||||
local node_list = {}
|
||||
-- ssd appear to be in this format, starting with ssd://.
|
||||
if raw:find('ssd://') then
|
||||
@@ -2022,11 +2314,45 @@ local function parse_link(raw, add_mode, group, sub_cfg)
|
||||
end
|
||||
nodes = servers
|
||||
else
|
||||
-- Formats other than ssd
|
||||
if add_mode == "1" then
|
||||
nodes = split(raw, "\n")
|
||||
-- Try parseYAML, if success, is clash.
|
||||
local yamlTable = lyaml.load(raw)
|
||||
if yamlTable and type(yamlTable) == "table" then
|
||||
-- clash
|
||||
szType = "clash"
|
||||
clashTable = yamlTable
|
||||
else
|
||||
nodes = split(base64Decode(raw):gsub("\r\n", "\n"), "\n")
|
||||
-- Formats other than ssd
|
||||
if add_mode == "1" then
|
||||
nodes = split(raw, "\n")
|
||||
else
|
||||
nodes = split(base64Decode(raw):gsub("\r\n", "\n"), "\n")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function nodeFilter(node)
|
||||
if node then
|
||||
if node.error_msg then
|
||||
log(2, i18n.translatef("Discard node: %s, Reason:", node.remarks) .. " " .. node.error_msg)
|
||||
elseif not node.type then
|
||||
log(2, i18n.translatef("Discard node: %s, Reason:", node.remarks) .. " " .. i18n.translatef("No usable binary was found."))
|
||||
elseif (add_mode == "2" and is_filter_keyword(sub_cfg, node.remarks)) or not node.address or node.remarks == "NULL" or node.address == "127.0.0.1" or
|
||||
(not datatypes.hostname(node.address) and not (api.is_ip(node.address))) then
|
||||
log(2, i18n.translatef("Discard filter nodes: %s type node %s", node.type, node.remarks))
|
||||
else
|
||||
tinsert(node_list, node)
|
||||
end
|
||||
if add_mode == "2" then
|
||||
get_subscribe_info(cfgid, node.remarks)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if szType == "clash" and clashTable then
|
||||
nodes = {}
|
||||
local clashNodes = processClashData(clashTable, add_mode, group, sub_cfg)
|
||||
for _, v in ipairs(clashNodes) do
|
||||
nodeFilter(v)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2052,21 +2378,7 @@ local function parse_link(raw, add_mode, group, sub_cfg)
|
||||
log(2, i18n.translatef("Skip unknown types:") .. " " .. szType)
|
||||
end
|
||||
-- log(2, result)
|
||||
if result then
|
||||
if result.error_msg then
|
||||
log(2, i18n.translatef("Discard node: %s, Reason:", result.remarks) .. " " .. result.error_msg)
|
||||
elseif not result.type then
|
||||
log(2, i18n.translatef("Discard node: %s, Reason:", result.remarks) .. " " .. i18n.translatef("No usable binary was found."))
|
||||
elseif (add_mode == "2" and is_filter_keyword(sub_cfg, result.remarks)) or not result.address or result.remarks == "NULL" or result.address == "127.0.0.1" or
|
||||
(not datatypes.hostname(result.address) and not (api.is_ip(result.address))) then
|
||||
log(2, i18n.translatef("Discard filter nodes: %s type node %s", result.type, result.remarks))
|
||||
else
|
||||
tinsert(node_list, result)
|
||||
end
|
||||
if add_mode == "2" then
|
||||
get_subscribe_info(cfgid, result.remarks)
|
||||
end
|
||||
end
|
||||
nodeFilter(result)
|
||||
end, function (err)
|
||||
--log(2, err)
|
||||
log(2, v, i18n.translatef("Parsing error, skip this node."))
|
||||
|
||||
Reference in new issue
Block a user