From afb5f7b88002a56b8018ba6e66387ef742317173 Mon Sep 17 00:00:00 2001 From: xream Date: Wed, 5 Feb 2025 20:01:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=20VLESS=20spx=20?= =?UTF-8?q?=E5=8F=82=E6=95=B0;=20=E6=94=AF=E6=8C=81=20Trojan=20=E7=BB=93?= =?UTF-8?q?=E5=90=88=20REALITY/XHTTP?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/package.json | 2 +- backend/src/core/proxy-utils/parsers/index.js | 9 +++- .../proxy-utils/parsers/peggy/trojan-uri.js | 24 ++++++++++ .../proxy-utils/parsers/peggy/trojan-uri.peg | 24 ++++++++++ backend/src/core/proxy-utils/producers/uri.js | 47 +++++++++++++++++-- 5 files changed, 100 insertions(+), 6 deletions(-) diff --git a/backend/package.json b/backend/package.json index fd4cc9c..ea90316 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "sub-store", - "version": "2.16.25", + "version": "2.16.26", "description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.", "main": "src/main.js", "scripts": { diff --git a/backend/src/core/proxy-utils/parsers/index.js b/backend/src/core/proxy-utils/parsers/index.js index ac81a11..e29be4d 100644 --- a/backend/src/core/proxy-utils/parsers/index.js +++ b/backend/src/core/proxy-utils/parsers/index.js @@ -529,6 +529,9 @@ function URI_VLESS() { if (params.sid) { opts['short-id'] = params.sid; } + if (params.spx) { + opts['_spider-x'] = params.spx; + } if (Object.keys(opts).length > 0) { // proxy[`${params.security}-opts`] = opts; proxy[`${params.security}-opts`] = opts; @@ -596,8 +599,12 @@ function URI_VLESS() { // mKCP 的伪装头部类型。当前可选值有 none / srtp / utp / wechat-video / dtls / wireguard。省略时默认值为 none,即不使用伪装头部,但不可以为空字符串。 proxy.headerType = params.headerType || 'none'; } + + if (params.mode) { + proxy._mode = params.mode; + } if (params.extra) { - proxy.extra = params.extra; + proxy._extra = params.extra; } } diff --git a/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.js b/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.js index f5018d8..bc27623 100644 --- a/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.js +++ b/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.js @@ -80,6 +80,9 @@ port = digits:[0-9]+ { } params = "?" head:param tail:("&"@param)* { + for (const [key, value] of Object.entries(params)) { + params[key] = decodeURIComponent(value); + } proxy["skip-cert-verify"] = toBool(params["allowInsecure"]); proxy.sni = params["sni"] || params["peer"]; proxy['client-fingerprint'] = params.fp; @@ -115,6 +118,27 @@ params = "?" head:param tail:("&"@param)* { $set(proxy, proxy.network+"-opts.v2ray-http-upgrade-fast-open", true); } } + if (['reality'].includes(params.security)) { + const opts = {}; + if (params.pbk) { + opts['public-key'] = params.pbk; + } + if (params.sid) { + opts['short-id'] = params.sid; + } + if (params.spx) { + opts['_spider-x'] = params.spx; + } + if (params.mode) { + proxy._mode = params.mode; + } + if (params.extra) { + proxy._extra = params.extra; + } + if (Object.keys(opts).length > 0) { + $set(proxy, params.security+"-opts", opts); + } + } } proxy.udp = toBool(params["udp"]); diff --git a/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.peg b/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.peg index e42f388..c97d8e9 100644 --- a/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.peg +++ b/backend/src/core/proxy-utils/parsers/peggy/trojan-uri.peg @@ -78,6 +78,9 @@ port = digits:[0-9]+ { } params = "?" head:param tail:("&"@param)* { + for (const [key, value] of Object.entries(params)) { + params[key] = decodeURIComponent(value); + } proxy["skip-cert-verify"] = toBool(params["allowInsecure"]); proxy.sni = params["sni"] || params["peer"]; proxy['client-fingerprint'] = params.fp; @@ -113,6 +116,27 @@ params = "?" head:param tail:("&"@param)* { $set(proxy, proxy.network+"-opts.v2ray-http-upgrade-fast-open", true); } } + if (['reality'].includes(params.security)) { + const opts = {}; + if (params.pbk) { + opts['public-key'] = params.pbk; + } + if (params.sid) { + opts['short-id'] = params.sid; + } + if (params.spx) { + opts['_spider-x'] = params.spx; + } + if (params.mode) { + proxy._mode = params.mode; + } + if (params.extra) { + proxy._extra = params.extra; + } + if (Object.keys(opts).length > 0) { + $set(proxy, params.security+"-opts", opts); + } + } } proxy.udp = toBool(params["udp"]); diff --git a/backend/src/core/proxy-utils/producers/uri.js b/backend/src/core/proxy-utils/producers/uri.js index 428edb8..88f5f79 100644 --- a/backend/src/core/proxy-utils/producers/uri.js +++ b/backend/src/core/proxy-utils/producers/uri.js @@ -149,6 +149,7 @@ export default function URI_Producer() { const isReality = proxy['reality-opts']; let sid = ''; let pbk = ''; + let spx = ''; if (isReality) { security = 'reality'; const publicKey = proxy['reality-opts']?.['public-key']; @@ -159,6 +160,10 @@ export default function URI_Producer() { if (shortId) { sid = `&sid=${encodeURIComponent(shortId)}`; } + const spiderX = proxy['reality-opts']?.['_spider-x']; + if (spiderX) { + spx = `&spx=${encodeURIComponent(spiderX)}`; + } } else if (proxy.tls) { security = 'tls'; } @@ -189,8 +194,12 @@ export default function URI_Producer() { flow = `&flow=${encodeURIComponent(proxy.flow)}`; } let extra = ''; - if (proxy.extra) { - extra = `&extra=${encodeURIComponent(proxy.extra)}`; + if (proxy._extra) { + extra = `&extra=${encodeURIComponent(proxy._extra)}`; + } + let mode = ''; + if (proxy._mode) { + mode = `&mode=${encodeURIComponent(proxy._mode)}`; } let vlessType = proxy.network; if ( @@ -258,7 +267,7 @@ export default function URI_Producer() { proxy.port }?security=${encodeURIComponent( security, - )}${vlessTransport}${alpn}${allowInsecure}${sni}${fp}${flow}${sid}${pbk}${extra}#${encodeURIComponent( + )}${vlessTransport}${alpn}${allowInsecure}${sni}${fp}${flow}${sid}${spx}${pbk}${mode}${extra}#${encodeURIComponent( proxy.name, )}`; break; @@ -328,11 +337,41 @@ export default function URI_Producer() { : proxy.alpn.join(','), )}`; } + const trojanIsReality = proxy['reality-opts']; + let trojanSid = ''; + let trojanPbk = ''; + let trojanSpx = ''; + let trojanSecurity = ''; + let trojanMode = ''; + let trojanExtra = ''; + if (trojanIsReality) { + trojanSecurity = `&security=reality`; + const publicKey = proxy['reality-opts']?.['public-key']; + if (publicKey) { + trojanPbk = `&pbk=${encodeURIComponent(publicKey)}`; + } + const shortId = proxy['reality-opts']?.['short-id']; + if (shortId) { + trojanSid = `&sid=${encodeURIComponent(shortId)}`; + } + const spiderX = proxy['reality-opts']?.['_spider-x']; + if (spiderX) { + trojanSpx = `&spx=${encodeURIComponent(spiderX)}`; + } + if (proxy._extra) { + trojanExtra = `&extra=${encodeURIComponent( + proxy._extra, + )}`; + } + if (proxy._mode) { + trojanMode = `&mode=${encodeURIComponent(proxy._mode)}`; + } + } result = `trojan://${proxy.password}@${proxy.server}:${ proxy.port }?sni=${encodeURIComponent(proxy.sni || proxy.server)}${ proxy['skip-cert-verify'] ? '&allowInsecure=1' : '' - }${trojanTransport}${trojanAlpn}${trojanFp}#${encodeURIComponent( + }${trojanTransport}${trojanAlpn}${trojanFp}${trojanSecurity}${trojanSid}${trojanPbk}${trojanSpx}${trojanMode}${trojanExtra}#${encodeURIComponent( proxy.name, )}`; break;