Compare commits

...

9 Commits

Author SHA1 Message Date
xream
c5746f6a6b Fixed: fast-open tfo 2023-08-15 14:59:27 +08:00
xream
5cb226da62 feat: Added support for SS URI in other formats 2023-08-15 01:48:54 +08:00
xream
d229047744 Fixed: unsupported cipher for Clash/Stash 2023-08-14 10:04:47 +08:00
Hsiaoyi
cb21a8e6ec Merge pull request #229 from xream/feature/tuic
Adjust the logic for determining the tuic version
2023-08-13 17:03:40 +08:00
xream
537a00e8a9 Adjust the logic for determining the tuic version 2023-08-13 17:00:44 +08:00
Hsiaoyi
b770578cba Merge pull request #228 from xream/feature/tuic
feat: Added support for tuic and some compatibility adjustments
2023-08-13 15:56:52 +08:00
xream
47a95e5a3d feat: Added support for tuic and some compatibility adjustments 2023-08-13 15:54:04 +08:00
Hsiaoyi
e99f13d487 Merge pull request #227 from xream/feature/snell
feat: Added support for producing snell nodes with reuse and optional obfs
2023-07-31 18:44:53 +08:00
xream
fcab8401e0 feat: Added support for producing snell nodes with reuse and optional obfs 2023-07-31 18:41:48 +08:00
7 changed files with 173 additions and 13 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "sub-store",
"version": "2.14.3",
"version": "2.14.9",
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.",
"main": "src/main.js",
"scripts": {

View File

@@ -23,12 +23,19 @@ function URI_SS() {
};
content = content.split('#')[0]; // strip proxy name
// handle IPV4 and IPV6
const serverAndPort = content.match(/@([^/]*)(\/|$)/)[1];
let serverAndPortArray = content.match(/@([^/]*)(\/|$)/);
let userInfoStr = Base64.decode(content.split('@')[0]);
if (!serverAndPortArray) {
content = Base64.decode(content);
userInfoStr = content.split('@')[0];
serverAndPortArray = content.match(/@([^/]*)(\/|$)/);
}
const serverAndPort = serverAndPortArray[1];
const portIdx = serverAndPort.lastIndexOf(':');
proxy.server = serverAndPort.substring(0, portIdx);
proxy.port = serverAndPort.substring(portIdx + 1);
const userInfo = Base64.decode(content.split('@')[0]).split(':');
const userInfo = userInfoStr.split(':');
proxy.cipher = userInfo[0];
proxy.password = userInfo[1];
@@ -270,6 +277,7 @@ function Clash_All() {
'http',
'snell',
'trojan',
'tuic',
].includes(proxy.type)
) {
throw new Error(
@@ -474,6 +482,15 @@ function Surge_Snell() {
return { name, test, parse };
}
function Surge_Tuic() {
const name = 'Surge Tuic Parser';
const test = (line) => {
return /^.*=\s*tuic(-v5)??/.test(line.split(',')[0]);
};
const parse = (line) => getSurgeParser().parse(line);
return { name, test, parse };
}
export default [
URI_SS(),
URI_SSR(),
@@ -485,6 +502,7 @@ export default [
Surge_Trojan(),
Surge_Http(),
Surge_Snell(),
Surge_Tuic(),
Surge_Socks5(),
Loon_SS(),
Loon_SSR(),

View File

@@ -29,7 +29,7 @@ const grammars = String.raw`
}
}
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls) {
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls/tuic/tuic_v5) {
return proxy;
}
@@ -73,6 +73,13 @@ snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_
$set(proxy, "obfs-opts.path", obfs.path);
}
}
tuic = tag equals "tuic" address (alpn/token/ip_version/tls_verification/sni/fast_open/tfo/others)* {
proxy.type = "tuic";
}
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/tls_verification/sni/fast_open/tfo/others)* {
proxy.type = "tuic";
proxy.version = 5;
}
socks5 = tag equals "socks5" address (username password)? (fast_open/others)* {
proxy.type = "socks5";
}
@@ -175,6 +182,11 @@ uri = $[^,]+
udp_relay = comma "udp" equals flag:bool { proxy.udp = flag; }
fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; }
tfo = comma "tfo" equals flag:bool { proxy.tfo = flag; }
ip_version = comma "ip-version" equals match:[^,]+ { proxy["ip-version"] = match.join(""); }
token = comma "token" equals match:[^,]+ { proxy.token = match.join(""); }
alpn = comma "alpn" equals match:[^,]+ { proxy.alpn = match.join(""); }
uuidk = comma "uuid" equals match:[^,]+ { proxy.uuid = match.join(""); }
tag = match:[^=,]* { proxy.name = match.join("").trim(); }
comma = _ "," _

View File

@@ -27,7 +27,7 @@
}
}
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls) {
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls/tuic/tuic_v5) {
return proxy;
}
@@ -71,6 +71,13 @@ snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_
$set(proxy, "obfs-opts.path", obfs.path);
}
}
tuic = tag equals "tuic" address (alpn/token/ip_version/tls_verification/sni/fast_open/tfo/others)* {
proxy.type = "tuic";
}
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/tls_verification/sni/fast_open/tfo/others)* {
proxy.type = "tuic";
proxy.version = 5;
}
socks5 = tag equals "socks5" address (username password)? (fast_open/others)* {
proxy.type = "socks5";
}
@@ -173,6 +180,11 @@ uri = $[^,]+
udp_relay = comma "udp" equals flag:bool { proxy.udp = flag; }
fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; }
tfo = comma "tfo" equals flag:bool { proxy.tfo = flag; }
ip_version = comma "ip-version" equals match:[^,]+ { proxy["ip-version"] = match.join(""); }
token = comma "token" equals match:[^,]+ { proxy.token = match.join(""); }
alpn = comma "alpn" equals match:[^,]+ { proxy.alpn = match.join(""); }
uuidk = comma "uuid" equals match:[^,]+ { proxy.uuid = match.join(""); }
tag = match:[^=,]* { proxy.name = match.join("").trim(); }
comma = _ "," _

View File

@@ -4,11 +4,27 @@ export default function Clash_Producer() {
const type = 'ALL';
const produce = (proxies) => {
// filter unsupported proxies
proxies = proxies.filter((proxy) =>
['ss', 'ssr', 'vmess', 'socks', 'http', 'snell', 'trojan'].includes(
proxy.type,
),
);
proxies = proxies.filter((proxy) => {
if (
![
'ss',
'ssr',
'vmess',
'socks',
'http',
'snell',
'trojan',
].includes(proxy.type)
) {
return false;
} else if (
proxy.type === 'snell' &&
String(proxy.version) === '4'
) {
return false;
}
return true;
});
return (
'proxies:\n' +
proxies
@@ -25,6 +41,18 @@ export default function Clash_Producer() {
proxy.servername = proxy.sni;
delete proxy.sni;
}
// https://dreamacro.github.io/clash/configuration/outbound.html#vmess
if (
isPresent(proxy, 'cipher') &&
![
'auto',
'aes-128-gcm',
'chacha20-poly1305',
'none',
].includes(proxy.cipher)
) {
proxy.cipher = 'auto';
}
}
delete proxy['tls-fingerprint'];

View File

@@ -6,6 +6,15 @@ export default function Stash_Producer() {
return (
'proxies:\n' +
proxies
.filter((proxy) => {
if (
proxy.type === 'snell' &&
String(proxy.version) === '4'
) {
return false;
}
return true;
})
.map((proxy) => {
if (proxy.type === 'vmess') {
// handle vmess aead
@@ -19,6 +28,34 @@ export default function Stash_Producer() {
proxy.servername = proxy.sni;
delete proxy.sni;
}
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml#L400
// https://stash.wiki/proxy-protocols/proxy-types#vmess
if (
isPresent(proxy, 'cipher') &&
![
'auto',
'aes-128-gcm',
'chacha20-poly1305',
'none',
].includes(proxy.cipher)
) {
proxy.cipher = 'auto';
}
} else if (proxy.type === 'tuic') {
if (isPresent(proxy, 'alpn')) {
proxy.alpn = Array.isArray(proxy.alpn)
? proxy.alpn
: [proxy.alpn];
} else {
proxy.alpn = ['h3'];
}
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/adapter/outbound/tuic.go#L197
if (
(!proxy.token || proxy.token.length === 0) &&
!isPresent(proxy, 'version')
) {
proxy.version = 5;
}
}
delete proxy['tls-fingerprint'];

View File

@@ -4,6 +4,14 @@ import $ from '@/core/app';
const targetPlatform = 'Surge';
const ipVersions = {
dual: 'dual',
ipv4: 'v4-only',
ipv6: 'v6-only',
'ipv4-prefer': 'prefer-v4',
'ipv6-prefer': 'prefer-v6',
};
export default function Surge_Producer() {
const produce = (proxy) => {
switch (proxy.type) {
@@ -19,6 +27,8 @@ export default function Surge_Producer() {
return socks5(proxy);
case 'snell':
return snell(proxy);
case 'tuic':
return tuic(proxy);
}
throw new Error(
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`,
@@ -215,15 +225,15 @@ function snell(proxy) {
// obfs
result.appendIfPresent(
`,obfs=${proxy['obfs-opts'].mode}`,
`,obfs=${proxy['obfs-opts']?.mode}`,
'obfs-opts.mode',
);
result.appendIfPresent(
`,obfs-host=${proxy['obfs-opts'].host}`,
`,obfs-host=${proxy['obfs-opts']?.host}`,
'obfs-opts.host',
);
result.appendIfPresent(
`,obfs-uri=${proxy['obfs-opts'].path}`,
`,obfs-uri=${proxy['obfs-opts']?.path}`,
'obfs-opts.path',
);
@@ -233,6 +243,49 @@ function snell(proxy) {
// test-url
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
// reuse
result.appendIfPresent(`,reuse=${proxy['reuse']}`, 'reuse');
return result.toString();
}
function tuic(proxy) {
const result = new Result(proxy);
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/adapter/outbound/tuic.go#L197
let type = proxy.type;
if (!proxy.token || proxy.token.length === 0) {
type = 'tuic-v5';
}
result.append(`${proxy.name}=${type},${proxy.server},${proxy.port}`);
result.appendIfPresent(`,uuid=${proxy.uuid}`, 'uuid');
result.appendIfPresent(`,password=${proxy.password}`, 'password');
result.appendIfPresent(`,token=${proxy.token}`, 'token');
result.appendIfPresent(
`,alpn=${Array.isArray(proxy.alpn) ? proxy.alpn[0] : proxy.alpn}`,
'alpn',
);
result.appendIfPresent(
`,ip-version=${ipVersions[proxy['ip-version']] || proxy['ip-version']}`,
'ip-version',
);
// tls verification
result.appendIfPresent(`,sni=${proxy.sni}`, 'sni');
result.appendIfPresent(
`,skip-cert-verify=${proxy['skip-cert-verify']}`,
'skip-cert-verify',
);
// tfo
result.appendIfPresent(`,tfo=${proxy['fast-open']}`, 'fast-open');
result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo');
// test-url
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
return result.toString();
}