mirror of
https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-10 00:52:40 +00:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76e12bd6a0 | ||
|
|
3a33446422 | ||
|
|
17b12711b4 | ||
|
|
c266635ba1 | ||
|
|
f34eac9568 | ||
|
|
aa5b51a3cc | ||
|
|
b8897dd94a | ||
|
|
71958e6bb1 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sub-store",
|
||||
"version": "2.19.67",
|
||||
"version": "2.19.74",
|
||||
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and Shadowrocket.",
|
||||
"main": "src/main.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -12,6 +12,7 @@ import getLoonParser from './peggy/loon';
|
||||
import getQXParser from './peggy/qx';
|
||||
import getTrojanURIParser from './peggy/trojan-uri';
|
||||
import $ from '@/core/app';
|
||||
import JSON5 from 'json5';
|
||||
|
||||
import { Base64 } from 'js-base64';
|
||||
|
||||
@@ -1130,14 +1131,14 @@ function Clash_All() {
|
||||
const name = 'Clash Parser';
|
||||
const test = (line) => {
|
||||
try {
|
||||
JSON.parse(line);
|
||||
JSON5.parse(line);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
const parse = (line) => {
|
||||
const proxy = JSON.parse(line);
|
||||
const proxy = JSON5.parse(line);
|
||||
if (
|
||||
![
|
||||
'anytls',
|
||||
|
||||
@@ -179,8 +179,8 @@ username = & {
|
||||
peg$currPos = end;
|
||||
return true;
|
||||
}
|
||||
} { proxy.username = $.username; }
|
||||
password = comma match:[^,]+ { proxy.password = match.join("").replace(/^"(.*)"$/, '$1'); }
|
||||
} { proxy.username = $.username.trim().replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1'); }
|
||||
password = comma match:[^,]+ { proxy.password = match.join("").replace(/^"(.*)"$/, '$1').replace(/^'(.*?)'$/, '$1'); }
|
||||
|
||||
tls = comma "tls" equals flag:bool { proxy.tls = flag; }
|
||||
sni = comma "sni" equals sni:("off"/domain) {
|
||||
@@ -196,7 +196,7 @@ tls_fingerprint = comma "server-cert-fingerprint-sha256" equals tls_fingerprint:
|
||||
snell_psk = comma "psk" equals match:[^,]+ { proxy.psk = match.join(""); }
|
||||
snell_version = comma "version" equals match:$[0-9]+ { proxy.version = parseInt(match.trim()); }
|
||||
|
||||
usernamek = comma "username" equals match:[^,]+ { proxy.username = match.join(""); }
|
||||
usernamek = comma "username" equals match:[^,]+ { proxy.username = match.join("").replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1'); }
|
||||
passwordk = comma "password" equals match:[^,]+ { proxy.password = match.join("").replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1'); }
|
||||
vmess_uuid = comma "username" equals match:[^,]+ { proxy.uuid = match.join(""); }
|
||||
vmess_aead = comma "vmess-aead" equals flag:bool { proxy.aead = flag; }
|
||||
|
||||
@@ -176,8 +176,8 @@ username = & {
|
||||
peg$currPos = end;
|
||||
return true;
|
||||
}
|
||||
} { proxy.username = $.username; }
|
||||
password = comma match:[^,]+ { proxy.password = match.join("").replace(/^"(.*)"$/, '$1'); }
|
||||
} { proxy.username = $.username.trim().replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1'); }
|
||||
password = comma match:[^,]+ { proxy.password = match.join("").replace(/^"(.*)"$/, '$1').replace(/^'(.*?)'$/, '$1'); }
|
||||
|
||||
tls = comma "tls" equals flag:bool { proxy.tls = flag; }
|
||||
sni = comma "sni" equals sni:("off"/domain) {
|
||||
@@ -193,7 +193,7 @@ tls_fingerprint = comma "server-cert-fingerprint-sha256" equals tls_fingerprint:
|
||||
snell_psk = comma "psk" equals match:[^,]+ { proxy.psk = match.join(""); }
|
||||
snell_version = comma "version" equals match:$[0-9]+ { proxy.version = parseInt(match.trim()); }
|
||||
|
||||
usernamek = comma "username" equals match:[^,]+ { proxy.username = match.join(""); }
|
||||
usernamek = comma "username" equals match:[^,]+ { proxy.username = match.join("").replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1'); }
|
||||
passwordk = comma "password" equals match:[^,]+ { proxy.password = match.join("").replace(/^"(.*?)"$/, '$1').replace(/^'(.*?)'$/, '$1'); }
|
||||
vmess_uuid = comma "username" equals match:[^,]+ { proxy.uuid = match.join(""); }
|
||||
vmess_aead = comma "vmess-aead" equals flag:bool { proxy.aead = flag; }
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
import { isPresent } from '@/core/proxy-utils/producers/utils';
|
||||
|
||||
const ipVersions = {
|
||||
dual: 'dual',
|
||||
'v4-only': 'ipv4',
|
||||
'v6-only': 'ipv6',
|
||||
'prefer-v4': 'ipv4-prefer',
|
||||
'prefer-v6': 'ipv6-prefer',
|
||||
};
|
||||
|
||||
export default function ClashMeta_Producer() {
|
||||
const type = 'ALL';
|
||||
const produce = (proxies, type, opts = {}) => {
|
||||
@@ -242,6 +250,11 @@ export default function ClashMeta_Producer() {
|
||||
delete proxy[`${proxy.network}-opts`]['_grpc-type'];
|
||||
delete proxy[`${proxy.network}-opts`]['_grpc-authority'];
|
||||
}
|
||||
|
||||
if (proxy['ip-version']) {
|
||||
proxy['ip-version'] =
|
||||
ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||
}
|
||||
return proxy;
|
||||
});
|
||||
|
||||
|
||||
@@ -377,6 +377,23 @@ export default function Egern_Producer() {
|
||||
delete proxy.id;
|
||||
delete proxy.resolved;
|
||||
delete proxy['no-resolve'];
|
||||
|
||||
if (proxy.transport) {
|
||||
for (const key in proxy.transport) {
|
||||
if (
|
||||
Object.keys(proxy.transport[key]).length === 0 ||
|
||||
Object.values(proxy.transport[key]).every(
|
||||
(v) => v == null,
|
||||
)
|
||||
) {
|
||||
delete proxy.transport[key];
|
||||
}
|
||||
}
|
||||
if (Object.keys(proxy.transport).length === 0) {
|
||||
delete proxy.transport;
|
||||
}
|
||||
}
|
||||
|
||||
if (type !== 'internal') {
|
||||
for (const key in proxy) {
|
||||
if (proxy[key] == null || /^_/i.test(key)) {
|
||||
|
||||
@@ -2,6 +2,26 @@ import ClashMeta_Producer from './clashmeta';
|
||||
import $ from '@/core/app';
|
||||
import { isIPv4, isIPv6 } from '@/utils';
|
||||
|
||||
const ipVersions = {
|
||||
ipv4: 'ipv4_only',
|
||||
ipv6: 'ipv6_only',
|
||||
'v4-only': 'ipv4_only',
|
||||
'v6-only': 'ipv6_only',
|
||||
'ipv4-prefer': 'prefer_ipv4',
|
||||
'ipv6-prefer': 'prefer_ipv6',
|
||||
'prefer-v4': 'prefer_ipv4',
|
||||
'prefer-v6': 'prefer_ipv6',
|
||||
};
|
||||
|
||||
const ipVersionParser = (proxy, parsedProxy) => {
|
||||
const strategy = ipVersions[proxy['ip-version']];
|
||||
if (proxy._dns_server && strategy) {
|
||||
parsedProxy.domain_resolver = {
|
||||
server: proxy._dns_server,
|
||||
strategy,
|
||||
};
|
||||
}
|
||||
};
|
||||
const detourParser = (proxy, parsedProxy) => {
|
||||
parsedProxy.detour = proxy['dialer-proxy'] || proxy.detour;
|
||||
};
|
||||
@@ -278,6 +298,7 @@ const sshParser = (proxy = {}) => {
|
||||
if (proxy['fast-open']) parsedProxy.udp_fragment = true;
|
||||
tfoParser(proxy, parsedProxy);
|
||||
detourParser(proxy, parsedProxy);
|
||||
ipVersionParser(proxy, parsedProxy);
|
||||
return parsedProxy;
|
||||
};
|
||||
|
||||
@@ -305,6 +326,7 @@ const httpParser = (proxy = {}) => {
|
||||
tfoParser(proxy, parsedProxy);
|
||||
detourParser(proxy, parsedProxy);
|
||||
tlsParser(proxy, parsedProxy);
|
||||
ipVersionParser(proxy, parsedProxy);
|
||||
return parsedProxy;
|
||||
};
|
||||
|
||||
@@ -327,6 +349,7 @@ const socks5Parser = (proxy = {}) => {
|
||||
networkParser(proxy, parsedProxy);
|
||||
tfoParser(proxy, parsedProxy);
|
||||
detourParser(proxy, parsedProxy);
|
||||
ipVersionParser(proxy, parsedProxy);
|
||||
return parsedProxy;
|
||||
};
|
||||
|
||||
@@ -338,6 +361,17 @@ const shadowTLSParser = (proxy = {}) => {
|
||||
password: proxy.password,
|
||||
detour: `${proxy.name}_shadowtls`,
|
||||
};
|
||||
if (proxy.uot) ssPart.udp_over_tcp = true;
|
||||
if (proxy['udp-over-tcp']) {
|
||||
ssPart.udp_over_tcp = {
|
||||
enabled: true,
|
||||
version:
|
||||
!proxy['udp-over-tcp-version'] ||
|
||||
proxy['udp-over-tcp-version'] === 1
|
||||
? 1
|
||||
: 2,
|
||||
};
|
||||
}
|
||||
const stPart = {
|
||||
tag: `${proxy.name}_shadowtls`,
|
||||
type: 'shadowtls',
|
||||
@@ -360,6 +394,7 @@ const shadowTLSParser = (proxy = {}) => {
|
||||
tfoParser(proxy, stPart);
|
||||
detourParser(proxy, stPart);
|
||||
smuxParser(proxy.smux, ssPart);
|
||||
ipVersionParser(proxy, stPart);
|
||||
return { type: 'ss-with-st', ssPart, stPart };
|
||||
};
|
||||
const ssParser = (proxy = {}) => {
|
||||
@@ -389,6 +424,7 @@ const ssParser = (proxy = {}) => {
|
||||
tfoParser(proxy, parsedProxy);
|
||||
detourParser(proxy, parsedProxy);
|
||||
smuxParser(proxy.smux, parsedProxy);
|
||||
ipVersionParser(proxy, parsedProxy);
|
||||
if (proxy.plugin) {
|
||||
const optArr = [];
|
||||
if (proxy.plugin === 'obfs') {
|
||||
@@ -467,6 +503,7 @@ const ssrParser = (proxy = {}) => {
|
||||
tfoParser(proxy, parsedProxy);
|
||||
detourParser(proxy, parsedProxy);
|
||||
smuxParser(proxy.smux, parsedProxy);
|
||||
ipVersionParser(proxy, parsedProxy);
|
||||
return parsedProxy;
|
||||
};
|
||||
|
||||
@@ -505,6 +542,7 @@ const vmessParser = (proxy = {}) => {
|
||||
detourParser(proxy, parsedProxy);
|
||||
tlsParser(proxy, parsedProxy);
|
||||
smuxParser(proxy.smux, parsedProxy);
|
||||
ipVersionParser(proxy, parsedProxy);
|
||||
return parsedProxy;
|
||||
};
|
||||
|
||||
@@ -521,7 +559,8 @@ const vlessParser = (proxy = {}) => {
|
||||
throw 'invalid port';
|
||||
if (proxy.xudp) parsedProxy.packet_encoding = 'xudp';
|
||||
if (proxy['fast-open']) parsedProxy.udp_fragment = true;
|
||||
if (proxy.flow === 'xtls-rprx-vision') parsedProxy.flow = proxy.flow;
|
||||
// if (['xtls-rprx-vision', ''].includes(proxy.flow)) parsedProxy.flow = proxy.flow;
|
||||
if (proxy.flow != null) parsedProxy.flow = proxy.flow;
|
||||
if (proxy.network === 'ws') wsParser(proxy, parsedProxy);
|
||||
if (proxy.network === 'grpc') grpcParser(proxy, parsedProxy);
|
||||
networkParser(proxy, parsedProxy);
|
||||
@@ -529,6 +568,7 @@ const vlessParser = (proxy = {}) => {
|
||||
detourParser(proxy, parsedProxy);
|
||||
smuxParser(proxy.smux, parsedProxy);
|
||||
tlsParser(proxy, parsedProxy);
|
||||
ipVersionParser(proxy, parsedProxy);
|
||||
return parsedProxy;
|
||||
};
|
||||
const trojanParser = (proxy = {}) => {
|
||||
@@ -550,6 +590,7 @@ const trojanParser = (proxy = {}) => {
|
||||
detourParser(proxy, parsedProxy);
|
||||
tlsParser(proxy, parsedProxy);
|
||||
smuxParser(proxy.smux, parsedProxy);
|
||||
ipVersionParser(proxy, parsedProxy);
|
||||
return parsedProxy;
|
||||
};
|
||||
const hysteriaParser = (proxy = {}) => {
|
||||
@@ -599,6 +640,7 @@ const hysteriaParser = (proxy = {}) => {
|
||||
detourParser(proxy, parsedProxy);
|
||||
tfoParser(proxy, parsedProxy);
|
||||
smuxParser(proxy.smux, parsedProxy);
|
||||
ipVersionParser(proxy, parsedProxy);
|
||||
return parsedProxy;
|
||||
};
|
||||
const hysteria2Parser = (proxy = {}) => {
|
||||
@@ -632,6 +674,7 @@ const hysteria2Parser = (proxy = {}) => {
|
||||
tfoParser(proxy, parsedProxy);
|
||||
detourParser(proxy, parsedProxy);
|
||||
smuxParser(proxy.smux, parsedProxy);
|
||||
ipVersionParser(proxy, parsedProxy);
|
||||
return parsedProxy;
|
||||
};
|
||||
const tuic5Parser = (proxy = {}) => {
|
||||
@@ -663,6 +706,7 @@ const tuic5Parser = (proxy = {}) => {
|
||||
detourParser(proxy, parsedProxy);
|
||||
tlsParser(proxy, parsedProxy);
|
||||
smuxParser(proxy.smux, parsedProxy);
|
||||
ipVersionParser(proxy, parsedProxy);
|
||||
return parsedProxy;
|
||||
};
|
||||
const anytlsParser = (proxy = {}) => {
|
||||
@@ -685,6 +729,7 @@ const anytlsParser = (proxy = {}) => {
|
||||
);
|
||||
detourParser(proxy, parsedProxy);
|
||||
tlsParser(proxy, parsedProxy);
|
||||
ipVersionParser(proxy, parsedProxy);
|
||||
return parsedProxy;
|
||||
};
|
||||
|
||||
@@ -742,6 +787,7 @@ const wireguardParser = (proxy = {}) => {
|
||||
tfoParser(proxy, parsedProxy);
|
||||
detourParser(proxy, parsedProxy);
|
||||
smuxParser(proxy.smux, parsedProxy);
|
||||
ipVersionParser(proxy, parsedProxy);
|
||||
return parsedProxy;
|
||||
};
|
||||
|
||||
|
||||
@@ -370,9 +370,9 @@ function vmess(proxy, includeUnsupportedProxy) {
|
||||
function ssh(proxy) {
|
||||
const result = new Result(proxy);
|
||||
result.append(`${proxy.name}=ssh,${proxy.server},${proxy.port}`);
|
||||
result.appendIfPresent(`,${proxy.username}`, 'username');
|
||||
result.appendIfPresent(`,username="${proxy.username}"`, 'username');
|
||||
// 所有的类似的字段都有双引号的问题 暂不处理
|
||||
result.appendIfPresent(`,"${proxy.password}"`, 'password');
|
||||
result.appendIfPresent(`,password="${proxy.password}"`, 'password');
|
||||
|
||||
// https://manual.nssurge.com/policy/ssh.html
|
||||
// 需配合 Keystore
|
||||
@@ -439,8 +439,8 @@ function http(proxy) {
|
||||
const result = new Result(proxy);
|
||||
const type = proxy.tls ? 'https' : 'http';
|
||||
result.append(`${proxy.name}=${type},${proxy.server},${proxy.port}`);
|
||||
result.appendIfPresent(`,${proxy.username}`, 'username');
|
||||
result.appendIfPresent(`,"${proxy.password}"`, 'password');
|
||||
result.appendIfPresent(`,username="${proxy.username}"`, 'username');
|
||||
result.appendIfPresent(`,password="${proxy.password}"`, 'password');
|
||||
|
||||
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
||||
@@ -565,8 +565,8 @@ function socks5(proxy) {
|
||||
const result = new Result(proxy);
|
||||
const type = proxy.tls ? 'socks5-tls' : 'socks5';
|
||||
result.append(`${proxy.name}=${type},${proxy.server},${proxy.port}`);
|
||||
result.appendIfPresent(`,${proxy.username}`, 'username');
|
||||
result.appendIfPresent(`,"${proxy.password}"`, 'password');
|
||||
result.appendIfPresent(`,username="${proxy.username}"`, 'username');
|
||||
result.appendIfPresent(`,password="${proxy.password}"`, 'password');
|
||||
|
||||
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||
result.appendIfPresent(`,ip-version=${ip_version}`, 'ip-version');
|
||||
|
||||
@@ -26,7 +26,7 @@ function operator(proxies = [], targetPlatform, context) {
|
||||
// 12. 以 Surge 为例, 最新的参数一般我都会跟进, 以 Surge 文档为例, 一些常用的: TUIC/Hysteria 2 的 `ecn`, Snell 的 `reuse` 连接复用, QUIC 策略 block-quic`, Hysteria 2 下载带宽 `down`
|
||||
// 13. `test-url` 为测延迟链接, `test-timeout` 为测延迟超时
|
||||
// 14. `ports` 为端口跳跃, `hop-interval` 变换端口号的时间间隔
|
||||
// 15. `ip-version` 设置节点使用 IP 版本,可选:dual,ipv4,ipv6,ipv4-prefer,ipv6-prefer. 会进行内部转换, 若无法匹配则使用原始值
|
||||
// 15. `ip-version` 设置节点使用 IP 版本,兼容各家的值. 会进行内部转换. sing-box 以外: 若无法匹配则使用原始值. sing-box: 需有匹配且节点上设置 `_dns_server` 字段, 将自动设置 `domain_resolver.server`
|
||||
// 16. `sing-box` 支持使用 `_network` 来设置 `network`, 例如 `tcp`, `udp`
|
||||
// 17. `block-quic` 支持 `auto`, `on`, `off`. 不同的平台不一定都支持, 会自动转换
|
||||
|
||||
@@ -151,6 +151,18 @@ function operator(proxies = [], targetPlatform, context) {
|
||||
// });
|
||||
// $server.sni = sni
|
||||
|
||||
// 示例: 从 config 文件中读取配置项并进行节点操作
|
||||
// config 的本地内容为
|
||||
// {
|
||||
// "reuse": false
|
||||
// }
|
||||
// 脚本操作为
|
||||
// const config = (ProxyUtils.JSON5 || JSON).parse(await produceArtifact({
|
||||
// type: 'file',
|
||||
// name: 'config' // 文件名
|
||||
// }))
|
||||
// $server.reuse = config.reuse
|
||||
|
||||
// 1. Surge 输出 WireGuard 完整配置
|
||||
|
||||
// let proxies = await produceArtifact({
|
||||
|
||||
Reference in New Issue
Block a user