Compare commits

...

6 Commits

Author SHA1 Message Date
xream
af9a2c86c1 fix: 修复 Surge/Loon VMess aead 2025-05-12 12:26:14 +08:00
xream
98892fa100 fix: 修复 QX VMess aead 2025-05-12 11:06:13 +08:00
xream
6e2411e2c2 doc: demo.js 2025-05-12 01:42:42 +08:00
xream
b3f6876bbd feat: 兼容 xishang0128/sparkle 的 JavaScript 覆写; ProxyUtils 新增 Buffer, Base64 2025-05-11 16:21:28 +08:00
xream
d2c3956884 feat: QX 正式支持 SS2022 2025-05-07 02:59:19 +08:00
xream
21c1e11976 feat: 兼容非标 Shadowsocks URI 输入 2025-04-28 13:55:15 +08:00
12 changed files with 41 additions and 16 deletions

View File

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

View File

@@ -1,3 +1,4 @@
import { Base64 } from 'js-base64';
import { Buffer } from 'buffer';
import rs from '@/utils/rs';
import YAML from '@/utils/yaml';
@@ -333,6 +334,8 @@ export const ProxyUtils = {
downloadFile,
isValidUUID,
doh,
Buffer,
Base64,
};
function tryParse(parser, line) {

View File

@@ -134,7 +134,7 @@ function URI_SS() {
};
content = content.split('#')[0]; // strip proxy name
// handle IPV4 and IPV6
let serverAndPortArray = content.match(/@([^/]*)(\/|$)/);
let serverAndPortArray = content.match(/@([^/?]*)(\/|\?|$)/);
let rawUserInfoStr = decodeURIComponent(content.split('@')[0]); // 其实应该分隔之后, 用户名和密码再 decodeURIComponent. 但是问题不大
let userInfoStr;

View File

@@ -86,10 +86,10 @@ vmess = "vmess" equals address
(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.cipher = proxy.cipher || "none";
if (proxy.aead) {
proxy.alterId = 0;
if (proxy.aead === false) {
proxy.alterId = 1;
} else {
proxy.alterId = proxy.alterId || 0;
proxy.alterId = 0;
}
handleObfs();
}

View File

@@ -84,10 +84,10 @@ vmess = "vmess" equals address
(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.cipher = proxy.cipher || "none";
if (proxy.aead) {
proxy.alterId = 0;
if (proxy.aead === false) {
proxy.alterId = 1;
} else {
proxy.alterId = proxy.alterId || 0;
proxy.alterId = 0;
}
handleObfs();
}

View File

@@ -55,10 +55,11 @@ shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/
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/fast_open/tfo/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
proxy.type = "vmess";
proxy.cipher = proxy.cipher || "none";
// Surfboard 与 Surge 默认不一致, 不管 Surfboard https://getsurfboard.com/docs/profile-format/proxy/external-proxy/vmess
if (proxy.aead) {
proxy.alterId = 0;
} else {
proxy.alterId = proxy.alterId || 0;
proxy.alterId = 1;
}
handleWebsocket();
handleShadowTLS();

View File

@@ -53,10 +53,11 @@ shadowsocks = tag equals "ss" address (method/passwordk/obfs/obfs_host/obfs_uri/
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/fast_open/tfo/udp_relay/shadow_tls_version/shadow_tls_sni/shadow_tls_password/block_quic/others)* {
proxy.type = "vmess";
proxy.cipher = proxy.cipher || "none";
// Surfboard 与 Surge 默认不一致, 不管 Surfboard https://getsurfboard.com/docs/profile-format/proxy/external-proxy/vmess
if (proxy.aead) {
proxy.alterId = 0;
} else {
proxy.alterId = proxy.alterId || 0;
proxy.alterId = 1;
}
handleWebsocket();
handleShadowTLS();

View File

@@ -1141,6 +1141,10 @@ function createDynamicFunction(name, script, $arguments, $options) {
'$httpClient',
'$notification',
'ProxyUtils',
'yaml',
'Buffer',
'b64d',
'b64e',
'scriptResourceCache',
'flowUtils',
'produceArtifact',
@@ -1158,6 +1162,10 @@ function createDynamicFunction(name, script, $arguments, $options) {
// eslint-disable-next-line no-undef
$notification,
ProxyUtils,
ProxyUtils.yaml,
ProxyUtils.Buffer,
ProxyUtils.Base64.decode,
ProxyUtils.Base64.encode,
scriptResourceCache,
flowUtils,
produceArtifact,
@@ -1170,6 +1178,10 @@ function createDynamicFunction(name, script, $arguments, $options) {
'$substore',
'lodash',
'ProxyUtils',
'yaml',
'Buffer',
'b64d',
'b64e',
'scriptResourceCache',
'flowUtils',
'produceArtifact',
@@ -1181,6 +1193,10 @@ function createDynamicFunction(name, script, $arguments, $options) {
$,
lodash,
ProxyUtils,
ProxyUtils.yaml,
ProxyUtils.Buffer,
ProxyUtils.Base64.decode,
ProxyUtils.Base64.encode,
scriptResourceCache,
flowUtils,
produceArtifact,

View File

@@ -365,7 +365,7 @@ function vmess(proxy) {
// AEAD
if (isPresent(proxy, 'aead')) {
result.append(`,alterId=0`);
result.append(`,alterId=${proxy.aead ? 0 : 1}`);
} else {
result.append(`,alterId=${proxy.alterId}`);
}

View File

@@ -7,7 +7,7 @@ export default function QX_Producer() {
const produce = (proxy, type, opts = {}) => {
switch (proxy.type) {
case 'ss':
return shadowsocks(proxy, opts['include-unsupported-proxy']);
return shadowsocks(proxy);
case 'ssr':
return shadowsocksr(proxy);
case 'trojan':
@@ -28,7 +28,7 @@ export default function QX_Producer() {
return { produce };
}
function shadowsocks(proxy, includeUnsupportedProxy) {
function shadowsocks(proxy) {
const result = new Result(proxy);
const append = result.append.bind(result);
const appendIfPresent = result.appendIfPresent.bind(result);
@@ -58,9 +58,8 @@ function shadowsocks(proxy, includeUnsupportedProxy) {
'aes-256-gcm',
'chacha20-ietf-poly1305',
'xchacha20-ietf-poly1305',
...(includeUnsupportedProxy
? ['2022-blake3-aes-128-gcm', '2022-blake3-aes-256-gcm']
: []),
'2022-blake3-aes-128-gcm',
'2022-blake3-aes-256-gcm',
].includes(proxy.cipher)
) {
throw new Error(`cipher ${proxy.cipher} is not supported`);

View File

@@ -34,4 +34,6 @@ export default {
load,
safeDump,
dump,
parse: safeLoad,
stringify: safeDump,
};

View File

@@ -120,7 +120,10 @@ function operator(proxies = [], targetPlatform, context) {
// downloadFile, // 下载二进制文件, 见 backend/src/utils/download.js
// MMDB, // Node.js 环境 可用于模拟 Surge/Loon 的 $utils.ipasn, $utils.ipaso, $utils.geoip. 具体见 https://t.me/zhetengsha/1269
// isValidUUID, // 辅助判断是否为有效的 UUID
// Buffer, // https://github.com/feross/buffer
// Base64, // https://github.com/dankogai/js-base64
// }
// 为兼容 https://github.com/xishang0128/sparkle 的 JavaScript 覆写, 也可以直接使用 `b64d`(Base64 解码), `b64e`(Base64 编码), `Buffer`, `yaml`(简单兼容了下 `yaml.parse` 和 `yaml.stringify`)
// 如果只是为了快速修改或者筛选 可以参考 脚本操作支持节点快捷脚本 https://t.me/zhetengsha/970 和 脚本筛选支持节点快捷脚本 https://t.me/zhetengsha/1009
// ⚠️ 注意: 函数式(即本文件这样的 function operator() {}) 和快捷操作(下面使用 $server) 只能二选一