Compare commits

...

6 Commits

Author SHA1 Message Date
xream
d255390d48 fix: 修复 Surge shadow-tls-password 引号解析
Some checks are pending
build / build (push) Waiting to run
2025-03-04 22:36:47 +08:00
xream
72c7f4333a feat: SurgeMac mihomo 配置中支持自定义 DNS 2025-03-04 20:11:22 +08:00
xream
f35837ff9f feat: 支持 AnyTLS URI
Some checks are pending
build / build (push) Waiting to run
2025-03-03 20:52:31 +08:00
xream
c2c39c5de6 fix: 修复 Egern 输出
Some checks are pending
build / build (push) Waiting to run
2025-03-03 10:42:44 +08:00
xream
87a4b14ae2 feat(wip): 本地脚本支持传入参数 2025-03-02 19:02:15 +08:00
xream
ff1dacda87 区域过滤和协议过滤支持保留模式和过滤模式(后端需 >= 2.17.0, 前端需 >= 2.15.0)
Some checks are pending
build / build (push) Waiting to run
2025-03-02 11:06:33 +08:00
10 changed files with 138 additions and 19 deletions

View File

@@ -32,14 +32,14 @@ Core functionalities:
example: `socks5+tls://user:pass@ip:port#name`
- [x] URI(SOCKS, SS, SSR, VMess, VLESS, Trojan, Hysteria, Hysteria 2, TUIC v5, WireGuard)
- [x] URI(AnyTLS, SOCKS, SS, SSR, VMess, VLESS, Trojan, Hysteria, Hysteria 2, TUIC v5, WireGuard)
- [x] Clash Proxies YAML
- [x] Clash Proxy JSON(single line)
- [x] QX (SS, SSR, VMess, Trojan, HTTP, SOCKS5, VLESS)
- [x] Loon (SS, SSR, VMess, Trojan, HTTP, SOCKS5, SOCKS5-TLS, WireGuard, VLESS, Hysteria 2)
- [x] Surge (Direct, SS, VMess, Trojan, HTTP, SOCKS5, SOCKS5-TLS, TUIC, Snell, Hysteria 2, SSH(Password authentication only), External Proxy Program(only for macOS), WireGuard(Surge to Surge))
- [x] Surfboard (SS, VMess, Trojan, HTTP, SOCKS5, SOCKS5-TLS, WireGuard(Surfboard to Surfboard))
- [x] Clash.Meta (Direct, SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard, Hysteria, Hysteria 2, TUIC, SSH, mieru)
- [x] Clash.Meta (Direct, SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard, Hysteria, Hysteria 2, TUIC, SSH, mieru, AnyTLS)
- [x] Stash (SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard, Hysteria, TUIC, Juicity, SSH)
- [x] Clash (SS, SSR, VMess, Trojan, HTTP, SOCKS5, Snell, VLESS, WireGuard)

View File

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

View File

@@ -185,6 +185,7 @@ async function processFn(
}
} else {
script = content;
$arguments = item.args.arguments || {};
}
}

View File

@@ -699,6 +699,52 @@ function URI_VLESS() {
};
return { name, test, parse };
}
function URI_AnyTLS() {
const name = 'URI AnyTLS Parser';
const test = (line) => {
return /^anytls:\/\//.test(line);
};
const parse = (line) => {
line = line.split(/anytls:\/\//)[1];
// eslint-disable-next-line no-unused-vars
let [__, password, server, port, addons = '', name] =
/^(.*?)@(.*?)(?::(\d+))?\/?(?:\?(.*?))?(?:#(.*?))?$/.exec(line);
password = decodeURIComponent(password);
port = parseInt(`${port}`, 10);
if (isNaN(port)) {
port = 443;
}
password = decodeURIComponent(password);
if (name != null) {
name = decodeURIComponent(name);
}
name = name ?? `AnyTLS ${server}:${port}`;
const proxy = {
type: 'anytls',
name,
server,
port,
password,
};
for (const addon of addons.split('&')) {
let [key, value] = addon.split('=');
key = key.replace(/_/g, '-');
value = decodeURIComponent(value);
if (['alpn'].includes(key)) {
proxy[key] = value ? value.split(',') : undefined;
} else if (['insecure'].includes(key)) {
proxy['skip-cert-verify'] = /(TRUE)|1/i.test(value);
} else {
proxy[key] = value;
}
}
return proxy;
};
return { name, test, parse };
}
function URI_Hysteria2() {
const name = 'URI Hysteria2 Parser';
const test = (line) => {
@@ -1544,6 +1590,7 @@ export default [
URI_Hysteria(),
URI_Hysteria2(),
URI_Trojan(),
URI_AnyTLS(),
Clash_All(),
Surge_Direct(),
Surge_SSH(),

View File

@@ -246,7 +246,7 @@ block_quic = comma "block-quic" equals match:[^,]+ { proxy["block-quic"] = match
udp_port = comma "udp-port" equals match:$[0-9]+ { proxy["udp-port"] = parseInt(match.trim()); }
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(""); }
shadow_tls_password = comma "shadow-tls-password" equals match:[^,]+ { proxy["shadow-tls-password"] = match.join("").replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1'); }
token = comma "token" equals match:[^,]+ { proxy.token = match.join(""); }
alpn = comma "alpn" equals match:[^,]+ { proxy.alpn = match.join(""); }
uuidk = comma "uuid" equals match:[^,]+ { proxy.uuid = match.join(""); }

View File

@@ -243,7 +243,7 @@ block_quic = comma "block-quic" equals match:[^,]+ { proxy["block-quic"] = match
udp_port = comma "udp-port" equals match:$[0-9]+ { proxy["udp-port"] = parseInt(match.trim()); }
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(""); }
shadow_tls_password = comma "shadow-tls-password" equals match:[^,]+ { proxy["shadow-tls-password"] = match.join("").replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1'); }
token = comma "token" equals match:[^,]+ { proxy.token = match.join(""); }
alpn = comma "alpn" equals match:[^,]+ { proxy.alpn = match.join(""); }
uuidk = comma "uuid" equals match:[^,]+ { proxy.uuid = match.join(""); }

View File

@@ -849,7 +849,12 @@ function UselessFilter() {
}
// filter by regions
function RegionFilter(regions) {
function RegionFilter(input) {
let regions = input?.value || input;
if (!Array.isArray(regions)) {
regions = [];
}
const keep = input?.keep ?? true;
const REGION_MAP = {
HK: '🇭🇰',
TW: '🇹🇼',
@@ -866,7 +871,8 @@ function RegionFilter(regions) {
// this would be high memory usage
return proxies.map((proxy) => {
const flag = getFlag(proxy.name);
return regions.some((r) => REGION_MAP[r] === flag);
const selected = regions.some((r) => REGION_MAP[r] === flag);
return keep ? selected : !selected;
});
},
};
@@ -898,11 +904,19 @@ function buildRegex(str, ...options) {
}
// filter by proxy types
function TypeFilter(types) {
function TypeFilter(input) {
let types = input?.value || input;
if (!Array.isArray(types)) {
types = [];
}
const keep = input?.keep ?? true;
return {
name: 'Type Filter',
func: (proxies) => {
return proxies.map((proxy) => types.some((t) => proxy.type === t));
return proxies.map((proxy) => {
const selected = types.some((t) => proxy.type === t);
return keep ? selected : !selected;
});
},
};
}

View File

@@ -123,10 +123,10 @@ export default function Egern_Producer() {
proxy.udp || proxy.udp_relay || proxy.udp_relay,
next_hop: proxy.next_hop,
};
if (proxy.plugin === 'obfs') {
proxy.obfs = proxy['plugin-opts'].mode;
proxy.obfs_host = proxy['plugin-opts'].host;
proxy.obfs_uri = proxy['plugin-opts'].path;
if (original.plugin === 'obfs') {
proxy.obfs = original['plugin-opts'].mode;
proxy.obfs_host = original['plugin-opts'].host;
proxy.obfs_uri = original['plugin-opts'].path;
}
} else if (proxy.type === 'hysteria2') {
proxy = {
@@ -144,9 +144,12 @@ export default function Egern_Producer() {
port_hopping: proxy.ports,
port_hopping_interval: proxy['hop-interval'],
};
if (proxy['obfs-password'] && proxy.obfs == 'salamander') {
if (
original['obfs-password'] &&
original.obfs == 'salamander'
) {
proxy.obfs = 'salamander';
proxy.obfs_password = proxy['obfs-password'];
proxy.obfs_password = original['obfs-password'];
}
} else if (proxy.type === 'tuic') {
proxy = {

View File

@@ -141,10 +141,19 @@ function mihomo(proxy, type, opts) {
dns: {
enable: true,
ipv6,
nameserver: [
'https://223.6.6.6/dns-query',
'https://120.53.53.53/dns-query',
],
'default-nameserver': opts?.defaultNameserver ||
proxy._defaultNameserver || [
'180.76.76.76',
'52.80.52.52',
'119.28.28.28',
'223.6.6.6',
],
nameserver: opts?.nameserver ||
proxy._nameserver || [
'https://doh.pub/dns-query',
'https://dns.alidns.com/dns-query',
'https://doh-pure.onedns.net/dns-query',
],
},
proxies: [
{

View File

@@ -493,6 +493,7 @@ export default function URI_Producer() {
'password',
'server',
'port',
'tls',
].includes(key)
) {
const i = key.replace(/-/, '_');
@@ -542,6 +543,50 @@ export default function URI_Producer() {
)}`;
}
break;
case 'anytls':
let anytlsParams = [];
Object.keys(proxy).forEach((key) => {
if (
![
'name',
'type',
'password',
'server',
'port',
'tls',
].includes(key)
) {
const i = key.replace(/-/, '_');
if (['alpn'].includes(key)) {
if (proxy[key]) {
anytlsParams.push(
`${i}=${encodeURIComponent(
Array.isArray(proxy[key])
? proxy[key][0]
: proxy[key],
)}`,
);
}
} else if (['skip-cert-verify'].includes(key)) {
if (proxy[key]) {
anytlsParams.push(`insecure=1`);
}
} else if (proxy[key]) {
anytlsParams.push(
`${i.replace(/-/g, '_')}=${encodeURIComponent(
proxy[key],
)}`,
);
}
}
});
result = `anytls://${encodeURIComponent(proxy.password)}@${
proxy.server
}:${proxy.port}/?${anytlsParams.join('&')}#${encodeURIComponent(
proxy.name,
)}`;
break;
case 'wireguard':
let wireguardParams = [];