Reworked Surge producer

This commit is contained in:
Peng-YM 2022-06-17 22:11:55 +08:00
parent 0da236fbb1
commit c12ff37f68
11 changed files with 345 additions and 150 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "sub-store", "name": "sub-store",
"version": "2.0.5", "version": "2.0.6",
"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": {

View File

@ -43,13 +43,13 @@ start = (trojan/shadowsocks/vmess/http/socks5) {
} }
trojan = "trojan" equals address trojan = "trojan" equals address
(password/over_tls/tls_host/tls_verification/obfs/obfs_host/obfs_uri/tag/udp_relay/udp_over_tcp/fast_open/others)* { (password/over_tls/tls_host/tls_fingerprint/tls_verification/obfs/obfs_host/obfs_uri/tag/udp_relay/udp_over_tcp/fast_open/others)* {
proxy.type = "trojan"; proxy.type = "trojan";
handleObfs(); handleObfs();
} }
shadowsocks = "shadowsocks" equals address shadowsocks = "shadowsocks" equals address
(password/method/obfs_ssr/obfs_ss/obfs_host/obfs_uri/ssr_protocol/ssr_protocol_param/tls_verification/udp_relay/udp_over_tcp/fast_open/tag/others)* { (password/method/obfs_ssr/obfs_ss/obfs_host/obfs_uri/ssr_protocol/ssr_protocol_param/tls_fingerprint/tls_verification/udp_relay/udp_over_tcp/fast_open/tag/others)* {
if (proxy.protocol) { if (proxy.protocol) {
proxy.type = "ssr"; proxy.type = "ssr";
// handle ssr obfs // handle ssr obfs
@ -80,19 +80,19 @@ shadowsocks = "shadowsocks" equals address
} }
vmess = "vmess" equals address vmess = "vmess" equals address
(uuid/method/over_tls/tls_host/tls_verification/tag/obfs/obfs_host/obfs_uri/udp_relay/udp_over_tcp/fast_open/aead/others)* { (uuid/method/over_tls/tls_host/tls_fingerprint/tls_verification/tag/obfs/obfs_host/obfs_uri/udp_relay/udp_over_tcp/fast_open/aead/others)* {
proxy.type = "vmess"; proxy.type = "vmess";
proxy.cipher = proxy.cipher || "auto"; proxy.cipher = proxy.cipher || "auto";
handleObfs(); handleObfs();
} }
http = "http" equals address http = "http" equals address
(username/password/over_tls/tls_host/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/others)*{ (username/password/over_tls/tls_host/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/others)*{
proxy.type = "http"; proxy.type = "http";
} }
socks5 = "socks5" equals address socks5 = "socks5" equals address
(username/password/password/over_tls/tls_host/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/others)* { (username/password/password/over_tls/tls_host/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/others)* {
proxy.type = "socks5"; proxy.type = "socks5";
} }
@ -150,8 +150,9 @@ tls_host = comma "tls-host" equals sni:domain { proxy.sni = sni; }
tls_verification = comma "tls-verification" equals flag:bool { tls_verification = comma "tls-verification" equals flag:bool {
proxy["skip-cert-verify"] = !flag; proxy["skip-cert-verify"] = !flag;
} }
tls_fingerprint = comma "tls-cert-sha256" equals tls_fingerprint:[^,] { proxy["tls-fingerprint"] = tls_fingerprint; }
obfs_ss = comma "obfs" equals type:("http"/"tls"/"wss"/"ws") { obfs.type = type; return type; } obfs_ss = comma "obfs" equals type:("http"/"tls"/"wss"/"ws"/"over-tls") { obfs.type = type; return type; }
obfs_ssr = comma "obfs" equals type:("plain"/"http_simple"/"http_post"/"random_head"/"tls1.2_ticket_auth"/"tls1.2_ticket_fastauth") { obfs.type = type; return type; } obfs_ssr = comma "obfs" equals type:("plain"/"http_simple"/"http_post"/"random_head"/"tls1.2_ticket_auth"/"tls1.2_ticket_fastauth") { obfs.type = type; return type; }
obfs = comma "obfs" equals type:("wss"/"ws"/"over-tls"/"http") { obfs.type = type; return type; }; obfs = comma "obfs" equals type:("wss"/"ws"/"over-tls"/"http") { obfs.type = type; return type; };

View File

@ -41,13 +41,13 @@ start = (trojan/shadowsocks/vmess/http/socks5) {
} }
trojan = "trojan" equals address trojan = "trojan" equals address
(password/over_tls/tls_host/tls_verification/obfs/obfs_host/obfs_uri/tag/udp_relay/udp_over_tcp/fast_open/others)* { (password/over_tls/tls_host/tls_fingerprint/tls_verification/obfs/obfs_host/obfs_uri/tag/udp_relay/udp_over_tcp/fast_open/others)* {
proxy.type = "trojan"; proxy.type = "trojan";
handleObfs(); handleObfs();
} }
shadowsocks = "shadowsocks" equals address shadowsocks = "shadowsocks" equals address
(password/method/obfs_ssr/obfs_ss/obfs_host/obfs_uri/ssr_protocol/ssr_protocol_param/tls_verification/udp_relay/udp_over_tcp/fast_open/tag/others)* { (password/method/obfs_ssr/obfs_ss/obfs_host/obfs_uri/ssr_protocol/ssr_protocol_param/tls_fingerprint/tls_verification/udp_relay/udp_over_tcp/fast_open/tag/others)* {
if (proxy.protocol) { if (proxy.protocol) {
proxy.type = "ssr"; proxy.type = "ssr";
// handle ssr obfs // handle ssr obfs
@ -78,19 +78,19 @@ shadowsocks = "shadowsocks" equals address
} }
vmess = "vmess" equals address vmess = "vmess" equals address
(uuid/method/over_tls/tls_host/tls_verification/tag/obfs/obfs_host/obfs_uri/udp_relay/udp_over_tcp/fast_open/aead/others)* { (uuid/method/over_tls/tls_host/tls_fingerprint/tls_verification/tag/obfs/obfs_host/obfs_uri/udp_relay/udp_over_tcp/fast_open/aead/others)* {
proxy.type = "vmess"; proxy.type = "vmess";
proxy.cipher = proxy.cipher || "auto"; proxy.cipher = proxy.cipher || "auto";
handleObfs(); handleObfs();
} }
http = "http" equals address http = "http" equals address
(username/password/over_tls/tls_host/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/others)*{ (username/password/over_tls/tls_host/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/others)*{
proxy.type = "http"; proxy.type = "http";
} }
socks5 = "socks5" equals address socks5 = "socks5" equals address
(username/password/password/over_tls/tls_host/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/others)* { (username/password/password/over_tls/tls_host/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/others)* {
proxy.type = "socks5"; proxy.type = "socks5";
} }
@ -148,8 +148,9 @@ tls_host = comma "tls-host" equals sni:domain { proxy.sni = sni; }
tls_verification = comma "tls-verification" equals flag:bool { tls_verification = comma "tls-verification" equals flag:bool {
proxy["skip-cert-verify"] = !flag; proxy["skip-cert-verify"] = !flag;
} }
tls_fingerprint = comma "tls-cert-sha256" equals tls_fingerprint:[^,] { proxy["tls-fingerprint"] = tls_fingerprint; }
obfs_ss = comma "obfs" equals type:("http"/"tls"/"wss"/"ws") { obfs.type = type; return type; } obfs_ss = comma "obfs" equals type:("http"/"tls"/"wss"/"ws"/"over-tls") { obfs.type = type; return type; }
obfs_ssr = comma "obfs" equals type:("plain"/"http_simple"/"http_post"/"random_head"/"tls1.2_ticket_auth"/"tls1.2_ticket_fastauth") { obfs.type = type; return type; } obfs_ssr = comma "obfs" equals type:("plain"/"http_simple"/"http_post"/"random_head"/"tls1.2_ticket_auth"/"tls1.2_ticket_fastauth") { obfs.type = type; return type; }
obfs = comma "obfs" equals type:("wss"/"ws"/"over-tls"/"http") { obfs.type = type; return type; }; obfs = comma "obfs" equals type:("wss"/"ws"/"over-tls"/"http") { obfs.type = type; return type; };

View File

@ -43,16 +43,16 @@ shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/
$set(proxy, "plugin-opts.path", obfs.path); $set(proxy, "plugin-opts.path", obfs.path);
} }
} }
vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/method/tls/sni/tls_verification/fast_open/udp_relay/others)* { vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/method/tls/sni/tls_fingerprint/tls_verification/fast_open/udp_relay/others)* {
proxy.type = "vmess"; proxy.type = "vmess";
proxy.cipher = proxy.cipher || "auto"; proxy.cipher = proxy.cipher || "auto";
handleWebsocket(); handleWebsocket();
} }
trojan = tag equals "trojan" address (passwordk/ws/ws_path/ws_headers/tls/sni/tls_verification/fast_open/udp_relay/others)* { trojan = tag equals "trojan" address (passwordk/ws/ws_path/ws_headers/tls/sni/tls_fingerprint/tls_verification/fast_open/udp_relay/others)* {
proxy.type = "trojan"; proxy.type = "trojan";
handleWebsocket(); handleWebsocket();
} }
https = tag equals "https" address (username password)? (sni/tls_verification/fast_open/others)* { https = tag equals "https" address (username password)? (sni/tls_fingerprint/tls_verification/fast_open/others)* {
proxy.type = "http"; proxy.type = "http";
proxy.tls = true; proxy.tls = true;
} }
@ -71,7 +71,7 @@ snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_
socks5 = tag equals "socks5" address (username password)? (fast_open/others)* { socks5 = tag equals "socks5" address (username password)? (fast_open/others)* {
proxy.type = "socks5"; proxy.type = "socks5";
} }
socks5_tls = tag equals "socks5-tls" address (username password)? (sni/tls_verification/fast_open/others)* { socks5_tls = tag equals "socks5-tls" address (username password)? (sni/tls_fingerprint/tls_verification/fast_open/others)* {
proxy.type = "socks5"; proxy.type = "socks5";
proxy.tls = true; proxy.tls = true;
} }
@ -137,6 +137,7 @@ password = comma match:[^,]+ { proxy.password = match.join(""); }
tls = comma "tls" equals flag:bool { proxy.tls = flag; } tls = comma "tls" equals flag:bool { proxy.tls = flag; }
sni = comma "sni" equals sni:domain { proxy.sni = sni; } sni = comma "sni" equals sni:domain { proxy.sni = sni; }
tls_verification = comma "skip-cert-verify" equals flag:bool { proxy["skip-cert-verify"] = flag; } tls_verification = comma "skip-cert-verify" equals flag:bool { proxy["skip-cert-verify"] = flag; }
tls_fingerprint = comma "server-cert-fingerprint-sha256" equals tls_fingerprint:[^,] { proxy["tls-fingerprint"] = tls_fingerprint; }
snell_psk = comma "psk" equals match:[^,]+ { proxy.psk = match.join(""); } snell_psk = comma "psk" equals match:[^,]+ { proxy.psk = match.join(""); }
snell_version = comma "version" equals match:$[0-9]+ { proxy.version = parseInt(match.trim()); } snell_version = comma "version" equals match:$[0-9]+ { proxy.version = parseInt(match.trim()); }

View File

@ -41,16 +41,16 @@ shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/
$set(proxy, "plugin-opts.path", obfs.path); $set(proxy, "plugin-opts.path", obfs.path);
} }
} }
vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/method/tls/sni/tls_verification/fast_open/udp_relay/others)* { vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/method/tls/sni/tls_fingerprint/tls_verification/fast_open/udp_relay/others)* {
proxy.type = "vmess"; proxy.type = "vmess";
proxy.cipher = proxy.cipher || "auto"; proxy.cipher = proxy.cipher || "auto";
handleWebsocket(); handleWebsocket();
} }
trojan = tag equals "trojan" address (passwordk/ws/ws_path/ws_headers/tls/sni/tls_verification/fast_open/udp_relay/others)* { trojan = tag equals "trojan" address (passwordk/ws/ws_path/ws_headers/tls/sni/tls_fingerprint/tls_verification/fast_open/udp_relay/others)* {
proxy.type = "trojan"; proxy.type = "trojan";
handleWebsocket(); handleWebsocket();
} }
https = tag equals "https" address (username password)? (sni/tls_verification/fast_open/others)* { https = tag equals "https" address (username password)? (sni/tls_fingerprint/tls_verification/fast_open/others)* {
proxy.type = "http"; proxy.type = "http";
proxy.tls = true; proxy.tls = true;
} }
@ -69,7 +69,7 @@ snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_
socks5 = tag equals "socks5" address (username password)? (fast_open/others)* { socks5 = tag equals "socks5" address (username password)? (fast_open/others)* {
proxy.type = "socks5"; proxy.type = "socks5";
} }
socks5_tls = tag equals "socks5-tls" address (username password)? (sni/tls_verification/fast_open/others)* { socks5_tls = tag equals "socks5-tls" address (username password)? (sni/tls_fingerprint/tls_verification/fast_open/others)* {
proxy.type = "socks5"; proxy.type = "socks5";
proxy.tls = true; proxy.tls = true;
} }
@ -135,6 +135,7 @@ password = comma match:[^,]+ { proxy.password = match.join(""); }
tls = comma "tls" equals flag:bool { proxy.tls = flag; } tls = comma "tls" equals flag:bool { proxy.tls = flag; }
sni = comma "sni" equals sni:domain { proxy.sni = sni; } sni = comma "sni" equals sni:domain { proxy.sni = sni; }
tls_verification = comma "skip-cert-verify" equals flag:bool { proxy["skip-cert-verify"] = flag; } tls_verification = comma "skip-cert-verify" equals flag:bool { proxy["skip-cert-verify"] = flag; }
tls_fingerprint = comma "server-cert-fingerprint-sha256" equals tls_fingerprint:[^,] { proxy["tls-fingerprint"] = tls_fingerprint; }
snell_psk = comma "psk" equals match:[^,]+ { proxy.psk = match.join(""); } snell_psk = comma "psk" equals match:[^,]+ { proxy.psk = match.join(""); }
snell_version = comma "version" equals match:$[0-9]+ { proxy.version = parseInt(match.trim()); } snell_version = comma "version" equals match:$[0-9]+ { proxy.version = parseInt(match.trim()); }

View File

@ -1,4 +1,4 @@
import { Result } from './utils'; import { isPresent, Result } from './utils';
const targetPlatform = 'QX'; const targetPlatform = 'QX';
export default function QX_Producer() { export default function QX_Producer() {
@ -34,7 +34,7 @@ function shadowsocks(proxy) {
append(`,password=${proxy.password}`); append(`,password=${proxy.password}`);
// obfs // obfs
if (proxy.plugin) { if (isPresent(proxy, 'plugin')) {
if (proxy.plugin === 'obfs') { if (proxy.plugin === 'obfs') {
const opts = proxy['plugin-opts']; const opts = proxy['plugin-opts'];
append(`,obfs=${opts.mode}`); append(`,obfs=${opts.mode}`);
@ -45,6 +45,8 @@ function shadowsocks(proxy) {
const opts = proxy['plugin-opts']; const opts = proxy['plugin-opts'];
if (opts.tls) append(`,obfs=wss`); if (opts.tls) append(`,obfs=wss`);
else append(`,obfs=ws`); else append(`,obfs=ws`);
} else {
throw new Error(`plugin is not supported`);
} }
appendIfPresent( appendIfPresent(
`,obfs-host=${proxy['plugin-opts'].host}`, `,obfs-host=${proxy['plugin-opts'].host}`,
@ -56,6 +58,12 @@ function shadowsocks(proxy) {
); );
} }
// tls fingerprint
appendIfPresent(
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
'tls-fingerprint',
);
// tls verification // tls verification
appendIfPresent( appendIfPresent(
`,tls-verification=${!proxy['skip-cert-verify']}`, `,tls-verification=${!proxy['skip-cert-verify']}`,
@ -116,19 +124,32 @@ function trojan(proxy) {
append(`,password=${proxy.password}`); append(`,password=${proxy.password}`);
// obfs ws // obfs ws
if (proxy.network === 'ws') { if (isPresent(proxy, 'network')) {
if (proxy.tls) append(`,obfs=wss`); if (proxy.network === 'ws') {
else append(`,obfs=ws`); if (proxy.tls) append(`,obfs=wss`);
appendIfPresent(`,obfs-uri=${proxy['ws-opts'].path}`, 'ws-opts.path'); else append(`,obfs=ws`);
appendIfPresent( appendIfPresent(
`,obfs-host=${proxy['ws-opts'].headers.Host}`, `,obfs-uri=${proxy['ws-opts'].path}`,
'ws-opts.headers.Host', 'ws-opts.path',
); );
appendIfPresent(
`,obfs-host=${proxy['ws-opts'].headers.Host}`,
'ws-opts.headers.Host',
);
} else {
throw new Error(`network ${proxy.network} is unsupported`);
}
} }
// tls // tls
appendIfPresent(`,over-tls=${proxy.tls}`, 'tls'); appendIfPresent(`,over-tls=${proxy.tls}`, 'tls');
// tls fingerprint
appendIfPresent(
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
'tls-fingerprint',
);
// tls verification // tls verification
appendIfPresent( appendIfPresent(
`,tls-verification=${!proxy['skip-cert-verify']}`, `,tls-verification=${!proxy['skip-cert-verify']}`,
@ -163,26 +184,39 @@ function vmess(proxy) {
append(`,password=${proxy.uuid}`); append(`,password=${proxy.uuid}`);
// obfs // obfs
if (proxy.network === 'ws') { if (isPresent(proxy, 'network')) {
if (proxy.tls) append(`,obfs=wss`); if (proxy.network === 'ws') {
else append(`,obfs=ws`); if (proxy.tls) append(`,obfs=wss`);
appendIfPresent(`,obfs-uri=${proxy['ws-opts'].path}`, 'ws-opts.path'); else append(`,obfs=ws`);
appendIfPresent( appendIfPresent(
`,obfs-host=${proxy['ws-opts'].headers.Host}`, `,obfs-uri=${proxy['ws-opts'].path}`,
'ws-opts.headers.Host', 'ws-opts.path',
); );
} else if (proxy.network === 'http') { appendIfPresent(
append(`,obfs=http`); `,obfs-host=${proxy['ws-opts'].headers.Host}`,
appendIfPresent( 'ws-opts.headers.Host',
`,obfs-uri=${proxy['http-opts'].path}`, );
'http-opts.path', } else if (proxy.network === 'http') {
); append(`,obfs=http`);
appendIfPresent( appendIfPresent(
`,obfs-host=${proxy['http-opts'].headers.Host}`, `,obfs-uri=${proxy['http-opts'].path}`,
'http-opts.headers.Host', 'http-opts.path',
); );
appendIfPresent(
`,obfs-host=${proxy['http-opts'].headers.Host}`,
'http-opts.headers.Host',
);
} else {
throw new Error(`network ${proxy.network} is unsupported`);
}
} }
// tls fingerprint
appendIfPresent(
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
'tls-fingerprint',
);
// tls verification // tls verification
appendIfPresent( appendIfPresent(
`,tls-verification=${!proxy['skip-cert-verify']}`, `,tls-verification=${!proxy['skip-cert-verify']}`,
@ -217,6 +251,12 @@ function http(proxy) {
// tls // tls
appendIfPresent(`,over-tls=${proxy.tls}`, 'tls'); appendIfPresent(`,over-tls=${proxy.tls}`, 'tls');
// tls fingerprint
appendIfPresent(
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
'tls-fingerprint',
);
// tls verification // tls verification
appendIfPresent( appendIfPresent(
`,tls-verification=${!proxy['skip-cert-verify']}`, `,tls-verification=${!proxy['skip-cert-verify']}`,
@ -248,6 +288,12 @@ function socks5(proxy) {
// tls // tls
appendIfPresent(`,over-tls=${proxy.tls}`, 'tls'); appendIfPresent(`,over-tls=${proxy.tls}`, 'tls');
// tls fingerprint
appendIfPresent(
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
'tls-fingerprint',
);
// tls verification // tls verification
appendIfPresent( appendIfPresent(
`,tls-verification=${!proxy['skip-cert-verify']}`, `,tls-verification=${!proxy['skip-cert-verify']}`,

View File

@ -1,98 +1,241 @@
/* eslint-disable no-case-declarations */ import { Result, isPresent } from './utils';
import $ from '@/core/app';
const targetPlatform = 'Surge';
export default function Surge_Producer() { export default function Surge_Producer() {
const targetPlatform = 'Surge';
const produce = (proxy) => { const produce = (proxy) => {
let result = '';
let obfs_opts, tls_opts;
switch (proxy.type) { switch (proxy.type) {
case 'ss': case 'ss':
obfs_opts = ''; return shadowsocks(proxy);
if (proxy.plugin) {
const { host, mode } = proxy['plugin-opts'];
if (proxy.plugin === 'obfs') {
obfs_opts = `,obfs=${mode}${
host ? ',obfs-host=' + host : ''
}`;
} else {
throw new Error(
`Platform ${targetPlatform} does not support obfs option: ${proxy.obfs}`,
);
}
}
result = `${proxy.name}=ss,${proxy.server}, ${
proxy.port
},encrypt-method=${proxy.cipher},password=${
proxy.password
}${obfs_opts},tfo=${proxy.tfo || 'false'},udp-relay=${
proxy.udp || 'false'
}`;
break;
case 'vmess':
tls_opts = '';
result = `${proxy.name}=vmess,${proxy.server},${
proxy.port
},username=${proxy.uuid},tls=${proxy.tls || 'false'},tfo=${
proxy.tfo || 'false'
}`;
if (proxy.alterId === 0) proxy['vmess-aead'] = true;
if (typeof proxy['vmess-aead'] !== 'undefined') {
result += `,vmess-aead=${proxy['vmess-aead']}`;
}
if (proxy.network === 'ws') {
const path = proxy['ws-opts'].path || '/';
const wsHeaders = Object.entries(proxy['ws-opts'].headers)
.map(([key, value]) => `${key}:"${value}"`)
.join('|');
result += `,ws=true${path ? ',ws-path=' + path : ''}${
wsHeaders ? ',ws-headers=' + wsHeaders : ''
}`;
}
if (proxy.tls) {
result += `${
typeof proxy['skip-cert-verify'] !== 'undefined'
? ',skip-cert-verify=' + proxy['skip-cert-verify']
: ''
}`;
result += proxy.sni ? `,sni=${proxy.sni}` : '';
}
break;
case 'trojan': case 'trojan':
result = `${proxy.name}=trojan,${proxy.server},${ return trojan(proxy);
proxy.port case 'vmess':
},password=${proxy.password}${ return vmess(proxy);
typeof proxy['skip-cert-verify'] !== 'undefined'
? ',skip-cert-verify=' + proxy['skip-cert-verify']
: ''
}${proxy.sni ? ',sni=' + proxy.sni : ''},tfo=${
proxy.tfo || 'false'
},udp-relay=${proxy.udp || 'false'}`;
break;
case 'http': case 'http':
if (proxy.tls) { return http(proxy);
tls_opts = `,skip-cert-verify=${proxy['skip-cert-verify']},sni=${proxy.sni}`; case 'socks5':
} return socks5(proxy);
result = `${proxy.name}=${proxy.tls ? 'https' : 'http'},${ case 'snell':
proxy.server return snell(proxy);
},${proxy.port}${
proxy.username ? ',username=' + proxy.username : ''
}${
proxy.password ? ',password=' + proxy.password : ''
}${tls_opts},tfo=${proxy.tfo || 'false'}`;
break;
default:
throw new Error(
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`,
);
} }
throw new Error(
// handle surge hybrid param `Platform ${targetPlatform} does not support proxy type: ${proxy.type}`,
result += );
proxy['surge-hybrid'] !== undefined
? `,hybrid=${proxy['surge-hybrid']}`
: '';
return result;
}; };
return { produce }; return { produce };
} }
function shadowsocks(proxy) {
const result = new Result(proxy);
result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`);
result.append(`,encrypt-method=${proxy.cipher}`);
result.appendIfPresent(`,password=${proxy.password}`, 'password');
// obfs
if (isPresent(proxy, 'plugin')) {
if (proxy.plugin === 'obfs') {
result.append(`,obfs=${proxy['plugin-opts']}`);
result.appendIfPresent(
`,obfs-host=${proxy['plugin-opts'].host}`,
'plugin-opts.host',
);
result.appendIfPresent(
`,obfs-uri=${proxy['plugin-opts'].path}`,
'plugin-opts.path',
);
} else {
throw new Error(`plugin ${proxy.plugin} is not supported`);
}
}
// tfo
result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo');
// udp
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
return result.toString();
}
function trojan(proxy) {
const result = new Result(proxy);
result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`);
result.appendIfPresent(`,password=${proxy.password}`, 'password');
if (isPresent(proxy, 'network')) {
if (proxy.network === 'ws') {
result.append(`,ws=true`);
result.appendIfPresent(
`,ws-path=${proxy['ws-opts'].path}`,
'ws-opts.path',
);
result.appendIfPresent(
`,ws-headers=Host:${proxy['ws-opts'].headers.Host}`,
'ws-opts.headers.Host',
);
} else {
throw new Error(`network ${proxy.network} is not supported`);
}
}
// tls
result.appendIfPresent(`,tls=${proxy.tls}`, 'tls');
// tls fingerprint
result.appendIfPresent(
`,server-cert-fingerprint-sha256=${proxy['tls-fingerprint']}`,
'tls-fingerprint',
);
// 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.tfo}`, 'tfo');
// udp
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
return result.toString();
}
function vmess(proxy) {
const result = new Result(proxy);
result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`);
result.appendIfPresent(`,username=${proxy.uuid}`, 'uuid');
if (proxy.cipher === 'auto') {
result.append(`,encrypt-method=none`);
} else {
result.append(`,encrypt-method=${proxy.cipher}`);
}
if (isPresent(proxy, 'network')) {
if (proxy.network === 'ws') {
result.append(`,ws=true`);
result.appendIfPresent(
`,ws-path=${proxy['ws-opts'].path}`,
'ws-opts.path',
);
result.appendIfPresent(
`,ws-headers=Host:${proxy['ws-opts'].headers.Host}`,
'ws-opts.headers.Host',
);
} else {
throw new Error(`network ${proxy.network} is unsupported`);
}
}
// AEAD
result.appendIfPresent(`,vmess-aead=${proxy.alterId === 0}`, 'alterId');
// tls fingerprint
result.appendIfPresent(
`,server-cert-fingerprint-sha256=${proxy['tls-fingerprint']}`,
'tls-fingerprint',
);
// tls
result.appendIfPresent(`,tls=${proxy.tls}`, 'tls');
// 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.tfo}`, 'tfo');
// udp
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
return result.toString();
}
function http(proxy) {
const result = new Result(proxy);
const type = proxy.tls ? 'https' : 'http';
result.append(`${proxy.name}=${type},${proxy.server},${proxy.port}`);
result.appendIfPresent(`,${proxy.username}`, 'username');
result.appendIfPresent(`,${proxy.password}`, 'password');
// tls fingerprint
result.appendIfPresent(
`,server-cert-fingerprint-sha256=${proxy['tls-fingerprint']}`,
'tls-fingerprint',
);
// 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.tfo}`, 'tfo');
// udp
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
return result.toString();
}
function socks5(proxy) {
const result = new Result(proxy);
const type = proxy.tls ? 'socks5' : 'socks5-tls';
result.append(`${proxy.name}=${type},${proxy.server},${proxy.port}`);
result.appendIfPresent(`,${proxy.username}`, 'username');
result.appendIfPresent(`,${proxy.password}`, 'password');
// tls fingerprint
result.appendIfPresent(
`,server-cert-fingerprint-sha256=${proxy['tls-fingerprint']}`,
'tls-fingerprint',
);
// tls verification
result.appendIfPresent(`,sni=${proxy.sni}`, 'sni');
result.appendIfPresent(
`,skip-cert-verify=${proxy['skip-cert-verify']}`,
'skip-cert-verify',
);
// tfo
if (proxy.tfo) {
$.info(`Option tfo is not supported by Surge, thus omitted`);
}
// udp
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
return result.toString();
}
function snell(proxy) {
const result = new Result(proxy);
result.append(`${proxy.name}=${proxy.type},${proxy.server},${proxy.port}`);
result.appendIfPresent(`,version=${proxy.version}`, 'version');
result.appendIfPresent(`,psk=${proxy.psk}`, 'psk');
// obfs
result.appendIfPresent(
`,obfs=${proxy['obfs-opts'].mode}`,
'obfs-opts.mode',
);
result.appendIfPresent(
`,obfs-host=${proxy['obfs-opts'].host}`,
'obfs-opts.host',
);
result.appendIfPresent(
`,obfs-uri=${proxy['obfs-opts'].path}`,
'obfs-opts.path',
);
// udp
result.appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
return result.toString();
}

View File

@ -11,7 +11,7 @@ export class Result {
} }
appendIfPresent(data, attr) { appendIfPresent(data, attr) {
if (typeof _.get(this.proxy, attr) !== 'undefined') { if (isPresent(this.proxy, attr)) {
this.append(data); this.append(data);
} }
} }
@ -20,3 +20,7 @@ export class Result {
return this.output.join(''); return this.output.join('');
} }
} }
export function isPresent(obj, attr) {
return typeof _.get(obj, attr) !== 'undefined';
}

File diff suppressed because one or more lines are too long

View File

@ -1,14 +1,12 @@
/** /**
* 为节点添加 tls 证书指纹 * 为节点添加 tls 证书指纹
* 示例
* #fingerprint=...
*/ */
function operator(proxies, targetPlatform) { function operator(proxies) {
const {fingerprint} = $arguments; const { fingerprint } = $arguments;
proxies.forEach(proxy => { proxies.forEach(proxy => {
if (targetPlatform === "Surge") { proxy['tls-fingerprint'] = fingerprint;
proxy.tfo = `${proxy.tfo || false}, server-cert-fingerprint-sha256=${fingerprint}`;
} else if (targetPlatform === "QX") {
proxy.tfo = `${proxy.tfo || false}, tls-cert-sha256=${fingerprint}`;
}
}); });
return proxies; return proxies;
} }