mirror of
https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-10 00:52:40 +00:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e30a35bc4 | ||
|
|
3e5f3eafdd | ||
|
|
9c78b87834 | ||
|
|
ea88cc1794 | ||
|
|
c8b197c0a1 | ||
|
|
69fab11344 | ||
|
|
955c74a77d | ||
|
|
6d51774d36 | ||
|
|
a91f9d7728 | ||
|
|
df366cf8eb | ||
|
|
c547f34f57 | ||
|
|
a4ff32331a | ||
|
|
14648d6401 | ||
|
|
6a66475154 | ||
|
|
adc95bba60 | ||
|
|
fab3644b86 | ||
|
|
c21ce0be16 | ||
|
|
fa65eb1850 | ||
|
|
79c9b89c5f | ||
|
|
fca508ba8a | ||
|
|
21b531a44d | ||
|
|
4e5b46a43d | ||
|
|
bf81ca4acf | ||
|
|
e7c0b23222 | ||
|
|
40fb0fd7f3 |
25
README.md
25
README.md
@@ -30,13 +30,14 @@ Core functionalities:
|
|||||||
- [x] SSR URI
|
- [x] SSR URI
|
||||||
- [x] SSD URI
|
- [x] SSD URI
|
||||||
- [x] V2RayN URI
|
- [x] V2RayN URI
|
||||||
|
- [x] Hysteria2 URI
|
||||||
- [x] QX (SS, SSR, VMess, Trojan, HTTP)
|
- [x] QX (SS, SSR, VMess, Trojan, HTTP)
|
||||||
- [x] Loon (SS, SSR, VMess, Trojan, HTTP, WireGuard, VLESS)
|
- [x] Loon (SS, SSR, VMess, Trojan, HTTP, WireGuard, VLESS, Hysteria2)
|
||||||
- [x] Surge (SS, VMess, Trojan, HTTP, TUIC, Snell, SSR(external, only for macOS), WireGuard(Surge to Surge))
|
- [x] Surge (SS, VMess, Trojan, HTTP, TUIC, Snell, Hysteria2, SSR(external, only for macOS), WireGuard(Surge to Surge))
|
||||||
- [x] ShadowRocket (SS, SSR, VMess, Trojan, HTTP, Snell, VLESS, WireGuard, Hysteria)
|
- [x] ShadowRocket (SS, SSR, VMess, Trojan, HTTP, Snell, VLESS, Hysteria2)
|
||||||
- [x] Clash.Meta (SS, SSR, VMess, Trojan, HTTP, Snell, VLESS, WireGuard, Hysteria)
|
- [x] Clash.Meta (SS, SSR, VMess, Trojan, HTTP, Snell, VLESS, WireGuard, Hysteria, Hysteria2)
|
||||||
- [x] Stash (SS, SSR, VMess, Trojan, HTTP, Snell, VLESS, WireGuard, Hysteria)
|
- [x] Stash (SS, SSR, VMess, Trojan, HTTP, Snell, VLESS, WireGuard, Hysteria)
|
||||||
- [x] Clash (SS, SSR, VMess, Trojan, HTTP, Snell)
|
- [x] Clash (SS, SSR, VMess, Trojan, HTTP, Snell, VLESS, WireGuard)
|
||||||
|
|
||||||
### Supported Target Platforms
|
### Supported Target Platforms
|
||||||
|
|
||||||
@@ -75,24 +76,20 @@ Core functionalities:
|
|||||||
|
|
||||||
### Development
|
### Development
|
||||||
|
|
||||||
Go to `backend` and `web` directories, install node dependencies:
|
Install `pnpm`
|
||||||
|
|
||||||
|
Go to `backend` directories, install node dependencies:
|
||||||
|
|
||||||
```
|
```
|
||||||
npm install
|
pnpm install
|
||||||
```
|
```
|
||||||
|
|
||||||
1. In `backend`, run the backend server on http://localhost:3000
|
1. In `backend`, run the backend server on http://localhost:3000
|
||||||
|
|
||||||
```
|
```
|
||||||
npm run serve
|
pnpm start
|
||||||
```
|
```
|
||||||
|
|
||||||
2. In`web`, start the vue-cli server
|
|
||||||
|
|
||||||
```
|
|
||||||
npm start
|
|
||||||
```
|
|
||||||
|
|
||||||
## LICENSE
|
## LICENSE
|
||||||
|
|
||||||
This project is under the GPL V3 LICENSE.
|
This project is under the GPL V3 LICENSE.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sub-store",
|
"name": "sub-store",
|
||||||
"version": "2.14.64",
|
"version": "2.14.89",
|
||||||
"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": {
|
||||||
|
|||||||
@@ -183,6 +183,9 @@ export const ProxyUtils = {
|
|||||||
parse,
|
parse,
|
||||||
process,
|
process,
|
||||||
produce,
|
produce,
|
||||||
|
isIPv4,
|
||||||
|
isIPv6,
|
||||||
|
isIP,
|
||||||
};
|
};
|
||||||
|
|
||||||
function tryParse(parser, line) {
|
function tryParse(parser, line) {
|
||||||
@@ -212,6 +215,14 @@ function lastParse(proxy) {
|
|||||||
if (['trojan', 'tuic', 'hysteria', 'hysteria2'].includes(proxy.type)) {
|
if (['trojan', 'tuic', 'hysteria', 'hysteria2'].includes(proxy.type)) {
|
||||||
proxy.tls = true;
|
proxy.tls = true;
|
||||||
}
|
}
|
||||||
|
if (proxy.network) {
|
||||||
|
let transportHost = proxy[`${proxy.network}-opts`]?.headers?.Host;
|
||||||
|
let transporthost = proxy[`${proxy.network}-opts`]?.headers?.host;
|
||||||
|
if (transporthost && !transportHost) {
|
||||||
|
proxy[`${proxy.network}-opts`].headers.Host = transporthost;
|
||||||
|
delete proxy[`${proxy.network}-opts`].headers.host;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (proxy.tls && !proxy.sni) {
|
if (proxy.tls && !proxy.sni) {
|
||||||
if (proxy.network) {
|
if (proxy.network) {
|
||||||
let transportHost = proxy[`${proxy.network}-opts`]?.headers?.Host;
|
let transportHost = proxy[`${proxy.network}-opts`]?.headers?.Host;
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ function URI_VMess() {
|
|||||||
params.add = server;
|
params.add = server;
|
||||||
}
|
}
|
||||||
const proxy = {
|
const proxy = {
|
||||||
name: params.ps ?? params.remark,
|
name: params.ps ?? params.remarks,
|
||||||
type: 'vmess',
|
type: 'vmess',
|
||||||
server: params.add,
|
server: params.add,
|
||||||
port: parseInt(getIfPresent(params.port), 10),
|
port: parseInt(getIfPresent(params.port), 10),
|
||||||
@@ -272,6 +272,14 @@ function URI_VMess() {
|
|||||||
}
|
}
|
||||||
if (proxy.network) {
|
if (proxy.network) {
|
||||||
let transportHost = params.host ?? params.obfsParam;
|
let transportHost = params.host ?? params.obfsParam;
|
||||||
|
try {
|
||||||
|
const parsedObfs = JSON.parse(transportHost);
|
||||||
|
const parsedHost = parsedObfs?.Host;
|
||||||
|
if (parsedHost) {
|
||||||
|
transportHost = parsedHost;
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line no-empty
|
||||||
|
} catch (e) {}
|
||||||
let transportPath = params.path;
|
let transportPath = params.path;
|
||||||
|
|
||||||
if (proxy.network === 'http') {
|
if (proxy.network === 'http') {
|
||||||
@@ -396,6 +404,56 @@ function URI_VLESS() {
|
|||||||
};
|
};
|
||||||
return { name, test, parse };
|
return { name, test, parse };
|
||||||
}
|
}
|
||||||
|
function URI_Hysteria2() {
|
||||||
|
const name = 'URI Hysteria2 Parser';
|
||||||
|
const test = (line) => {
|
||||||
|
return /^hysteria2:\/\//.test(line);
|
||||||
|
};
|
||||||
|
const parse = (line) => {
|
||||||
|
line = line.split('hysteria2://')[1];
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
let [__, password, server, ___, port, addons, name] =
|
||||||
|
/^(.*?)@(.*?)(:(\d+))?\/?\?(.*?)(?:#(.*?))$/.exec(line);
|
||||||
|
port = parseInt(`${port}`, 10);
|
||||||
|
if (isNaN(port)) {
|
||||||
|
port = 443;
|
||||||
|
}
|
||||||
|
password = decodeURIComponent(password);
|
||||||
|
name = decodeURIComponent(name) ?? `Hysteria2 ${server}:${port}`;
|
||||||
|
|
||||||
|
const proxy = {
|
||||||
|
type: 'hysteria2',
|
||||||
|
name,
|
||||||
|
server,
|
||||||
|
port,
|
||||||
|
password,
|
||||||
|
};
|
||||||
|
|
||||||
|
const params = {};
|
||||||
|
for (const addon of addons.split('&')) {
|
||||||
|
const [key, valueRaw] = addon.split('=');
|
||||||
|
let value = valueRaw;
|
||||||
|
value = decodeURIComponent(valueRaw);
|
||||||
|
params[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy.sni = params.sni;
|
||||||
|
if (!proxy.sni && params.peer) {
|
||||||
|
proxy.sni = params.peer;
|
||||||
|
}
|
||||||
|
if (params.obfs && params.obfs !== 'none') {
|
||||||
|
proxy.obfs = params.obfs;
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy['obfs-password'] = params['obfs-password'];
|
||||||
|
proxy['skip-cert-verify'] = /(TRUE)|1/i.test(params.insecure);
|
||||||
|
proxy.tfo = /(TRUE)|1/i.test(params.fastopen);
|
||||||
|
proxy['tls-fingerprint'] = params.pinSHA256;
|
||||||
|
|
||||||
|
return proxy;
|
||||||
|
};
|
||||||
|
return { name, test, parse };
|
||||||
|
}
|
||||||
|
|
||||||
// Trojan URI format
|
// Trojan URI format
|
||||||
function URI_Trojan() {
|
function URI_Trojan() {
|
||||||
@@ -405,8 +463,16 @@ function URI_Trojan() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const parse = (line) => {
|
const parse = (line) => {
|
||||||
|
let [newLine, name] = line.split(/#(.+)/, 2);
|
||||||
const parser = getTrojanURIParser();
|
const parser = getTrojanURIParser();
|
||||||
const proxy = parser.parse(line);
|
const proxy = parser.parse(newLine);
|
||||||
|
if (isNotBlank(name)) {
|
||||||
|
try {
|
||||||
|
proxy.name = decodeURIComponent(name);
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
return { name, test, parse };
|
return { name, test, parse };
|
||||||
@@ -429,7 +495,7 @@ function Clash_All() {
|
|||||||
'ss',
|
'ss',
|
||||||
'ssr',
|
'ssr',
|
||||||
'vmess',
|
'vmess',
|
||||||
'socks',
|
'socks5',
|
||||||
'http',
|
'http',
|
||||||
'snell',
|
'snell',
|
||||||
'trojan',
|
'trojan',
|
||||||
@@ -461,6 +527,10 @@ function Clash_All() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (proxy['benchmark-url']) {
|
||||||
|
proxy['test-url'] = proxy['benchmark-url'];
|
||||||
|
}
|
||||||
|
|
||||||
return proxy;
|
return proxy;
|
||||||
};
|
};
|
||||||
return { name, test, parse };
|
return { name, test, parse };
|
||||||
@@ -584,6 +654,15 @@ function Loon_Trojan() {
|
|||||||
const parse = (line) => getLoonParser().parse(line);
|
const parse = (line) => getLoonParser().parse(line);
|
||||||
return { name, test, parse };
|
return { name, test, parse };
|
||||||
}
|
}
|
||||||
|
function Loon_Hysteria2() {
|
||||||
|
const name = 'Loon Hysteria2 Parser';
|
||||||
|
const test = (line) => {
|
||||||
|
return /^.*=\s*Hysteria2/i.test(line.split(',')[0]);
|
||||||
|
};
|
||||||
|
|
||||||
|
const parse = (line) => getLoonParser().parse(line);
|
||||||
|
return { name, test, parse };
|
||||||
|
}
|
||||||
|
|
||||||
function Loon_Http() {
|
function Loon_Http() {
|
||||||
const name = 'Loon HTTP Parser';
|
const name = 'Loon HTTP Parser';
|
||||||
@@ -776,11 +855,21 @@ function Surge_WireGuard() {
|
|||||||
return { name, test, parse };
|
return { name, test, parse };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Surge_Hysteria2() {
|
||||||
|
const name = 'Surge Hysteria2 Parser';
|
||||||
|
const test = (line) => {
|
||||||
|
return /^.*=\s*hysteria2/.test(line.split(',')[0]);
|
||||||
|
};
|
||||||
|
const parse = (line) => getSurgeParser().parse(line);
|
||||||
|
return { name, test, parse };
|
||||||
|
}
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
URI_SS(),
|
URI_SS(),
|
||||||
URI_SSR(),
|
URI_SSR(),
|
||||||
URI_VMess(),
|
URI_VMess(),
|
||||||
URI_VLESS(),
|
URI_VLESS(),
|
||||||
|
URI_Hysteria2(),
|
||||||
URI_Trojan(),
|
URI_Trojan(),
|
||||||
Clash_All(),
|
Clash_All(),
|
||||||
Surge_SS(),
|
Surge_SS(),
|
||||||
@@ -790,11 +879,13 @@ export default [
|
|||||||
Surge_Snell(),
|
Surge_Snell(),
|
||||||
Surge_Tuic(),
|
Surge_Tuic(),
|
||||||
Surge_WireGuard(),
|
Surge_WireGuard(),
|
||||||
|
Surge_Hysteria2(),
|
||||||
Surge_Socks5(),
|
Surge_Socks5(),
|
||||||
Loon_SS(),
|
Loon_SS(),
|
||||||
Loon_SSR(),
|
Loon_SSR(),
|
||||||
Loon_VMess(),
|
Loon_VMess(),
|
||||||
Loon_Vless(),
|
Loon_Vless(),
|
||||||
|
Loon_Hysteria2(),
|
||||||
Loon_Trojan(),
|
Loon_Trojan(),
|
||||||
Loon_Http(),
|
Loon_Http(),
|
||||||
Loon_WireGuard(),
|
Loon_WireGuard(),
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const grammars = String.raw`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start = (shadowsocksr/shadowsocks/vmess/vless/trojan/https/http) {
|
start = (shadowsocksr/shadowsocks/vmess/vless/trojan/https/http/hysteria2) {
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,6 +68,9 @@ trojan = tag equals "trojan"i address password (transport/transport_host/transpo
|
|||||||
proxy.type = "trojan";
|
proxy.type = "trojan";
|
||||||
handleTransport();
|
handleTransport();
|
||||||
}
|
}
|
||||||
|
hysteria2 = tag equals "hysteria2"i address password (tls_host/tls_verification/udp_relay/download_bandwidth/ecn/others)* {
|
||||||
|
proxy.type = "hysteria2";
|
||||||
|
}
|
||||||
https = tag equals "https"i address (username password)? (tls_host/tls_verification/fast_open/udp_relay/others)* {
|
https = tag equals "https"i address (username password)? (tls_host/tls_verification/fast_open/udp_relay/others)* {
|
||||||
proxy.type = "http";
|
proxy.type = "http";
|
||||||
proxy.tls = true;
|
proxy.tls = true;
|
||||||
@@ -167,6 +170,9 @@ tls_verification = comma "skip-cert-verify" equals flag:bool { proxy["skip-cert-
|
|||||||
fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; }
|
fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; }
|
||||||
udp_relay = comma "udp" equals flag:bool { proxy.udp = flag; }
|
udp_relay = comma "udp" equals flag:bool { proxy.udp = flag; }
|
||||||
|
|
||||||
|
ecn = comma "ecn" equals flag:bool { proxy.ecn = flag; }
|
||||||
|
download_bandwidth = comma "download-bandwidth" equals match:[^,]+ { proxy.down = match.join(""); }
|
||||||
|
|
||||||
tag = match:[^=,]* { proxy.name = match.join("").trim(); }
|
tag = match:[^=,]* { proxy.name = match.join("").trim(); }
|
||||||
comma = _ "," _
|
comma = _ "," _
|
||||||
equals = _ "=" _
|
equals = _ "=" _
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start = (shadowsocksr/shadowsocks/vmess/vless/trojan/https/http) {
|
start = (shadowsocksr/shadowsocks/vmess/vless/trojan/https/http/hysteria2) {
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,6 +66,9 @@ trojan = tag equals "trojan"i address password (transport/transport_host/transpo
|
|||||||
proxy.type = "trojan";
|
proxy.type = "trojan";
|
||||||
handleTransport();
|
handleTransport();
|
||||||
}
|
}
|
||||||
|
hysteria2 = tag equals "hysteria2"i address password (tls_host/tls_verification/udp_relay/download_bandwidth/ecn/others)* {
|
||||||
|
proxy.type = "hysteria2";
|
||||||
|
}
|
||||||
https = tag equals "https"i address (username password)? (tls_host/tls_verification/fast_open/udp_relay/others)* {
|
https = tag equals "https"i address (username password)? (tls_host/tls_verification/fast_open/udp_relay/others)* {
|
||||||
proxy.type = "http";
|
proxy.type = "http";
|
||||||
proxy.tls = true;
|
proxy.tls = true;
|
||||||
@@ -165,6 +168,9 @@ tls_verification = comma "skip-cert-verify" equals flag:bool { proxy["skip-cert-
|
|||||||
fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; }
|
fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; }
|
||||||
udp_relay = comma "udp" equals flag:bool { proxy.udp = flag; }
|
udp_relay = comma "udp" equals flag:bool { proxy.udp = flag; }
|
||||||
|
|
||||||
|
ecn = comma "ecn" equals flag:bool { proxy.ecn = flag; }
|
||||||
|
download_bandwidth = comma "download-bandwidth" equals match:[^,]+ { proxy.down = match.join(""); }
|
||||||
|
|
||||||
tag = match:[^=,]* { proxy.name = match.join("").trim(); }
|
tag = match:[^=,]* { proxy.name = match.join("").trim(); }
|
||||||
comma = _ "," _
|
comma = _ "," _
|
||||||
equals = _ "=" _
|
equals = _ "=" _
|
||||||
|
|||||||
@@ -43,13 +43,13 @@ start = (trojan/shadowsocks/vmess/http/socks5) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
trojan = "trojan" equals address
|
trojan = "trojan" equals address
|
||||||
(password/over_tls/tls_host/tls_fingerprint/tls_verification/obfs/obfs_host/obfs_uri/tag/udp_relay/udp_over_tcp/fast_open/others)* {
|
(password/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/obfs/obfs_host/obfs_uri/tag/udp_relay/udp_over_tcp/fast_open/server_check_url/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_fingerprint/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_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/udp_relay/udp_over_tcp/fast_open/tag/server_check_url/others)* {
|
||||||
if (proxy.protocol) {
|
if (proxy.protocol) {
|
||||||
proxy.type = "ssr";
|
proxy.type = "ssr";
|
||||||
// handle ssr obfs
|
// handle ssr obfs
|
||||||
@@ -80,7 +80,7 @@ shadowsocks = "shadowsocks" equals address
|
|||||||
}
|
}
|
||||||
|
|
||||||
vmess = "vmess" equals address
|
vmess = "vmess" equals address
|
||||||
(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)* {
|
(uuid/method/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/tag/obfs/obfs_host/obfs_uri/udp_relay/udp_over_tcp/fast_open/aead/server_check_url/others)* {
|
||||||
proxy.type = "vmess";
|
proxy.type = "vmess";
|
||||||
proxy.cipher = proxy.cipher || "none";
|
proxy.cipher = proxy.cipher || "none";
|
||||||
if (proxy.aead) {
|
if (proxy.aead) {
|
||||||
@@ -92,12 +92,12 @@ vmess = "vmess" equals address
|
|||||||
}
|
}
|
||||||
|
|
||||||
http = "http" equals address
|
http = "http" equals address
|
||||||
(username/password/over_tls/tls_host/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/others)*{
|
(username/password/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/server_check_url/others)*{
|
||||||
proxy.type = "http";
|
proxy.type = "http";
|
||||||
}
|
}
|
||||||
|
|
||||||
socks5 = "socks5" equals address
|
socks5 = "socks5" equals address
|
||||||
(username/password/password/over_tls/tls_host/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/others)* {
|
(username/password/password/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/server_check_url/others)* {
|
||||||
proxy.type = "socks5";
|
proxy.type = "socks5";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,6 +155,14 @@ 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.trim(); }
|
tls_fingerprint = comma "tls-cert-sha256" equals tls_fingerprint:$[^,]+ { proxy["tls-fingerprint"] = tls_fingerprint.trim(); }
|
||||||
|
tls_pubkey_sha256 = comma "tls-pubkey-sha256" equals param:$[^=,]+ { proxy["tls-pubkey-sha256"] = param; }
|
||||||
|
tls_alpn = comma "tls-alpn" equals param:$[^=,]+ { proxy["tls-alpn"] = param; }
|
||||||
|
tls_no_session_ticket = comma "tls-no-session-ticket" equals flag:bool {
|
||||||
|
proxy["tls-no-session-ticket"] = flag;
|
||||||
|
}
|
||||||
|
tls_no_session_reuse = comma "tls-no-session-reuse" equals flag:bool {
|
||||||
|
proxy["tls-no-session-reuse"] = flag;
|
||||||
|
}
|
||||||
|
|
||||||
obfs_ss = comma "obfs" equals type:("http"/"tls"/"wss"/"ws"/"over-tls") { 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; }
|
||||||
@@ -166,6 +174,8 @@ obfs_uri = comma "obfs-uri" equals uri:uri { obfs.path = uri; }
|
|||||||
ssr_protocol = comma "ssr-protocol" equals protocol:("origin"/"auth_sha1_v4"/"auth_aes128_md5"/"auth_aes128_sha1"/"auth_chain_a"/"auth_chain_b") { proxy.protocol = protocol; return protocol; }
|
ssr_protocol = comma "ssr-protocol" equals protocol:("origin"/"auth_sha1_v4"/"auth_aes128_md5"/"auth_aes128_sha1"/"auth_chain_a"/"auth_chain_b") { proxy.protocol = protocol; return protocol; }
|
||||||
ssr_protocol_param = comma "ssr-protocol-param" equals param:$[^=,]+ { proxy["protocol-param"] = param; }
|
ssr_protocol_param = comma "ssr-protocol-param" equals param:$[^=,]+ { proxy["protocol-param"] = param; }
|
||||||
|
|
||||||
|
server_check_url = comma "server_check_url" equals param:$[^=,]+ { proxy["test-url"] = param; }
|
||||||
|
|
||||||
uri = $[^,]+
|
uri = $[^,]+
|
||||||
|
|
||||||
tag = comma "tag" equals tag:[^=,]+ { proxy.name = tag.join(""); }
|
tag = comma "tag" equals tag:[^=,]+ { proxy.name = tag.join(""); }
|
||||||
|
|||||||
@@ -41,13 +41,13 @@ start = (trojan/shadowsocks/vmess/http/socks5) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
trojan = "trojan" equals address
|
trojan = "trojan" equals address
|
||||||
(password/over_tls/tls_host/tls_fingerprint/tls_verification/obfs/obfs_host/obfs_uri/tag/udp_relay/udp_over_tcp/fast_open/others)* {
|
(password/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/obfs/obfs_host/obfs_uri/tag/udp_relay/udp_over_tcp/fast_open/server_check_url/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_fingerprint/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_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/udp_relay/udp_over_tcp/fast_open/tag/server_check_url/others)* {
|
||||||
if (proxy.protocol) {
|
if (proxy.protocol) {
|
||||||
proxy.type = "ssr";
|
proxy.type = "ssr";
|
||||||
// handle ssr obfs
|
// handle ssr obfs
|
||||||
@@ -78,7 +78,7 @@ shadowsocks = "shadowsocks" equals address
|
|||||||
}
|
}
|
||||||
|
|
||||||
vmess = "vmess" equals address
|
vmess = "vmess" equals address
|
||||||
(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)* {
|
(uuid/method/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/tag/obfs/obfs_host/obfs_uri/udp_relay/udp_over_tcp/fast_open/aead/server_check_url/others)* {
|
||||||
proxy.type = "vmess";
|
proxy.type = "vmess";
|
||||||
proxy.cipher = proxy.cipher || "none";
|
proxy.cipher = proxy.cipher || "none";
|
||||||
if (proxy.aead) {
|
if (proxy.aead) {
|
||||||
@@ -90,12 +90,12 @@ vmess = "vmess" equals address
|
|||||||
}
|
}
|
||||||
|
|
||||||
http = "http" equals address
|
http = "http" equals address
|
||||||
(username/password/over_tls/tls_host/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/others)*{
|
(username/password/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/server_check_url/others)*{
|
||||||
proxy.type = "http";
|
proxy.type = "http";
|
||||||
}
|
}
|
||||||
|
|
||||||
socks5 = "socks5" equals address
|
socks5 = "socks5" equals address
|
||||||
(username/password/password/over_tls/tls_host/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/others)* {
|
(username/password/password/over_tls/tls_host/tls_pubkey_sha256/tls_alpn/tls_no_session_ticket/tls_no_session_reuse/tls_fingerprint/tls_verification/tag/fast_open/udp_relay/udp_over_tcp/server_check_url/others)* {
|
||||||
proxy.type = "socks5";
|
proxy.type = "socks5";
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,6 +153,14 @@ 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.trim(); }
|
tls_fingerprint = comma "tls-cert-sha256" equals tls_fingerprint:$[^,]+ { proxy["tls-fingerprint"] = tls_fingerprint.trim(); }
|
||||||
|
tls_pubkey_sha256 = comma "tls-pubkey-sha256" equals param:$[^=,]+ { proxy["tls-pubkey-sha256"] = param; }
|
||||||
|
tls_alpn = comma "tls-alpn" equals param:$[^=,]+ { proxy["tls-alpn"] = param; }
|
||||||
|
tls_no_session_ticket = comma "tls-no-session-ticket" equals flag:bool {
|
||||||
|
proxy["tls-no-session-ticket"] = flag;
|
||||||
|
}
|
||||||
|
tls_no_session_reuse = comma "tls-no-session-reuse" equals flag:bool {
|
||||||
|
proxy["tls-no-session-reuse"] = flag;
|
||||||
|
}
|
||||||
|
|
||||||
obfs_ss = comma "obfs" equals type:("http"/"tls"/"wss"/"ws"/"over-tls") { 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; }
|
||||||
@@ -164,6 +172,8 @@ obfs_uri = comma "obfs-uri" equals uri:uri { obfs.path = uri; }
|
|||||||
ssr_protocol = comma "ssr-protocol" equals protocol:("origin"/"auth_sha1_v4"/"auth_aes128_md5"/"auth_aes128_sha1"/"auth_chain_a"/"auth_chain_b") { proxy.protocol = protocol; return protocol; }
|
ssr_protocol = comma "ssr-protocol" equals protocol:("origin"/"auth_sha1_v4"/"auth_aes128_md5"/"auth_aes128_sha1"/"auth_chain_a"/"auth_chain_b") { proxy.protocol = protocol; return protocol; }
|
||||||
ssr_protocol_param = comma "ssr-protocol-param" equals param:$[^=,]+ { proxy["protocol-param"] = param; }
|
ssr_protocol_param = comma "ssr-protocol-param" equals param:$[^=,]+ { proxy["protocol-param"] = param; }
|
||||||
|
|
||||||
|
server_check_url = comma "server_check_url" equals param:$[^=,]+ { proxy["test-url"] = param; }
|
||||||
|
|
||||||
uri = $[^,]+
|
uri = $[^,]+
|
||||||
|
|
||||||
tag = comma "tag" equals tag:[^=,]+ { proxy.name = tag.join(""); }
|
tag = comma "tag" equals tag:[^=,]+ { proxy.name = tag.join(""); }
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ const grammars = String.raw`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls/tuic/tuic_v5/wireguard) {
|
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls/tuic/tuic_v5/wireguard/hysteria2) {
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/fast_open/udp_relay/others)* {
|
shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/fast_open/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "ss";
|
proxy.type = "ss";
|
||||||
// handle obfs
|
// handle obfs
|
||||||
if (obfs.type == "http" || obfs.type === "tls") {
|
if (obfs.type == "http" || obfs.type === "tls") {
|
||||||
@@ -46,7 +46,7 @@ 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_fingerprint/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/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "vmess";
|
proxy.type = "vmess";
|
||||||
proxy.cipher = proxy.cipher || "none";
|
proxy.cipher = proxy.cipher || "none";
|
||||||
if (proxy.aead) {
|
if (proxy.aead) {
|
||||||
@@ -56,18 +56,18 @@ vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/
|
|||||||
}
|
}
|
||||||
handleWebsocket();
|
handleWebsocket();
|
||||||
}
|
}
|
||||||
trojan = tag equals "trojan" address (passwordk/ws/ws_path/ws_headers/tls/sni/tls_fingerprint/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/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "trojan";
|
proxy.type = "trojan";
|
||||||
handleWebsocket();
|
handleWebsocket();
|
||||||
}
|
}
|
||||||
https = tag equals "https" address (username password)? (sni/tls_fingerprint/tls_verification/fast_open/others)* {
|
https = tag equals "https" address (username password)? (usernamek passwordk)? (sni/tls_fingerprint/tls_verification/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "http";
|
proxy.type = "http";
|
||||||
proxy.tls = true;
|
proxy.tls = true;
|
||||||
}
|
}
|
||||||
http = tag equals "http" address (username password)? (fast_open/others)* {
|
http = tag equals "http" address (username password)? (usernamek passwordk)? (fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "http";
|
proxy.type = "http";
|
||||||
}
|
}
|
||||||
snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_uri/fast_open/udp_relay/reuse/others)* {
|
snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_uri/fast_open/udp_relay/reuse/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "snell";
|
proxy.type = "snell";
|
||||||
// handle obfs
|
// handle obfs
|
||||||
if (obfs.type == "http" || obfs.type === "tls") {
|
if (obfs.type == "http" || obfs.type === "tls") {
|
||||||
@@ -76,20 +76,23 @@ snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_
|
|||||||
$set(proxy, "obfs-opts.path", obfs.path);
|
$set(proxy, "obfs-opts.path", obfs.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tuic = tag equals "tuic" address (alpn/token/ip_version/tls_verification/sni/fast_open/tfo/others)* {
|
tuic = tag equals "tuic" address (alpn/token/ip_version/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "tuic";
|
proxy.type = "tuic";
|
||||||
}
|
}
|
||||||
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/tls_verification/sni/fast_open/tfo/others)* {
|
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "tuic";
|
proxy.type = "tuic";
|
||||||
proxy.version = 5;
|
proxy.version = 5;
|
||||||
}
|
}
|
||||||
wireguard = tag equals "wireguard" (section_name/no_error_alert/ip_version/underlying_proxy/test_url/others)* {
|
wireguard = tag equals "wireguard" (section_name/no_error_alert/ip_version/underlying_proxy/test_url/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "wireguard-surge";
|
proxy.type = "wireguard-surge";
|
||||||
}
|
}
|
||||||
socks5 = tag equals "socks5" address (username password)? (fast_open/others)* {
|
hysteria2 = tag equals "hysteria2" address (no_error_alert/ip_version/underlying_proxy/test_url/sni/tls_verification/passwordk/tls_fingerprint/download_bandwidth/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
|
proxy.type = "hysteria2";
|
||||||
|
}
|
||||||
|
socks5 = tag equals "socks5" address (username password)? (usernamek passwordk)? (fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "socks5";
|
proxy.type = "socks5";
|
||||||
}
|
}
|
||||||
socks5_tls = tag equals "socks5-tls" address (username password)? (sni/tls_fingerprint/tls_verification/fast_open/others)* {
|
socks5_tls = tag equals "socks5-tls" address (username password)? (usernamek passwordk)? (sni/tls_fingerprint/tls_verification/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "socks5";
|
proxy.type = "socks5";
|
||||||
proxy.tls = true;
|
proxy.tls = true;
|
||||||
}
|
}
|
||||||
@@ -160,6 +163,7 @@ tls_fingerprint = comma "server-cert-fingerprint-sha256" equals 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()); }
|
||||||
|
|
||||||
|
usernamek = comma "username" equals match:[^,]+ { proxy.username = match.join(""); }
|
||||||
passwordk = comma "password" equals match:[^,]+ { proxy.password = match.join(""); }
|
passwordk = comma "password" equals match:[^,]+ { proxy.password = match.join(""); }
|
||||||
vmess_uuid = comma "username" equals match:[^,]+ { proxy.uuid = match.join(""); }
|
vmess_uuid = comma "username" equals match:[^,]+ { proxy.uuid = match.join(""); }
|
||||||
vmess_aead = comma "vmess-aead" equals flag:bool { proxy.aead = flag; }
|
vmess_aead = comma "vmess-aead" equals flag:bool { proxy.aead = flag; }
|
||||||
@@ -189,12 +193,18 @@ uri = $[^,]+
|
|||||||
udp_relay = comma "udp" equals flag:bool { proxy.udp = flag; }
|
udp_relay = comma "udp" equals flag:bool { proxy.udp = flag; }
|
||||||
fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; }
|
fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; }
|
||||||
reuse = comma "reuse" equals flag:bool { proxy.reuse = flag; }
|
reuse = comma "reuse" equals flag:bool { proxy.reuse = flag; }
|
||||||
|
ecn = comma "ecn" equals flag:bool { proxy.ecn = flag; }
|
||||||
tfo = comma "tfo" 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(""); }
|
ip_version = comma "ip-version" equals match:[^,]+ { proxy["ip-version"] = match.join(""); }
|
||||||
section_name = comma "section-name" equals match:[^,]+ { proxy["section-name"] = match.join(""); }
|
section_name = comma "section-name" equals match:[^,]+ { proxy["section-name"] = match.join(""); }
|
||||||
no_error_alert = comma "no-error-alert" equals match:[^,]+ { proxy["no-error-alert"] = match.join(""); }
|
no_error_alert = comma "no-error-alert" equals match:[^,]+ { proxy["no-error-alert"] = match.join(""); }
|
||||||
underlying_proxy = comma "underlying-proxy" equals match:[^,]+ { proxy["underlying-proxy"] = match.join(""); }
|
underlying_proxy = comma "underlying-proxy" equals match:[^,]+ { proxy["underlying-proxy"] = match.join(""); }
|
||||||
|
download_bandwidth = comma "download-bandwidth" equals match:[^,]+ { proxy.down = match.join(""); }
|
||||||
test_url = comma "test-url" equals match:[^,]+ { proxy["test-url"] = match.join(""); }
|
test_url = comma "test-url" equals match:[^,]+ { proxy["test-url"] = match.join(""); }
|
||||||
|
block_quic = comma "block-quic" equals match:[^,]+ { proxy["block-quic"] = match.join(""); }
|
||||||
|
shadow_tls_version = comma "shadow-tls-version" equals match:$[0-9]+ { proxy["shadow-tls-version"] = parseInt(match.trim()); }
|
||||||
|
shadow_tls_sni = comma "shadow-tls-sni" equals match:[^,]+ { proxy["shadow-tls-sni"] = match.join(""); }
|
||||||
|
shadow_tls_password = comma "shadow-tls-password" equals match:[^,]+ { proxy["shadow-tls-password"] = match.join(""); }
|
||||||
token = comma "token" equals match:[^,]+ { proxy.token = match.join(""); }
|
token = comma "token" equals match:[^,]+ { proxy.token = match.join(""); }
|
||||||
alpn = comma "alpn" equals match:[^,]+ { proxy.alpn = match.join(""); }
|
alpn = comma "alpn" equals match:[^,]+ { proxy.alpn = match.join(""); }
|
||||||
uuidk = comma "uuid" equals match:[^,]+ { proxy.uuid = match.join(""); }
|
uuidk = comma "uuid" equals match:[^,]+ { proxy.uuid = match.join(""); }
|
||||||
|
|||||||
@@ -30,11 +30,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls/tuic/tuic_v5/wireguard) {
|
start = (shadowsocks/vmess/trojan/https/http/snell/socks5/socks5_tls/tuic/tuic_v5/wireguard/hysteria2) {
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/fast_open/udp_relay/others)* {
|
shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/fast_open/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "ss";
|
proxy.type = "ss";
|
||||||
// handle obfs
|
// handle obfs
|
||||||
if (obfs.type == "http" || obfs.type === "tls") {
|
if (obfs.type == "http" || obfs.type === "tls") {
|
||||||
@@ -44,7 +44,7 @@ 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_fingerprint/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/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "vmess";
|
proxy.type = "vmess";
|
||||||
proxy.cipher = proxy.cipher || "none";
|
proxy.cipher = proxy.cipher || "none";
|
||||||
if (proxy.aead) {
|
if (proxy.aead) {
|
||||||
@@ -54,18 +54,18 @@ vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/
|
|||||||
}
|
}
|
||||||
handleWebsocket();
|
handleWebsocket();
|
||||||
}
|
}
|
||||||
trojan = tag equals "trojan" address (passwordk/ws/ws_path/ws_headers/tls/sni/tls_fingerprint/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/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "trojan";
|
proxy.type = "trojan";
|
||||||
handleWebsocket();
|
handleWebsocket();
|
||||||
}
|
}
|
||||||
https = tag equals "https" address (username password)? (sni/tls_fingerprint/tls_verification/fast_open/others)* {
|
https = tag equals "https" address (username password)? (usernamek passwordk)? (sni/tls_fingerprint/tls_verification/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "http";
|
proxy.type = "http";
|
||||||
proxy.tls = true;
|
proxy.tls = true;
|
||||||
}
|
}
|
||||||
http = tag equals "http" address (username password)? (fast_open/others)* {
|
http = tag equals "http" address (username password)? (usernamek passwordk)? (fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "http";
|
proxy.type = "http";
|
||||||
}
|
}
|
||||||
snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_uri/fast_open/udp_relay/reuse/others)* {
|
snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_uri/fast_open/udp_relay/reuse/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "snell";
|
proxy.type = "snell";
|
||||||
// handle obfs
|
// handle obfs
|
||||||
if (obfs.type == "http" || obfs.type === "tls") {
|
if (obfs.type == "http" || obfs.type === "tls") {
|
||||||
@@ -74,20 +74,23 @@ snell = tag equals "snell" address (snell_version/snell_psk/obfs/obfs_host/obfs_
|
|||||||
$set(proxy, "obfs-opts.path", obfs.path);
|
$set(proxy, "obfs-opts.path", obfs.path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tuic = tag equals "tuic" address (alpn/token/ip_version/tls_verification/sni/fast_open/tfo/others)* {
|
tuic = tag equals "tuic" address (alpn/token/ip_version/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "tuic";
|
proxy.type = "tuic";
|
||||||
}
|
}
|
||||||
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/tls_verification/sni/fast_open/tfo/others)* {
|
tuic_v5 = tag equals "tuic-v5" address (alpn/passwordk/uuidk/ip_version/tls_verification/sni/fast_open/tfo/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "tuic";
|
proxy.type = "tuic";
|
||||||
proxy.version = 5;
|
proxy.version = 5;
|
||||||
}
|
}
|
||||||
wireguard = tag equals "wireguard" (section_name/no_error_alert/ip_version/underlying_proxy/test_url/others)* {
|
wireguard = tag equals "wireguard" (section_name/no_error_alert/ip_version/underlying_proxy/test_url/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "wireguard-surge";
|
proxy.type = "wireguard-surge";
|
||||||
}
|
}
|
||||||
socks5 = tag equals "socks5" address (username password)? (fast_open/others)* {
|
hysteria2 = tag equals "hysteria2" address (no_error_alert/ip_version/underlying_proxy/test_url/sni/tls_verification/passwordk/tls_fingerprint/download_bandwidth/ecn/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
|
proxy.type = "hysteria2";
|
||||||
|
}
|
||||||
|
socks5 = tag equals "socks5" address (username password)? (usernamek passwordk)? (fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "socks5";
|
proxy.type = "socks5";
|
||||||
}
|
}
|
||||||
socks5_tls = tag equals "socks5-tls" address (username password)? (sni/tls_fingerprint/tls_verification/fast_open/others)* {
|
socks5_tls = tag equals "socks5-tls" address (username password)? (usernamek passwordk)? (sni/tls_fingerprint/tls_verification/fast_open/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
|
||||||
proxy.type = "socks5";
|
proxy.type = "socks5";
|
||||||
proxy.tls = true;
|
proxy.tls = true;
|
||||||
}
|
}
|
||||||
@@ -158,6 +161,7 @@ tls_fingerprint = comma "server-cert-fingerprint-sha256" equals 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()); }
|
||||||
|
|
||||||
|
usernamek = comma "username" equals match:[^,]+ { proxy.username = match.join(""); }
|
||||||
passwordk = comma "password" equals match:[^,]+ { proxy.password = match.join(""); }
|
passwordk = comma "password" equals match:[^,]+ { proxy.password = match.join(""); }
|
||||||
vmess_uuid = comma "username" equals match:[^,]+ { proxy.uuid = match.join(""); }
|
vmess_uuid = comma "username" equals match:[^,]+ { proxy.uuid = match.join(""); }
|
||||||
vmess_aead = comma "vmess-aead" equals flag:bool { proxy.aead = flag; }
|
vmess_aead = comma "vmess-aead" equals flag:bool { proxy.aead = flag; }
|
||||||
@@ -187,12 +191,18 @@ uri = $[^,]+
|
|||||||
udp_relay = comma "udp" equals flag:bool { proxy.udp = flag; }
|
udp_relay = comma "udp" equals flag:bool { proxy.udp = flag; }
|
||||||
fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; }
|
fast_open = comma "fast-open" equals flag:bool { proxy.tfo = flag; }
|
||||||
reuse = comma "reuse" equals flag:bool { proxy.reuse = flag; }
|
reuse = comma "reuse" equals flag:bool { proxy.reuse = flag; }
|
||||||
|
ecn = comma "ecn" equals flag:bool { proxy.ecn = flag; }
|
||||||
tfo = comma "tfo" 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(""); }
|
ip_version = comma "ip-version" equals match:[^,]+ { proxy["ip-version"] = match.join(""); }
|
||||||
section_name = comma "section-name" equals match:[^,]+ { proxy["section-name"] = match.join(""); }
|
section_name = comma "section-name" equals match:[^,]+ { proxy["section-name"] = match.join(""); }
|
||||||
no_error_alert = comma "no-error-alert" equals match:[^,]+ { proxy["no-error-alert"] = match.join(""); }
|
no_error_alert = comma "no-error-alert" equals match:[^,]+ { proxy["no-error-alert"] = match.join(""); }
|
||||||
underlying_proxy = comma "underlying-proxy" equals match:[^,]+ { proxy["underlying-proxy"] = match.join(""); }
|
underlying_proxy = comma "underlying-proxy" equals match:[^,]+ { proxy["underlying-proxy"] = match.join(""); }
|
||||||
|
download_bandwidth = comma "download-bandwidth" equals match:[^,]+ { proxy.down = match.join(""); }
|
||||||
test_url = comma "test-url" equals match:[^,]+ { proxy["test-url"] = match.join(""); }
|
test_url = comma "test-url" equals match:[^,]+ { proxy["test-url"] = match.join(""); }
|
||||||
|
block_quic = comma "block-quic" equals match:[^,]+ { proxy["block-quic"] = match.join(""); }
|
||||||
|
shadow_tls_version = comma "shadow-tls-version" equals match:$[0-9]+ { proxy["shadow-tls-version"] = parseInt(match.trim()); }
|
||||||
|
shadow_tls_sni = comma "shadow-tls-sni" equals match:[^,]+ { proxy["shadow-tls-sni"] = match.join(""); }
|
||||||
|
shadow_tls_password = comma "shadow-tls-password" equals match:[^,]+ { proxy["shadow-tls-password"] = match.join(""); }
|
||||||
token = comma "token" equals match:[^,]+ { proxy.token = match.join(""); }
|
token = comma "token" equals match:[^,]+ { proxy.token = match.join(""); }
|
||||||
alpn = comma "alpn" equals match:[^,]+ { proxy.alpn = match.join(""); }
|
alpn = comma "alpn" equals match:[^,]+ { proxy.alpn = match.join(""); }
|
||||||
uuidk = comma "uuid" equals match:[^,]+ { proxy.uuid = match.join(""); }
|
uuidk = comma "uuid" equals match:[^,]+ { proxy.uuid = match.join(""); }
|
||||||
|
|||||||
@@ -13,13 +13,15 @@ function Base64Encoded() {
|
|||||||
const name = 'Base64 Pre-processor';
|
const name = 'Base64 Pre-processor';
|
||||||
|
|
||||||
const keys = [
|
const keys = [
|
||||||
'dm1lc3M',
|
'dm1lc3M', // vmess
|
||||||
'c3NyOi8v',
|
'c3NyOi8v', // ssr://
|
||||||
'dHJvamFu',
|
'dHJvamFu', // trojan
|
||||||
'c3M6Ly',
|
'c3M6Ly', // ss:/
|
||||||
'c3NkOi8v',
|
'c3NkOi8v', // ssd://
|
||||||
'c2hhZG93',
|
'c2hhZG93', // shadow
|
||||||
'aHR0c',
|
'aHR0c', // htt
|
||||||
|
'dmxlc3M=', // vless
|
||||||
|
'aHlzdGVyaWEy', // hysteria2
|
||||||
];
|
];
|
||||||
|
|
||||||
const test = function (raw) {
|
const test = function (raw) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import $ from '@/core/app';
|
|||||||
import { hex_md5 } from '@/vendor/md5';
|
import { hex_md5 } from '@/vendor/md5';
|
||||||
import { ProxyUtils } from '@/core/proxy-utils';
|
import { ProxyUtils } from '@/core/proxy-utils';
|
||||||
import env from '@/utils/env';
|
import env from '@/utils/env';
|
||||||
|
import { getFlowHeaders, parseFlowHeaders, flowTransfer } from '@/utils/flow';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
The rule "(name CONTAINS "🇨🇳") AND (port IN [80, 443])" can be expressed as follows:
|
The rule "(name CONTAINS "🇨🇳") AND (port IN [80, 443])" can be expressed as follows:
|
||||||
@@ -310,6 +311,23 @@ function ScriptOperator(script, targetPlatform, $arguments, source) {
|
|||||||
})();
|
})();
|
||||||
return output;
|
return output;
|
||||||
},
|
},
|
||||||
|
nodeFunc: async (proxies) => {
|
||||||
|
let output = proxies;
|
||||||
|
await (async function () {
|
||||||
|
const operator = createDynamicFunction(
|
||||||
|
'operator',
|
||||||
|
`async function operator(proxies = []) {
|
||||||
|
return proxies.map(($server = {}) => {
|
||||||
|
${script}
|
||||||
|
return $server
|
||||||
|
})
|
||||||
|
}`,
|
||||||
|
$arguments,
|
||||||
|
);
|
||||||
|
output = operator(proxies, targetPlatform, { source, ...env });
|
||||||
|
})();
|
||||||
|
return output;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,9 +637,33 @@ async function ApplyOperator(operator, objs) {
|
|||||||
const output_ = await operator.func(output);
|
const output_ = await operator.func(output);
|
||||||
if (output_) output = output_;
|
if (output_) output = output_;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// print log and skip this operator
|
$.error(
|
||||||
$.error(`Cannot apply operator ${operator.name}! Reason: ${err}`);
|
`Cannot apply operator ${operator.name}(function operator)! Reason: ${err}`,
|
||||||
throw new Error(`脚本操作失败 ${err.message ?? err}`);
|
);
|
||||||
|
let funcErr = '';
|
||||||
|
let funcErrMsg = `${err.message ?? err}`;
|
||||||
|
if (funcErrMsg.includes('$server is not defined')) {
|
||||||
|
funcErr = '';
|
||||||
|
} else {
|
||||||
|
funcErr = `执行 function operator 失败 ${funcErrMsg}; `;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const output_ = await operator.nodeFunc(output);
|
||||||
|
if (output_) output = output_;
|
||||||
|
} catch (err) {
|
||||||
|
$.error(
|
||||||
|
`Cannot apply operator ${operator.name}(node script)! Reason: ${err}`,
|
||||||
|
);
|
||||||
|
let nodeErr = '';
|
||||||
|
let nodeErrMsg = `${err.message ?? err}`;
|
||||||
|
if (funcErr && nodeErrMsg === funcErrMsg) {
|
||||||
|
nodeErr = '';
|
||||||
|
funcErr = `执行失败 ${funcErrMsg}`;
|
||||||
|
} else {
|
||||||
|
nodeErr = `执行节点快捷脚本 失败 ${nodeErr}`;
|
||||||
|
}
|
||||||
|
throw new Error(`脚本操作 ${funcErr}${nodeErr}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
@@ -668,6 +710,7 @@ function removeFlag(str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createDynamicFunction(name, script, $arguments) {
|
function createDynamicFunction(name, script, $arguments) {
|
||||||
|
const flowUtils = { getFlowHeaders, parseFlowHeaders, flowTransfer };
|
||||||
if ($.env.isLoon) {
|
if ($.env.isLoon) {
|
||||||
return new Function(
|
return new Function(
|
||||||
'$arguments',
|
'$arguments',
|
||||||
@@ -678,6 +721,7 @@ function createDynamicFunction(name, script, $arguments) {
|
|||||||
'$notification',
|
'$notification',
|
||||||
'ProxyUtils',
|
'ProxyUtils',
|
||||||
'scriptResourceCache',
|
'scriptResourceCache',
|
||||||
|
'flowUtils',
|
||||||
`${script}\n return ${name}`,
|
`${script}\n return ${name}`,
|
||||||
)(
|
)(
|
||||||
$arguments,
|
$arguments,
|
||||||
@@ -691,6 +735,7 @@ function createDynamicFunction(name, script, $arguments) {
|
|||||||
$notification,
|
$notification,
|
||||||
ProxyUtils,
|
ProxyUtils,
|
||||||
scriptResourceCache,
|
scriptResourceCache,
|
||||||
|
flowUtils,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return new Function(
|
return new Function(
|
||||||
@@ -699,7 +744,9 @@ function createDynamicFunction(name, script, $arguments) {
|
|||||||
'lodash',
|
'lodash',
|
||||||
'ProxyUtils',
|
'ProxyUtils',
|
||||||
'scriptResourceCache',
|
'scriptResourceCache',
|
||||||
|
'flowUtils',
|
||||||
|
|
||||||
`${script}\n return ${name}`,
|
`${script}\n return ${name}`,
|
||||||
)($arguments, $, lodash, ProxyUtils, scriptResourceCache);
|
)($arguments, $, lodash, ProxyUtils, scriptResourceCache, flowUtils);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export default function Clash_Producer() {
|
|||||||
'ssr',
|
'ssr',
|
||||||
'vmess',
|
'vmess',
|
||||||
'vless',
|
'vless',
|
||||||
'socks',
|
'socks5',
|
||||||
'http',
|
'http',
|
||||||
'snell',
|
'snell',
|
||||||
'trojan',
|
'trojan',
|
||||||
@@ -97,6 +97,10 @@ export default function Clash_Producer() {
|
|||||||
) {
|
) {
|
||||||
delete proxy.tls;
|
delete proxy.tls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (proxy['tls-fingerprint']) {
|
||||||
|
proxy.fingerprint = proxy['tls-fingerprint'];
|
||||||
|
}
|
||||||
delete proxy['tls-fingerprint'];
|
delete proxy['tls-fingerprint'];
|
||||||
delete proxy.subName;
|
delete proxy.subName;
|
||||||
delete proxy.collectionName;
|
delete proxy.collectionName;
|
||||||
|
|||||||
@@ -63,6 +63,13 @@ export default function ClashMeta_Producer() {
|
|||||||
proxy.version = 5;
|
proxy.version = 5;
|
||||||
}
|
}
|
||||||
} else if (proxy.type === 'hysteria') {
|
} else if (proxy.type === 'hysteria') {
|
||||||
|
// auth_str 将会在未来某个时候删除 但是有的机场不规范
|
||||||
|
if (
|
||||||
|
isPresent(proxy, 'auth_str') &&
|
||||||
|
!isPresent(proxy, 'auth-str')
|
||||||
|
) {
|
||||||
|
proxy['auth-str'] = proxy['auth_str'];
|
||||||
|
}
|
||||||
if (isPresent(proxy, 'alpn')) {
|
if (isPresent(proxy, 'alpn')) {
|
||||||
proxy.alpn = Array.isArray(proxy.alpn)
|
proxy.alpn = Array.isArray(proxy.alpn)
|
||||||
? proxy.alpn
|
? proxy.alpn
|
||||||
@@ -116,6 +123,9 @@ export default function ClashMeta_Producer() {
|
|||||||
delete proxy.tls;
|
delete proxy.tls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (proxy['tls-fingerprint']) {
|
||||||
|
proxy.fingerprint = proxy['tls-fingerprint'];
|
||||||
|
}
|
||||||
delete proxy['tls-fingerprint'];
|
delete proxy['tls-fingerprint'];
|
||||||
delete proxy.subName;
|
delete proxy.subName;
|
||||||
delete proxy.collectionName;
|
delete proxy.collectionName;
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ export default function Loon_Producer() {
|
|||||||
return http(proxy);
|
return http(proxy);
|
||||||
case 'wireguard':
|
case 'wireguard':
|
||||||
return wireguard(proxy);
|
return wireguard(proxy);
|
||||||
|
case 'hysteria2':
|
||||||
|
return hysteria2(proxy);
|
||||||
}
|
}
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`,
|
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`,
|
||||||
@@ -334,3 +336,33 @@ function wireguard(proxy) {
|
|||||||
|
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hysteria2(proxy) {
|
||||||
|
if (proxy.obfs || proxy['obfs-password']) {
|
||||||
|
throw new Error(`obfs is unsupported`);
|
||||||
|
}
|
||||||
|
const result = new Result(proxy);
|
||||||
|
result.append(`${proxy.name}=Hysteria2,${proxy.server},${proxy.port}`);
|
||||||
|
|
||||||
|
result.appendIfPresent(`,"${proxy.password}"`, 'password');
|
||||||
|
|
||||||
|
// sni
|
||||||
|
result.appendIfPresent(`,tls-name=${proxy.sni}`, 'sni');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,skip-cert-verify=${proxy['skip-cert-verify']}`,
|
||||||
|
'skip-cert-verify',
|
||||||
|
);
|
||||||
|
|
||||||
|
// udp
|
||||||
|
result.appendIfPresent(`,udp=${proxy.udp}`, 'udp');
|
||||||
|
|
||||||
|
// download-bandwidth
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,download-bandwidth=${`${proxy['down']}`.match(/\d+/)?.[0] || 0}`,
|
||||||
|
'down',
|
||||||
|
);
|
||||||
|
|
||||||
|
result.appendIfPresent(`,ecn=${proxy.ecn}`, 'ecn');
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|||||||
@@ -63,6 +63,19 @@ function shadowsocks(proxy) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (needTls(proxy)) {
|
if (needTls(proxy)) {
|
||||||
|
appendIfPresent(
|
||||||
|
`,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`,
|
||||||
|
'tls-pubkey-sha256',
|
||||||
|
);
|
||||||
|
appendIfPresent(`,tls-alpn=${proxy['tls-alpn']}`, 'tls-alpn');
|
||||||
|
appendIfPresent(
|
||||||
|
`,tls-no-session-ticket=${proxy['tls-no-session-ticket']}`,
|
||||||
|
'tls-no-session-ticket',
|
||||||
|
);
|
||||||
|
appendIfPresent(
|
||||||
|
`,tls-no-session-reuse=${proxy['tls-no-session-reuse']}`,
|
||||||
|
'tls-no-session-reuse',
|
||||||
|
);
|
||||||
// tls fingerprint
|
// tls fingerprint
|
||||||
appendIfPresent(
|
appendIfPresent(
|
||||||
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
|
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
|
||||||
@@ -83,6 +96,12 @@ function shadowsocks(proxy) {
|
|||||||
// udp
|
// udp
|
||||||
appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
||||||
|
|
||||||
|
// server_check_url
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,server_check_url=${proxy['test-url']}`,
|
||||||
|
'test-url',
|
||||||
|
);
|
||||||
|
|
||||||
// tag
|
// tag
|
||||||
append(`,tag=${proxy.name}`);
|
append(`,tag=${proxy.name}`);
|
||||||
|
|
||||||
@@ -115,6 +134,12 @@ function shadowsocksr(proxy) {
|
|||||||
// udp
|
// udp
|
||||||
appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
||||||
|
|
||||||
|
// server_check_url
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,server_check_url=${proxy['test-url']}`,
|
||||||
|
'test-url',
|
||||||
|
);
|
||||||
|
|
||||||
// tag
|
// tag
|
||||||
append(`,tag=${proxy.name}`);
|
append(`,tag=${proxy.name}`);
|
||||||
|
|
||||||
@@ -153,6 +178,19 @@ function trojan(proxy) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (needTls(proxy)) {
|
if (needTls(proxy)) {
|
||||||
|
appendIfPresent(
|
||||||
|
`,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`,
|
||||||
|
'tls-pubkey-sha256',
|
||||||
|
);
|
||||||
|
appendIfPresent(`,tls-alpn=${proxy['tls-alpn']}`, 'tls-alpn');
|
||||||
|
appendIfPresent(
|
||||||
|
`,tls-no-session-ticket=${proxy['tls-no-session-ticket']}`,
|
||||||
|
'tls-no-session-ticket',
|
||||||
|
);
|
||||||
|
appendIfPresent(
|
||||||
|
`,tls-no-session-reuse=${proxy['tls-no-session-reuse']}`,
|
||||||
|
'tls-no-session-reuse',
|
||||||
|
);
|
||||||
// tls fingerprint
|
// tls fingerprint
|
||||||
appendIfPresent(
|
appendIfPresent(
|
||||||
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
|
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
|
||||||
@@ -173,6 +211,12 @@ function trojan(proxy) {
|
|||||||
// udp
|
// udp
|
||||||
appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
||||||
|
|
||||||
|
// server_check_url
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,server_check_url=${proxy['test-url']}`,
|
||||||
|
'test-url',
|
||||||
|
);
|
||||||
|
|
||||||
// tag
|
// tag
|
||||||
append(`,tag=${proxy.name}`);
|
append(`,tag=${proxy.name}`);
|
||||||
|
|
||||||
@@ -230,6 +274,19 @@ function vmess(proxy) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (needTls(proxy)) {
|
if (needTls(proxy)) {
|
||||||
|
appendIfPresent(
|
||||||
|
`,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`,
|
||||||
|
'tls-pubkey-sha256',
|
||||||
|
);
|
||||||
|
appendIfPresent(`,tls-alpn=${proxy['tls-alpn']}`, 'tls-alpn');
|
||||||
|
appendIfPresent(
|
||||||
|
`,tls-no-session-ticket=${proxy['tls-no-session-ticket']}`,
|
||||||
|
'tls-no-session-ticket',
|
||||||
|
);
|
||||||
|
appendIfPresent(
|
||||||
|
`,tls-no-session-reuse=${proxy['tls-no-session-reuse']}`,
|
||||||
|
'tls-no-session-reuse',
|
||||||
|
);
|
||||||
// tls fingerprint
|
// tls fingerprint
|
||||||
appendIfPresent(
|
appendIfPresent(
|
||||||
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
|
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
|
||||||
@@ -257,6 +314,12 @@ function vmess(proxy) {
|
|||||||
// udp
|
// udp
|
||||||
appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
||||||
|
|
||||||
|
// server_check_url
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,server_check_url=${proxy['test-url']}`,
|
||||||
|
'test-url',
|
||||||
|
);
|
||||||
|
|
||||||
// tag
|
// tag
|
||||||
append(`,tag=${proxy.name}`);
|
append(`,tag=${proxy.name}`);
|
||||||
|
|
||||||
@@ -279,6 +342,19 @@ function http(proxy) {
|
|||||||
appendIfPresent(`,over-tls=${proxy.tls}`, 'tls');
|
appendIfPresent(`,over-tls=${proxy.tls}`, 'tls');
|
||||||
|
|
||||||
if (needTls(proxy)) {
|
if (needTls(proxy)) {
|
||||||
|
appendIfPresent(
|
||||||
|
`,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`,
|
||||||
|
'tls-pubkey-sha256',
|
||||||
|
);
|
||||||
|
appendIfPresent(`,tls-alpn=${proxy['tls-alpn']}`, 'tls-alpn');
|
||||||
|
appendIfPresent(
|
||||||
|
`,tls-no-session-ticket=${proxy['tls-no-session-ticket']}`,
|
||||||
|
'tls-no-session-ticket',
|
||||||
|
);
|
||||||
|
appendIfPresent(
|
||||||
|
`,tls-no-session-reuse=${proxy['tls-no-session-reuse']}`,
|
||||||
|
'tls-no-session-reuse',
|
||||||
|
);
|
||||||
// tls fingerprint
|
// tls fingerprint
|
||||||
appendIfPresent(
|
appendIfPresent(
|
||||||
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
|
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
|
||||||
@@ -299,6 +375,12 @@ function http(proxy) {
|
|||||||
// udp
|
// udp
|
||||||
appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
||||||
|
|
||||||
|
// server_check_url
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,server_check_url=${proxy['test-url']}`,
|
||||||
|
'test-url',
|
||||||
|
);
|
||||||
|
|
||||||
// tag
|
// tag
|
||||||
append(`,tag=${proxy.name}`);
|
append(`,tag=${proxy.name}`);
|
||||||
|
|
||||||
@@ -321,6 +403,19 @@ function socks5(proxy) {
|
|||||||
appendIfPresent(`,over-tls=${proxy.tls}`, 'tls');
|
appendIfPresent(`,over-tls=${proxy.tls}`, 'tls');
|
||||||
|
|
||||||
if (needTls(proxy)) {
|
if (needTls(proxy)) {
|
||||||
|
appendIfPresent(
|
||||||
|
`,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`,
|
||||||
|
'tls-pubkey-sha256',
|
||||||
|
);
|
||||||
|
appendIfPresent(`,tls-alpn=${proxy['tls-alpn']}`, 'tls-alpn');
|
||||||
|
appendIfPresent(
|
||||||
|
`,tls-no-session-ticket=${proxy['tls-no-session-ticket']}`,
|
||||||
|
'tls-no-session-ticket',
|
||||||
|
);
|
||||||
|
appendIfPresent(
|
||||||
|
`,tls-no-session-reuse=${proxy['tls-no-session-reuse']}`,
|
||||||
|
'tls-no-session-reuse',
|
||||||
|
);
|
||||||
// tls fingerprint
|
// tls fingerprint
|
||||||
appendIfPresent(
|
appendIfPresent(
|
||||||
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
|
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
|
||||||
@@ -341,6 +436,12 @@ function socks5(proxy) {
|
|||||||
// udp
|
// udp
|
||||||
appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
|
||||||
|
|
||||||
|
// server_check_url
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,server_check_url=${proxy['test-url']}`,
|
||||||
|
'test-url',
|
||||||
|
);
|
||||||
|
|
||||||
// tag
|
// tag
|
||||||
append(`,tag=${proxy.name}`);
|
append(`,tag=${proxy.name}`);
|
||||||
|
|
||||||
|
|||||||
@@ -63,6 +63,13 @@ export default function ShadowRocket_Producer() {
|
|||||||
proxy.version = 5;
|
proxy.version = 5;
|
||||||
}
|
}
|
||||||
} else if (proxy.type === 'hysteria') {
|
} else if (proxy.type === 'hysteria') {
|
||||||
|
// auth_str 将会在未来某个时候删除 但是有的机场不规范
|
||||||
|
if (
|
||||||
|
isPresent(proxy, 'auth_str') &&
|
||||||
|
!isPresent(proxy, 'auth-str')
|
||||||
|
) {
|
||||||
|
proxy['auth-str'] = proxy['auth_str'];
|
||||||
|
}
|
||||||
if (isPresent(proxy, 'alpn')) {
|
if (isPresent(proxy, 'alpn')) {
|
||||||
proxy.alpn = Array.isArray(proxy.alpn)
|
proxy.alpn = Array.isArray(proxy.alpn)
|
||||||
? proxy.alpn
|
? proxy.alpn
|
||||||
@@ -116,6 +123,9 @@ export default function ShadowRocket_Producer() {
|
|||||||
delete proxy.tls;
|
delete proxy.tls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (proxy['tls-fingerprint']) {
|
||||||
|
proxy.fingerprint = proxy['tls-fingerprint'];
|
||||||
|
}
|
||||||
delete proxy['tls-fingerprint'];
|
delete proxy['tls-fingerprint'];
|
||||||
delete proxy.subName;
|
delete proxy.subName;
|
||||||
delete proxy.collectionName;
|
delete proxy.collectionName;
|
||||||
|
|||||||
@@ -12,13 +12,15 @@ export default function Stash_Producer() {
|
|||||||
'ss',
|
'ss',
|
||||||
'ssr',
|
'ssr',
|
||||||
'vmess',
|
'vmess',
|
||||||
'socks',
|
'socks5',
|
||||||
'http',
|
'http',
|
||||||
'snell',
|
'snell',
|
||||||
'trojan',
|
'trojan',
|
||||||
'tuic',
|
'tuic',
|
||||||
'vless',
|
'vless',
|
||||||
'wireguard',
|
'wireguard',
|
||||||
|
'hysteria',
|
||||||
|
'hysteria2',
|
||||||
].includes(proxy.type) ||
|
].includes(proxy.type) ||
|
||||||
(proxy.type === 'snell' &&
|
(proxy.type === 'snell' &&
|
||||||
String(proxy.version) === '4') ||
|
String(proxy.version) === '4') ||
|
||||||
@@ -67,6 +69,7 @@ export default function Stash_Producer() {
|
|||||||
!isPresent(proxy, 'fast-open')
|
!isPresent(proxy, 'fast-open')
|
||||||
) {
|
) {
|
||||||
proxy['fast-open'] = proxy.tfo;
|
proxy['fast-open'] = proxy.tfo;
|
||||||
|
delete proxy.tfo;
|
||||||
}
|
}
|
||||||
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/adapter/outbound/tuic.go#L197
|
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/adapter/outbound/tuic.go#L197
|
||||||
if (
|
if (
|
||||||
@@ -76,6 +79,13 @@ export default function Stash_Producer() {
|
|||||||
proxy.version = 5;
|
proxy.version = 5;
|
||||||
}
|
}
|
||||||
} else if (proxy.type === 'hysteria') {
|
} else if (proxy.type === 'hysteria') {
|
||||||
|
// auth_str 将会在未来某个时候删除 但是有的机场不规范
|
||||||
|
if (
|
||||||
|
isPresent(proxy, 'auth_str') &&
|
||||||
|
!isPresent(proxy, 'auth-str')
|
||||||
|
) {
|
||||||
|
proxy['auth-str'] = proxy['auth_str'];
|
||||||
|
}
|
||||||
if (isPresent(proxy, 'alpn')) {
|
if (isPresent(proxy, 'alpn')) {
|
||||||
proxy.alpn = Array.isArray(proxy.alpn)
|
proxy.alpn = Array.isArray(proxy.alpn)
|
||||||
? proxy.alpn
|
? proxy.alpn
|
||||||
@@ -86,6 +96,50 @@ export default function Stash_Producer() {
|
|||||||
!isPresent(proxy, 'fast-open')
|
!isPresent(proxy, 'fast-open')
|
||||||
) {
|
) {
|
||||||
proxy['fast-open'] = proxy.tfo;
|
proxy['fast-open'] = proxy.tfo;
|
||||||
|
delete proxy.tfo;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
isPresent(proxy, 'down') &&
|
||||||
|
!isPresent(proxy, 'down-speed')
|
||||||
|
) {
|
||||||
|
proxy['down-speed'] = proxy.down;
|
||||||
|
delete proxy.down;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
isPresent(proxy, 'up') &&
|
||||||
|
!isPresent(proxy, 'up-speed')
|
||||||
|
) {
|
||||||
|
proxy['up-speed'] = proxy.up;
|
||||||
|
delete proxy.up;
|
||||||
|
}
|
||||||
|
} else if (proxy.type === 'hysteria2') {
|
||||||
|
if (
|
||||||
|
isPresent(proxy, 'password') &&
|
||||||
|
!isPresent(proxy, 'auth')
|
||||||
|
) {
|
||||||
|
proxy.auth = proxy.password;
|
||||||
|
delete proxy.password;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
isPresent(proxy, 'tfo') &&
|
||||||
|
!isPresent(proxy, 'fast-open')
|
||||||
|
) {
|
||||||
|
proxy['fast-open'] = proxy.tfo;
|
||||||
|
delete proxy.tfo;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
isPresent(proxy, 'down') &&
|
||||||
|
!isPresent(proxy, 'down-speed')
|
||||||
|
) {
|
||||||
|
proxy['down-speed'] = proxy.down;
|
||||||
|
delete proxy.down;
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
isPresent(proxy, 'up') &&
|
||||||
|
!isPresent(proxy, 'up-speed')
|
||||||
|
) {
|
||||||
|
proxy['up-speed'] = proxy.up;
|
||||||
|
delete proxy.up;
|
||||||
}
|
}
|
||||||
} else if (proxy.type === 'wireguard') {
|
} else if (proxy.type === 'wireguard') {
|
||||||
proxy.keepalive =
|
proxy.keepalive =
|
||||||
@@ -127,7 +181,16 @@ export default function Stash_Producer() {
|
|||||||
) {
|
) {
|
||||||
delete proxy.tls;
|
delete proxy.tls;
|
||||||
}
|
}
|
||||||
|
if (proxy['tls-fingerprint']) {
|
||||||
|
proxy.fingerprint = proxy['tls-fingerprint'];
|
||||||
|
}
|
||||||
delete proxy['tls-fingerprint'];
|
delete proxy['tls-fingerprint'];
|
||||||
|
|
||||||
|
if (proxy['test-url']) {
|
||||||
|
proxy['benchmark-url'] = proxy['test-url'];
|
||||||
|
delete proxy['test-url'];
|
||||||
|
}
|
||||||
|
|
||||||
delete proxy.subName;
|
delete proxy.subName;
|
||||||
delete proxy.collectionName;
|
delete proxy.collectionName;
|
||||||
if (
|
if (
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ export default function Surge_Producer() {
|
|||||||
return tuic(proxy);
|
return tuic(proxy);
|
||||||
case 'wireguard-surge':
|
case 'wireguard-surge':
|
||||||
return wireguard(proxy);
|
return wireguard(proxy);
|
||||||
|
case 'hysteria2':
|
||||||
|
return hysteria2(proxy);
|
||||||
}
|
}
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`,
|
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`,
|
||||||
@@ -71,6 +73,23 @@ function shadowsocks(proxy) {
|
|||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
|
||||||
|
// shadow-tls
|
||||||
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
|
result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`);
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-version=${proxy['shadow-tls-version']}`,
|
||||||
|
'shadow-tls-version',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-sni=${proxy['shadow-tls-sni']}`,
|
||||||
|
'shadow-tls-sni',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// block-quic
|
||||||
|
result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic');
|
||||||
|
|
||||||
// underlying-proxy
|
// underlying-proxy
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
||||||
@@ -113,6 +132,23 @@ function trojan(proxy) {
|
|||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
|
||||||
|
// shadow-tls
|
||||||
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
|
result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`);
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-version=${proxy['shadow-tls-version']}`,
|
||||||
|
'shadow-tls-version',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-sni=${proxy['shadow-tls-sni']}`,
|
||||||
|
'shadow-tls-sni',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// block-quic
|
||||||
|
result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic');
|
||||||
|
|
||||||
// underlying-proxy
|
// underlying-proxy
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
||||||
@@ -162,6 +198,23 @@ function vmess(proxy) {
|
|||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
|
||||||
|
// shadow-tls
|
||||||
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
|
result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`);
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-version=${proxy['shadow-tls-version']}`,
|
||||||
|
'shadow-tls-version',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-sni=${proxy['shadow-tls-sni']}`,
|
||||||
|
'shadow-tls-sni',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// block-quic
|
||||||
|
result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic');
|
||||||
|
|
||||||
// underlying-proxy
|
// underlying-proxy
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
||||||
@@ -200,6 +253,23 @@ function http(proxy) {
|
|||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
|
||||||
|
// shadow-tls
|
||||||
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
|
result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`);
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-version=${proxy['shadow-tls-version']}`,
|
||||||
|
'shadow-tls-version',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-sni=${proxy['shadow-tls-sni']}`,
|
||||||
|
'shadow-tls-sni',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// block-quic
|
||||||
|
result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic');
|
||||||
|
|
||||||
// underlying-proxy
|
// underlying-proxy
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
||||||
@@ -240,6 +310,23 @@ function socks5(proxy) {
|
|||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
|
||||||
|
// shadow-tls
|
||||||
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
|
result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`);
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-version=${proxy['shadow-tls-version']}`,
|
||||||
|
'shadow-tls-version',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-sni=${proxy['shadow-tls-sni']}`,
|
||||||
|
'shadow-tls-sni',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// block-quic
|
||||||
|
result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic');
|
||||||
|
|
||||||
// underlying-proxy
|
// underlying-proxy
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
||||||
@@ -275,6 +362,23 @@ function snell(proxy) {
|
|||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
|
||||||
|
// shadow-tls
|
||||||
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
|
result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`);
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-version=${proxy['shadow-tls-version']}`,
|
||||||
|
'shadow-tls-version',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-sni=${proxy['shadow-tls-sni']}`,
|
||||||
|
'shadow-tls-sni',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// block-quic
|
||||||
|
result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic');
|
||||||
|
|
||||||
// underlying-proxy
|
// underlying-proxy
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
||||||
@@ -317,19 +421,47 @@ function tuic(proxy) {
|
|||||||
'skip-cert-verify',
|
'skip-cert-verify',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// tls fingerprint
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,server-cert-fingerprint-sha256=${proxy['tls-fingerprint']}`,
|
||||||
|
'tls-fingerprint',
|
||||||
|
);
|
||||||
|
|
||||||
// tfo
|
// tfo
|
||||||
result.appendIfPresent(`,tfo=${proxy['fast-open']}`, 'fast-open');
|
if (isPresent(proxy, 'tfo')) {
|
||||||
result.appendIfPresent(`,tfo=${proxy.tfo}`, 'tfo');
|
result.append(`,tfo=${proxy['tfo']}`);
|
||||||
|
} else if (isPresent(proxy, 'fast-open')) {
|
||||||
|
result.append(`,tfo=${proxy['fast-open']}`);
|
||||||
|
}
|
||||||
|
|
||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
|
||||||
|
// shadow-tls
|
||||||
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
|
result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`);
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-version=${proxy['shadow-tls-version']}`,
|
||||||
|
'shadow-tls-version',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-sni=${proxy['shadow-tls-sni']}`,
|
||||||
|
'shadow-tls-sni',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// block-quic
|
||||||
|
result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic');
|
||||||
|
|
||||||
// underlying-proxy
|
// underlying-proxy
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
||||||
'underlying-proxy',
|
'underlying-proxy',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
result.appendIfPresent(`,ecn=${proxy.ecn}`, 'ecn');
|
||||||
|
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,6 +487,23 @@ function wireguard(proxy) {
|
|||||||
// test-url
|
// test-url
|
||||||
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
|
||||||
|
// shadow-tls
|
||||||
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
|
result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`);
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-version=${proxy['shadow-tls-version']}`,
|
||||||
|
'shadow-tls-version',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-sni=${proxy['shadow-tls-sni']}`,
|
||||||
|
'shadow-tls-sni',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// block-quic
|
||||||
|
result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic');
|
||||||
|
|
||||||
// underlying-proxy
|
// underlying-proxy
|
||||||
result.appendIfPresent(
|
result.appendIfPresent(
|
||||||
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
||||||
@@ -364,6 +513,80 @@ function wireguard(proxy) {
|
|||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hysteria2(proxy) {
|
||||||
|
if (proxy.obfs || proxy['obfs-password']) {
|
||||||
|
throw new Error(`obfs is unsupported`);
|
||||||
|
}
|
||||||
|
const result = new Result(proxy);
|
||||||
|
result.append(`${proxy.name}=hysteria2,${proxy.server},${proxy.port}`);
|
||||||
|
|
||||||
|
result.appendIfPresent(`,password=${proxy.password}`, 'password');
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,ip-version=${ipVersions[proxy['ip-version']] || proxy['ip-version']}`,
|
||||||
|
'ip-version',
|
||||||
|
);
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,no-error-alert=${proxy['no-error-alert']}`,
|
||||||
|
'no-error-alert',
|
||||||
|
);
|
||||||
|
|
||||||
|
// tls verification
|
||||||
|
result.appendIfPresent(`,sni=${proxy.sni}`, 'sni');
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,skip-cert-verify=${proxy['skip-cert-verify']}`,
|
||||||
|
'skip-cert-verify',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,server-cert-fingerprint-sha256=${proxy['tls-fingerprint']}`,
|
||||||
|
'tls-fingerprint',
|
||||||
|
);
|
||||||
|
|
||||||
|
// tfo
|
||||||
|
if (isPresent(proxy, 'tfo')) {
|
||||||
|
result.append(`,tfo=${proxy['tfo']}`);
|
||||||
|
} else if (isPresent(proxy, 'fast-open')) {
|
||||||
|
result.append(`,tfo=${proxy['fast-open']}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// test-url
|
||||||
|
result.appendIfPresent(`,test-url=${proxy['test-url']}`, 'test-url');
|
||||||
|
|
||||||
|
// shadow-tls
|
||||||
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
|
result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`);
|
||||||
|
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-version=${proxy['shadow-tls-version']}`,
|
||||||
|
'shadow-tls-version',
|
||||||
|
);
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,shadow-tls-sni=${proxy['shadow-tls-sni']}`,
|
||||||
|
'shadow-tls-sni',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// block-quic
|
||||||
|
result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic');
|
||||||
|
|
||||||
|
// underlying-proxy
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,underlying-proxy=${proxy['underlying-proxy']}`,
|
||||||
|
'underlying-proxy',
|
||||||
|
);
|
||||||
|
|
||||||
|
// download-bandwidth
|
||||||
|
result.appendIfPresent(
|
||||||
|
`,download-bandwidth=${`${proxy['down']}`.match(/\d+/)?.[0] || 0}`,
|
||||||
|
'down',
|
||||||
|
);
|
||||||
|
|
||||||
|
result.appendIfPresent(`,ecn=${proxy.ecn}`, 'ecn');
|
||||||
|
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
function handleTransport(result, proxy) {
|
function handleTransport(result, proxy) {
|
||||||
if (isPresent(proxy, 'network')) {
|
if (isPresent(proxy, 'network')) {
|
||||||
if (proxy.network === 'ws') {
|
if (proxy.network === 'ws') {
|
||||||
|
|||||||
@@ -22,6 +22,16 @@ export default function register($app) {
|
|||||||
function createCollection(req, res) {
|
function createCollection(req, res) {
|
||||||
const collection = req.body;
|
const collection = req.body;
|
||||||
$.info(`正在创建组合订阅:${collection.name}`);
|
$.info(`正在创建组合订阅:${collection.name}`);
|
||||||
|
if (/\//.test(collection.name)) {
|
||||||
|
failed(
|
||||||
|
res,
|
||||||
|
new RequestInvalidError(
|
||||||
|
'INVALID_NAME',
|
||||||
|
`Collection ${collection.name} is invalid`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const allCols = $.read(COLLECTIONS_KEY);
|
const allCols = $.read(COLLECTIONS_KEY);
|
||||||
if (findByName(allCols, collection.name)) {
|
if (findByName(allCols, collection.name)) {
|
||||||
failed(
|
failed(
|
||||||
@@ -31,6 +41,7 @@ function createCollection(req, res) {
|
|||||||
`Collection ${collection.name} already exists.`,
|
`Collection ${collection.name} already exists.`,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
allCols.push(collection);
|
allCols.push(collection);
|
||||||
$.write(allCols, COLLECTIONS_KEY);
|
$.write(allCols, COLLECTIONS_KEY);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
} from './errors';
|
} from './errors';
|
||||||
import { deleteByName, findByName, updateByName } from '@/utils/database';
|
import { deleteByName, findByName, updateByName } from '@/utils/database';
|
||||||
import { SUBS_KEY, COLLECTIONS_KEY, ARTIFACTS_KEY } from '@/constants';
|
import { SUBS_KEY, COLLECTIONS_KEY, ARTIFACTS_KEY } from '@/constants';
|
||||||
import { getFlowHeaders } from '@/utils/flow';
|
import { getFlowHeaders, parseFlowHeaders } from '@/utils/flow';
|
||||||
import { success, failed } from './response';
|
import { success, failed } from './response';
|
||||||
import $ from '@/core/app';
|
import $ from '@/core/app';
|
||||||
|
|
||||||
@@ -68,20 +68,7 @@ async function getFlowInfo(req, res) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// unit is KB
|
success(res, parseFlowHeaders(flowHeaders));
|
||||||
const uploadMatch = flowHeaders.match(/upload=(-?)(\d+)/);
|
|
||||||
const upload = Number(uploadMatch[1] + uploadMatch[2]);
|
|
||||||
|
|
||||||
const downloadMatch = flowHeaders.match(/download=(-?)(\d+)/);
|
|
||||||
const download = Number(downloadMatch[1] + downloadMatch[2]);
|
|
||||||
|
|
||||||
const total = Number(flowHeaders.match(/total=(\d+)/)[1]);
|
|
||||||
|
|
||||||
// optional expire timestamp
|
|
||||||
const match = flowHeaders.match(/expire=(\d+)/);
|
|
||||||
const expires = match ? Number(match[1]) : undefined;
|
|
||||||
|
|
||||||
success(res, { expires, total, usage: { upload, download } });
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
failed(
|
failed(
|
||||||
res,
|
res,
|
||||||
@@ -96,6 +83,16 @@ async function getFlowInfo(req, res) {
|
|||||||
function createSubscription(req, res) {
|
function createSubscription(req, res) {
|
||||||
const sub = req.body;
|
const sub = req.body;
|
||||||
$.info(`正在创建订阅: ${sub.name}`);
|
$.info(`正在创建订阅: ${sub.name}`);
|
||||||
|
if (/\//.test(sub.name)) {
|
||||||
|
failed(
|
||||||
|
res,
|
||||||
|
new RequestInvalidError(
|
||||||
|
'INVALID_NAME',
|
||||||
|
`Subscription ${sub.name} is invalid`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
const allSubs = $.read(SUBS_KEY);
|
const allSubs = $.read(SUBS_KEY);
|
||||||
if (findByName(allSubs, sub.name)) {
|
if (findByName(allSubs, sub.name)) {
|
||||||
failed(
|
failed(
|
||||||
@@ -105,6 +102,7 @@ function createSubscription(req, res) {
|
|||||||
`Subscription ${sub.name} already exists.`,
|
`Subscription ${sub.name} already exists.`,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
allSubs.push(sub);
|
allSubs.push(sub);
|
||||||
$.write(allSubs, SUBS_KEY);
|
$.write(allSubs, SUBS_KEY);
|
||||||
|
|||||||
@@ -8,6 +8,25 @@ import $ from '@/core/app';
|
|||||||
const tasks = new Map();
|
const tasks = new Map();
|
||||||
|
|
||||||
export default async function download(url, ua) {
|
export default async function download(url, ua) {
|
||||||
|
let $arguments = {};
|
||||||
|
const rawArgs = url.split('#');
|
||||||
|
if (rawArgs.length > 1) {
|
||||||
|
try {
|
||||||
|
// 支持 `#${encodeURIComponent(JSON.stringify({arg1: "1"}))}`
|
||||||
|
$arguments = JSON.parse(decodeURIComponent(rawArgs[1]));
|
||||||
|
} catch (e) {
|
||||||
|
for (const pair of rawArgs[1].split('&')) {
|
||||||
|
const key = pair.split('=')[0];
|
||||||
|
const value = pair.split('=')[1];
|
||||||
|
// 部分兼容之前的逻辑 const value = pair.split('=')[1] || true;
|
||||||
|
$arguments[key] =
|
||||||
|
value == null || value === ''
|
||||||
|
? true
|
||||||
|
: decodeURIComponent(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const downloadUrlMatch = url.match(/^\/api\/(file|module)\/(.+)/);
|
const downloadUrlMatch = url.match(/^\/api\/(file|module)\/(.+)/);
|
||||||
if (downloadUrlMatch) {
|
if (downloadUrlMatch) {
|
||||||
let type = downloadUrlMatch?.[1];
|
let type = downloadUrlMatch?.[1];
|
||||||
@@ -41,7 +60,7 @@ export default async function download(url, ua) {
|
|||||||
const result = new Promise((resolve, reject) => {
|
const result = new Promise((resolve, reject) => {
|
||||||
// try to find in app cache
|
// try to find in app cache
|
||||||
const cached = resourceCache.get(id);
|
const cached = resourceCache.get(id);
|
||||||
if (cached) {
|
if (!$arguments?.noCache && cached) {
|
||||||
resolve(cached);
|
resolve(cached);
|
||||||
} else {
|
} else {
|
||||||
http.get(url)
|
http.get(url)
|
||||||
|
|||||||
@@ -13,3 +13,28 @@ export async function getFlowHeaders(url) {
|
|||||||
)[0];
|
)[0];
|
||||||
return headers[subkey];
|
return headers[subkey];
|
||||||
}
|
}
|
||||||
|
export function parseFlowHeaders(flowHeaders) {
|
||||||
|
if (!flowHeaders) return;
|
||||||
|
// unit is KB
|
||||||
|
const uploadMatch = flowHeaders.match(/upload=(-?)(\d+)/);
|
||||||
|
const upload = Number(uploadMatch[1] + uploadMatch[2]);
|
||||||
|
|
||||||
|
const downloadMatch = flowHeaders.match(/download=(-?)(\d+)/);
|
||||||
|
const download = Number(downloadMatch[1] + downloadMatch[2]);
|
||||||
|
|
||||||
|
const total = Number(flowHeaders.match(/total=(\d+)/)[1]);
|
||||||
|
|
||||||
|
// optional expire timestamp
|
||||||
|
const match = flowHeaders.match(/expire=(\d+)/);
|
||||||
|
const expires = match ? Number(match[1]) : undefined;
|
||||||
|
|
||||||
|
return { expires, total, usage: { upload, download } };
|
||||||
|
}
|
||||||
|
export function flowTransfer(flow, unit = 'B') {
|
||||||
|
const unitList = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB'];
|
||||||
|
let unitIndex = unitList.indexOf(unit);
|
||||||
|
|
||||||
|
return flow < 1024
|
||||||
|
? { value: flow.toFixed(1), unit: unit }
|
||||||
|
: flowTransfer(flow / 1024, unitList[++unitIndex]);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user