Skip to content

Commit 0883152

Browse files
committed
feat: VMess cipher 规范化
1 parent 3078e15 commit 0883152

18 files changed

Lines changed: 372 additions & 111 deletions

File tree

backend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "sub-store",
3-
"version": "2.23.34",
3+
"version": "2.23.35",
44
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and Shadowrocket.",
55
"main": "src/main.js",
66
"packageManager": "pnpm@11.0.9",

backend/src/core/proxy-utils/parsers/index.js

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
isSupportedXrayEchConfigList,
3131
isSupportedXrayEchForceQuery,
3232
} from '../ech-utils';
33+
import { normalizeVmessSecurity } from '../vmess-security';
3334

3435
function surge_port_hopping(raw) {
3536
const [parts, port_hopping] =
@@ -636,7 +637,9 @@ function URI_VMess() {
636637
type: 'vmess',
637638
server: partitions[1],
638639
port: partitions[2],
639-
cipher: getIfNotBlank(partitions[3], 'auto'),
640+
cipher: normalizeVmessSecurity(
641+
getIfNotBlank(partitions[3], 'auto'),
642+
),
640643
uuid: partitions[4].match(/^"(.*)"$/)[1],
641644
tls: params.obfs === 'wss',
642645
udp: getIfPresent(params['udp-relay']),
@@ -718,14 +721,7 @@ function URI_VMess() {
718721
port,
719722
// https://github.com/2dust/v2rayN/wiki/Description-of-VMess-share-link
720723
// https://github.com/XTLS/Xray-core/issues/91
721-
cipher: [
722-
'auto',
723-
'aes-128-gcm',
724-
'chacha20-poly1305',
725-
'none',
726-
].includes(params.scy)
727-
? params.scy
728-
: 'auto',
724+
cipher: normalizeVmessSecurity(params.scy),
729725
uuid: params.id,
730726
alterId: parseInt(
731727
getIfPresent(params.aid ?? params.alterId, 0),
@@ -2513,6 +2509,9 @@ function Clash_All() {
25132509
if (proxy['benchmark-timeout']) {
25142510
proxy['test-timeout'] = proxy['benchmark-timeout'];
25152511
}
2512+
if (proxy.type === 'vmess') {
2513+
proxy.cipher = normalizeVmessSecurity(proxy.cipher);
2514+
}
25162515

25172516
return proxy;
25182517
};

backend/src/core/proxy-utils/parsers/peggy/loon.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@ const grammars = String.raw`
3333
$set(proxy, "http-opts.headers.Host", transport.host);
3434
}
3535
}
36+
37+
function normalizeVmessSecurity(security) {
38+
const normalized = String(security || "").trim().toLowerCase();
39+
const supported = ["none", "auto", "aes-128-gcm", "chacha20-ietf-poly1305"];
40+
if (!supported.includes(normalized)) return "auto";
41+
return normalized === "chacha20-ietf-poly1305" ? "chacha20-poly1305" : normalized;
42+
}
3643
}
3744
3845
start = (shadowsocksr/shadowsocks/vmess/vless/trojan/https/http/socks5/hysteria2/anytls) {
@@ -54,9 +61,9 @@ shadowsocks = tag equals "shadowsocks"i address method password (obfs_typev obfs
5461
$set(proxy, "plugin-opts.path", obfs.path);
5562
}
5663
}
57-
vmess = tag equals "vmess"i address method uuid (transport/transport_host/transport_path/over_tls/tls_name/sni/tls_verification/tls_cert_sha256/tls_pubkey_sha256/tls_profile/vmess_alterId/fast_open/udp_relay/ip_mode/public_key/short_id/block_quic/others)* {
64+
vmess = tag equals "vmess"i address vmess_method uuid (transport/transport_host/transport_path/over_tls/tls_name/sni/tls_verification/tls_cert_sha256/tls_pubkey_sha256/tls_profile/vmess_alterId/fast_open/udp_relay/ip_mode/public_key/short_id/block_quic/others)* {
5865
proxy.type = "vmess";
59-
proxy.cipher = proxy.cipher || "none";
66+
proxy.cipher = proxy.cipher || "auto";
6067
proxy.alterId = proxy.alterId || 0;
6168
handleTransport();
6269
}
@@ -124,6 +131,9 @@ port = digits:[0-9]+ {
124131
method = comma cipher:cipher {
125132
proxy.cipher = cipher;
126133
}
134+
vmess_method = comma cipher:$[^,]+ {
135+
proxy.cipher = normalizeVmessSecurity(cipher);
136+
}
127137
cipher = ("aes-128-cfb"/"aes-128-ctr"/"aes-128-gcm"/"aes-192-cfb"/"aes-192-ctr"/"aes-192-gcm"/"aes-256-cfb"/"aes-256-ctr"/"aes-256-gcm"/"auto"/"bf-cfb"/"camellia-128-cfb"/"camellia-192-cfb"/"camellia-256-cfb"/"chacha20-ietf-poly1305"/"chacha20-ietf"/"chacha20-poly1305"/"chacha20"/"none"/"rc4-md5"/"rc4"/"salsa20"/"xchacha20-ietf-poly1305"/"2022-blake3-aes-128-gcm"/"2022-blake3-aes-256-gcm");
128138
129139
username = & {

backend/src/core/proxy-utils/parsers/peggy/surge.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,12 @@ const grammars = String.raw`
339339
});
340340
return result;
341341
}
342+
function normalizeVmessSecurity(security) {
343+
const normalized = String(security || "").trim().toLowerCase();
344+
const supported = ["aes-128-gcm", "chacha20-ietf-poly1305"];
345+
if (!supported.includes(normalized)) return "auto";
346+
return normalized === "chacha20-ietf-poly1305" ? "chacha20-poly1305" : normalized;
347+
}
342348
}
343349
344350
start = (anytls/shadowsocks/vmess/trojan/h2_connect/https/http/snell/socks5/socks5_tls/tuic/tuic_v5/wireguard/hysteria2/ssh/trust_tunnel/direct) {
@@ -356,9 +362,9 @@ shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/
356362
}
357363
handleShadowTLS();
358364
}
359-
vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/method/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls/sni/tls_fingerprint/tls_verification/client_cert/fast_open/tfo/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
365+
vmess = tag equals "vmess" address (vmess_uuid/vmess_aead/ws/ws_path/ws_headers/vmess_method/ip_version/underlying_proxy/tos/allow_other_interface/interface/test_url/test_udp/test_timeout/hybrid/no_error_alert/tls/sni/tls_fingerprint/tls_verification/client_cert/fast_open/tfo/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
360366
proxy.type = "vmess";
361-
proxy.cipher = proxy.cipher || "none";
367+
proxy.cipher = proxy.cipher || "auto";
362368
// Surfboard 与 Surge 默认不一致, 不管 Surfboard https://getsurfboard.com/docs/profile-format/proxy/external-proxy/vmess
363369
if (proxy.aead) {
364370
proxy.alterId = 0;
@@ -523,6 +529,9 @@ vmess_aead = comma "vmess-aead" equals flag:bool { proxy.aead = flag; }
523529
method = comma "encrypt-method" equals cipher:cipher {
524530
proxy.cipher = cipher;
525531
}
532+
vmess_method = comma "encrypt-method" equals cipher:$[^,]+ {
533+
proxy.cipher = normalizeVmessSecurity(cipher);
534+
}
526535
cipher = ("aes-128-cfb"/"aes-128-ctr"/"aes-128-gcm"/"aes-192-cfb"/"aes-192-ctr"/"aes-192-gcm"/"aes-256-cfb"/"aes-256-ctr"/"aes-256-gcm"/"bf-cfb"/"camellia-128-cfb"/"camellia-192-cfb"/"camellia-256-cfb"/"cast5-cfb"/"chacha20-ietf-poly1305"/"chacha20-ietf"/"chacha20-poly1305"/"chacha20"/"des-cfb"/"idea-cfb"/"none"/"rc2-cfb"/"rc4-md5"/"rc4"/"salsa20"/"seed-cfb"/"xchacha20-ietf-poly1305"/"2022-blake3-aes-128-gcm"/"2022-blake3-aes-256-gcm");
527536
528537
ws = comma "ws" equals flag:bool { obfs.type = "ws"; }

backend/src/core/proxy-utils/producers/clash.js

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {
22
isPresent,
33
produceProxyListOutput,
44
} from '@/core/proxy-utils/producers/utils';
5+
import { normalizeClashVmessSecurity } from '../vmess-security';
56
import {
67
deleteHttpUpgradeEarlyDataMetadata,
78
normalizeWebSocketEarlyDataPath,
@@ -81,17 +82,7 @@ export default function Clash_Producer() {
8182
delete proxy.sni;
8283
}
8384
// https://dreamacro.github.io/clash/configuration/outbound.html#vmess
84-
if (
85-
isPresent(proxy, 'cipher') &&
86-
![
87-
'auto',
88-
'aes-128-gcm',
89-
'chacha20-poly1305',
90-
'none',
91-
].includes(proxy.cipher)
92-
) {
93-
proxy.cipher = 'auto';
94-
}
85+
proxy.cipher = normalizeClashVmessSecurity(proxy.cipher);
9586
} else if (proxy.type === 'wireguard') {
9687
proxy.keepalive =
9788
proxy.keepalive ?? proxy['persistent-keepalive'];

backend/src/core/proxy-utils/producers/clashmeta.js

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
} from '../transport-path';
1313
import { ECH_DNS_FIELD } from '../ech-utils';
1414
import $ from '@/core/app';
15+
import { normalizeVmessSecurity } from '../vmess-security';
1516

1617
const ipVersions = {
1718
dual: 'dual',
@@ -161,18 +162,7 @@ export default function ClashMeta_Producer() {
161162
}
162163
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml#L400
163164
// https://stash.wiki/proxy-protocols/proxy-types#vmess
164-
if (
165-
isPresent(proxy, 'cipher') &&
166-
![
167-
'auto',
168-
'none',
169-
'zero',
170-
'aes-128-gcm',
171-
'chacha20-poly1305',
172-
].includes(proxy.cipher)
173-
) {
174-
proxy.cipher = 'auto';
175-
}
165+
proxy.cipher = normalizeVmessSecurity(proxy.cipher);
176166
} else if (proxy.type === 'tuic') {
177167
if (isPresent(proxy, 'alpn')) {
178168
proxy.alpn = Array.isArray(proxy.alpn)
@@ -315,9 +305,9 @@ export default function ClashMeta_Producer() {
315305
proxy['h2-opts']?.headers?.host ??
316306
proxy['h2-opts']?.headers?.Host;
317307
if (
318-
(isPresent(proxy, 'h2-opts.host') ||
319-
isPresent(proxy, 'h2-opts.headers.host') ||
320-
isPresent(proxy, 'h2-opts.headers.Host'))
308+
isPresent(proxy, 'h2-opts.host') ||
309+
isPresent(proxy, 'h2-opts.headers.host') ||
310+
isPresent(proxy, 'h2-opts.headers.Host')
321311
) {
322312
proxy['h2-opts'].host = Array.isArray(host)
323313
? host

backend/src/core/proxy-utils/producers/egern.js

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
isPresent,
55
produceProxyListOutput,
66
} from './utils';
7+
import { normalizeVmessSecurity } from '../vmess-security';
78

89
export default function Egern_Producer() {
910
const type = 'ALL';
@@ -272,19 +273,7 @@ export default function Egern_Producer() {
272273
};
273274
} else if (proxy.type === 'vmess') {
274275
// Egern:传输层,支持 ws/wss/http1/http2/tls,不配置则为 tcp
275-
let security = proxy.cipher;
276-
if (
277-
security &&
278-
![
279-
'auto',
280-
'none',
281-
'zero',
282-
'aes-128-gcm',
283-
'chacha20-poly1305',
284-
].includes(security)
285-
) {
286-
security = 'auto';
287-
}
276+
const security = normalizeVmessSecurity(proxy.cipher);
288277
if (proxy.network === 'ws') {
289278
proxy.transport = {
290279
[proxy.tls ? 'wss' : 'ws']: {

backend/src/core/proxy-utils/producers/loon.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const targetPlatform = 'Loon';
33
import { isPresent, Result } from './utils';
44
import { isIPv4, isIPv6 } from '@/utils';
55
import $ from '@/core/app';
6+
import { formatLoonVmessSecurity } from '../vmess-security';
67

78
const ipVersions = {
89
dual: 'dual',
@@ -405,10 +406,11 @@ function anytls(proxy) {
405406

406407
function vmess(proxy) {
407408
const isReality = !!proxy['reality-opts'];
409+
const security = formatLoonVmessSecurity(proxy.cipher);
408410

409411
const result = new Result(proxy);
410412
result.append(
411-
`${proxy.name}=vmess,${proxy.server},${proxy.port},${proxy.cipher},"${proxy.uuid}"`,
413+
`${proxy.name}=vmess,${proxy.server},${proxy.port},${security},"${proxy.uuid}"`,
412414
);
413415
if (proxy.network === 'tcp') {
414416
delete proxy.network;

backend/src/core/proxy-utils/producers/qx.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { isPresent, isShadowsocksOverTls, Result } from './utils';
2+
import { formatQXVmessMethod } from '../vmess-security';
23

34
const targetPlatform = 'QX';
45

@@ -333,12 +334,7 @@ function vmess(proxy) {
333334
append(`vmess=${proxy.server}:${proxy.port}`);
334335

335336
// cipher
336-
let cipher;
337-
if (proxy.cipher === 'auto') {
338-
cipher = 'chacha20-ietf-poly1305';
339-
} else {
340-
cipher = proxy.cipher;
341-
}
337+
let cipher = formatQXVmessMethod(proxy.cipher);
342338
append(`,method=${cipher}`);
343339

344340
append(`,password=${proxy.uuid}`);

backend/src/core/proxy-utils/producers/shadowrocket.js

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
normalizeWebSocketEarlyDataPath,
1111
} from '../transport-path';
1212
import $ from '@/core/app';
13+
import { normalizeVmessSecurity } from '../vmess-security';
1314

1415
export default function Shadowrocket_Producer() {
1516
const type = 'ALL';
@@ -63,18 +64,7 @@ export default function Shadowrocket_Producer() {
6364
}
6465
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml#L400
6566
// https://stash.wiki/proxy-protocols/proxy-types#vmess
66-
if (
67-
isPresent(proxy, 'cipher') &&
68-
![
69-
'auto',
70-
'none',
71-
'zero',
72-
'aes-128-gcm',
73-
'chacha20-poly1305',
74-
].includes(proxy.cipher)
75-
) {
76-
proxy.cipher = 'auto';
77-
}
67+
proxy.cipher = normalizeVmessSecurity(proxy.cipher);
7868
} else if (proxy.type === 'tuic') {
7969
if (isPresent(proxy, 'alpn')) {
8070
proxy.alpn = Array.isArray(proxy.alpn)

0 commit comments

Comments
 (0)