mirror of
https://git.mirrors.martin98.com/https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-14 00:15:58 +08:00
feat: Surge Hysteria2 与 TUIC 协议支持端口跳跃; Hysteria2 URI 的端口部分支持 端口跳跃 的「多端口地址格式」
This commit is contained in:
parent
562d349629
commit
59fe16a7b0
@ -98,7 +98,7 @@ or
|
|||||||
esbuild(experimental)
|
esbuild(experimental)
|
||||||
|
|
||||||
```
|
```
|
||||||
pnpm run --parallel "/^dev:.*/"
|
SUB_STORE_BACKEND_API_PORT=3000 pnpm run --parallel "/^dev:.*/"
|
||||||
```
|
```
|
||||||
|
|
||||||
## LICENSE
|
## LICENSE
|
||||||
@ -111,7 +111,6 @@ This project is under the GPL V3 LICENSE.
|
|||||||
|
|
||||||
[](https://star-history.com/#sub-store-org/sub-store&Date)
|
[](https://star-history.com/#sub-store-org/sub-store&Date)
|
||||||
|
|
||||||
|
|
||||||
## Acknowledgements
|
## Acknowledgements
|
||||||
|
|
||||||
- Special thanks to @KOP-XIAO for his awesome resource-parser. Please give a [star](https://github.com/KOP-XIAO/QuantumultX) for his great work!
|
- Special thanks to @KOP-XIAO for his awesome resource-parser. Please give a [star](https://github.com/KOP-XIAO/QuantumultX) for his great work!
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sub-store",
|
"name": "sub-store",
|
||||||
"version": "2.14.368",
|
"version": "2.14.370",
|
||||||
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.",
|
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.",
|
||||||
"main": "src/main.js",
|
"main": "src/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -424,9 +424,13 @@ function lastParse(proxy) {
|
|||||||
proxy[`${proxy.network}-opts`].path = [transportPath];
|
proxy[`${proxy.network}-opts`].path = [transportPath];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (['hysteria', 'hysteria2'].includes(proxy.type) && !proxy.ports) {
|
if (['hysteria', 'hysteria2'].includes(proxy.type)) {
|
||||||
|
if (proxy.ports) {
|
||||||
|
proxy.ports = proxy.ports.replace(/\//g, ',');
|
||||||
|
} else {
|
||||||
delete proxy.ports;
|
delete proxy.ports;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
['hysteria2'].includes(proxy.type) &&
|
['hysteria2'].includes(proxy.type) &&
|
||||||
proxy.obfs &&
|
proxy.obfs &&
|
||||||
|
@ -5,6 +5,7 @@ import {
|
|||||||
isPresent,
|
isPresent,
|
||||||
isNotBlank,
|
isNotBlank,
|
||||||
getIfPresent,
|
getIfPresent,
|
||||||
|
getRandomPort,
|
||||||
} from '@/utils';
|
} from '@/utils';
|
||||||
import getSurgeParser from './peggy/surge';
|
import getSurgeParser from './peggy/surge';
|
||||||
import getLoonParser from './peggy/loon';
|
import getLoonParser from './peggy/loon';
|
||||||
@ -13,6 +14,19 @@ import getTrojanURIParser from './peggy/trojan-uri';
|
|||||||
|
|
||||||
import { Base64 } from 'js-base64';
|
import { Base64 } from 'js-base64';
|
||||||
|
|
||||||
|
function surge_port_hopping(raw) {
|
||||||
|
const [parts, port_hopping] =
|
||||||
|
raw.match(
|
||||||
|
/,\s*?port-hopping\s*?=\s*?["']?\s*?((\d+(-\d+)?)([,;]\d+(-\d+)?)*)\s*?["']?\s*?/,
|
||||||
|
) || [];
|
||||||
|
return {
|
||||||
|
port_hopping: port_hopping
|
||||||
|
? port_hopping.replace(/;/g, ',')
|
||||||
|
: undefined,
|
||||||
|
line: parts ? raw.replace(parts, '') : raw,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Parse SS URI format (only supports new SIP002, legacy format is depreciated).
|
// Parse SS URI format (only supports new SIP002, legacy format is depreciated).
|
||||||
// reference: https://github.com/shadowsocks/shadowsocks-org/wiki/SIP002-URI-Scheme
|
// reference: https://github.com/shadowsocks/shadowsocks-org/wiki/SIP002-URI-Scheme
|
||||||
function URI_SS() {
|
function URI_SS() {
|
||||||
@ -545,13 +559,42 @@ function URI_Hysteria2() {
|
|||||||
};
|
};
|
||||||
const parse = (line) => {
|
const parse = (line) => {
|
||||||
line = line.split(/(hysteria2|hy2):\/\//)[2];
|
line = line.split(/(hysteria2|hy2):\/\//)[2];
|
||||||
// eslint-disable-next-line no-unused-vars
|
// 端口跳跃有两种写法:
|
||||||
let [__, password, server, ___, port, ____, addons = '', name] =
|
// 1. 服务器的地址和可选端口。如果省略端口,则默认为 443。
|
||||||
/^(.*?)@(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line);
|
// 端口部分支持 端口跳跃 的「多端口地址格式」。
|
||||||
|
// https://hysteria.network/zh/docs/advanced/Port-Hopping
|
||||||
|
// 2. 参数 mport
|
||||||
|
let ports;
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
let [
|
||||||
|
__,
|
||||||
|
password,
|
||||||
|
server,
|
||||||
|
___,
|
||||||
|
port,
|
||||||
|
____,
|
||||||
|
_____,
|
||||||
|
______,
|
||||||
|
_______,
|
||||||
|
________,
|
||||||
|
addons = '',
|
||||||
|
name,
|
||||||
|
] = /^(.*?)@(.*?)(:((\d+(-\d+)?)([,;]\d+(-\d+)?)*))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(
|
||||||
|
line,
|
||||||
|
);
|
||||||
|
/* eslint-enable no-unused-vars */
|
||||||
|
if (/^\d+$/.test(port)) {
|
||||||
port = parseInt(`${port}`, 10);
|
port = parseInt(`${port}`, 10);
|
||||||
if (isNaN(port)) {
|
if (isNaN(port)) {
|
||||||
port = 443;
|
port = 443;
|
||||||
}
|
}
|
||||||
|
} else if (port) {
|
||||||
|
ports = port;
|
||||||
|
port = getRandomPort(ports);
|
||||||
|
} else {
|
||||||
|
port = 443;
|
||||||
|
}
|
||||||
|
|
||||||
password = decodeURIComponent(password);
|
password = decodeURIComponent(password);
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
name = decodeURIComponent(name);
|
name = decodeURIComponent(name);
|
||||||
@ -563,6 +606,7 @@ function URI_Hysteria2() {
|
|||||||
name,
|
name,
|
||||||
server,
|
server,
|
||||||
port,
|
port,
|
||||||
|
ports,
|
||||||
password,
|
password,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1295,7 +1339,12 @@ function Surge_Tuic() {
|
|||||||
const test = (line) => {
|
const test = (line) => {
|
||||||
return /^.*=\s*tuic(-v5)?/.test(line.split(',')[0]);
|
return /^.*=\s*tuic(-v5)?/.test(line.split(',')[0]);
|
||||||
};
|
};
|
||||||
const parse = (line) => getSurgeParser().parse(line);
|
const parse = (raw) => {
|
||||||
|
const { port_hopping, line } = surge_port_hopping(raw);
|
||||||
|
const proxy = getSurgeParser().parse(line);
|
||||||
|
proxy['ports'] = port_hopping;
|
||||||
|
return proxy;
|
||||||
|
};
|
||||||
return { name, test, parse };
|
return { name, test, parse };
|
||||||
}
|
}
|
||||||
function Surge_WireGuard() {
|
function Surge_WireGuard() {
|
||||||
@ -1312,7 +1361,12 @@ function Surge_Hysteria2() {
|
|||||||
const test = (line) => {
|
const test = (line) => {
|
||||||
return /^.*=\s*hysteria2/.test(line.split(',')[0]);
|
return /^.*=\s*hysteria2/.test(line.split(',')[0]);
|
||||||
};
|
};
|
||||||
const parse = (line) => getSurgeParser().parse(line);
|
const parse = (raw) => {
|
||||||
|
const { port_hopping, line } = surge_port_hopping(raw);
|
||||||
|
const proxy = getSurgeParser().parse(line);
|
||||||
|
proxy['ports'] = port_hopping;
|
||||||
|
return proxy;
|
||||||
|
};
|
||||||
return { name, test, parse };
|
return { name, test, parse };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,11 +91,11 @@ snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_
|
|||||||
}
|
}
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
tuic = tag equals "tuic" address (alpn/token/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
tuic = tag equals "tuic" address (alpn/token/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/port_hopping_interval/others)* {
|
||||||
proxy.type = "tuic";
|
proxy.type = "tuic";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/port_hopping_interval/others)* {
|
||||||
proxy.type = "tuic";
|
proxy.type = "tuic";
|
||||||
proxy.version = 5;
|
proxy.version = 5;
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
@ -104,7 +104,7 @@ wireguard = tag equals "wireguard" (section_name/no_error_alert/ip_version/under
|
|||||||
proxy.type = "wireguard-surge";
|
proxy.type = "wireguard-surge";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
hysteria2 = tag equals "hysteria2" address (no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/sni/tls_verification/passwordk/tls_fingerprint/download_bandwidth/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
hysteria2 = tag equals "hysteria2" address (no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/sni/tls_verification/passwordk/tls_fingerprint/download_bandwidth/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/port_hopping_interval/others)* {
|
||||||
proxy.type = "hysteria2";
|
proxy.type = "hysteria2";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
@ -151,6 +151,8 @@ port = digits:[0-9]+ {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
port_hopping_interval = comma "port-hopping-interval" equals match:$[0-9]+ { proxy["hop-interval"] = parseInt(match.trim()); }
|
||||||
|
|
||||||
username = & {
|
username = & {
|
||||||
let j = peg$currPos;
|
let j = peg$currPos;
|
||||||
let start, end;
|
let start, end;
|
||||||
|
@ -89,11 +89,11 @@ snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_
|
|||||||
}
|
}
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
tuic = tag equals "tuic" address (alpn/token/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
tuic = tag equals "tuic" address (alpn/token/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/port_hopping_interval/others)* {
|
||||||
proxy.type = "tuic";
|
proxy.type = "tuic";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls_fingerprint/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/port_hopping_interval/others)* {
|
||||||
proxy.type = "tuic";
|
proxy.type = "tuic";
|
||||||
proxy.version = 5;
|
proxy.version = 5;
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
@ -102,7 +102,7 @@ wireguard = tag equals "wireguard" (section_name/no_error_alert/ip_version/under
|
|||||||
proxy.type = "wireguard-surge";
|
proxy.type = "wireguard-surge";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
hysteria2 = tag equals "hysteria2" address (no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/sni/tls_verification/passwordk/tls_fingerprint/download_bandwidth/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
hysteria2 = tag equals "hysteria2" address (no_error_alert/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/sni/tls_verification/passwordk/tls_fingerprint/download_bandwidth/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/port_hopping_interval/others)* {
|
||||||
proxy.type = "hysteria2";
|
proxy.type = "hysteria2";
|
||||||
handleShadowTLS();
|
handleShadowTLS();
|
||||||
}
|
}
|
||||||
@ -149,6 +149,8 @@ port = digits:[0-9]+ {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
port_hopping_interval = comma "port-hopping-interval" equals match:$[0-9]+ { proxy["hop-interval"] = parseInt(match.trim()); }
|
||||||
|
|
||||||
username = & {
|
username = & {
|
||||||
let j = peg$currPos;
|
let j = peg$currPos;
|
||||||
let start, end;
|
let start, end;
|
||||||
|
@ -675,6 +675,15 @@ function tuic(proxy) {
|
|||||||
'alpn',
|
'alpn',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (isPresent(proxy, 'ports')) {
|
||||||
|
result.append(`,port-hopping=${proxy.ports.replace(/,/g, ';')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,port-hopping-interval=${proxy['hop-interval']}`,
|
||||||
|
'hop-interval',
|
||||||
|
);
|
||||||
|
|
||||||
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||||
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
||||||
|
|
||||||
@ -935,6 +944,15 @@ function hysteria2(proxy) {
|
|||||||
|
|
||||||
result.appendIfPresent(`,password=${proxy.password}`, 'password');
|
result.appendIfPresent(`,password=${proxy.password}`, 'password');
|
||||||
|
|
||||||
|
if (isPresent(proxy, 'ports')) {
|
||||||
|
result.append(`,port-hopping=${proxy.ports.replace(/,/g, ';')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,port-hopping-interval=${proxy['hop-interval']}`,
|
||||||
|
'hop-interval',
|
||||||
|
);
|
||||||
|
|
||||||
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||||
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user