Compare commits

...

14 Commits

Author SHA1 Message Date
xream
1f505752ae fix: trojan uri and tls 2023-08-24 10:02:03 +08:00
xream
497bc264e3 fix: servername/sni priority over wss host 2023-08-22 18:21:34 +08:00
xream
feb207b333 fix: servername/sni priority over wss host 2023-08-22 17:28:39 +08:00
xream
9ac1112b37 fix: VMess URI alterId parseInt 2023-08-22 15:29:55 +08:00
xream
96769598ef fix: QX tls 2023-08-22 00:42:53 +08:00
xream
f8ed6a3342 fix: QX tls 2023-08-22 00:08:53 +08:00
xream
99b19c410d fix: vmess/vless http-opts.path/http-opts.headers.Host must be an array in some clients 2023-08-21 22:16:07 +08:00
xream
9e54507bbb fix: double quotes in Surge vmess ws-headers Host 2023-08-21 21:20:31 +08:00
xream
20afa0ad22 Surge 默认模块不带 ability 参数; 分离出固定带参和不带参的模块 2023-08-20 17:22:51 +08:00
walkxspace
c5b6960b35 Update geo.js (#231) 2023-08-19 11:44:55 +08:00
xream
4dd86cb368 feat: Added replaceArtifact API 2023-08-18 13:48:37 +08:00
xream
4a0319e95f fix: flexible cipher for Loon 2023-08-15 21:22:33 +08:00
xream
090d8a978f feat: Added support for scy of VMESS URI 2023-08-15 18:15:04 +08:00
xream
bc9fae6062 feat: Added support for SNI & allowInsecure of Trojan URI 2023-08-15 17:25:25 +08:00
18 changed files with 263 additions and 90 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "sub-store", "name": "sub-store",
"version": "2.14.10", "version": "2.14.22",
"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": {

View File

@@ -1,5 +1,5 @@
import download from '@/utils/download'; import download from '@/utils/download';
import { isIPv4, isIPv6 } from '@/utils';
import PROXY_PROCESSORS, { ApplyProcessor } from './processors'; import PROXY_PROCESSORS, { ApplyProcessor } from './processors';
import PROXY_PREPROCESSORS from './preprocessors'; import PROXY_PREPROCESSORS from './preprocessors';
import PROXY_PRODUCERS from './producers'; import PROXY_PRODUCERS from './producers';
@@ -36,7 +36,7 @@ function parse(raw) {
if (lastParser) { if (lastParser) {
const [proxy, error] = tryParse(lastParser, line); const [proxy, error] = tryParse(lastParser, line);
if (!error) { if (!error) {
proxies.push(proxy); proxies.push(lastParse(proxy));
success = true; success = true;
} }
} }
@@ -46,7 +46,7 @@ function parse(raw) {
for (const parser of PROXY_PARSERS) { for (const parser of PROXY_PARSERS) {
const [proxy, error] = tryParse(parser, line); const [proxy, error] = tryParse(parser, line);
if (!error) { if (!error) {
proxies.push(proxy); proxies.push(lastParse(proxy));
lastParser = parser; lastParser = parser;
success = true; success = true;
$.info(`${parser.name} is activated`); $.info(`${parser.name} is activated`);
@@ -182,3 +182,28 @@ function safeMatch(parser, line) {
return false; return false;
} }
} }
function lastParse(proxy) {
if (proxy.type === 'trojan') {
proxy.tls = true;
}
if (proxy.tls && !proxy.sni) {
if (proxy.network) {
let transportHost = proxy[`${proxy.network}-opts`]?.headers?.Host;
transportHost = Array.isArray(transportHost)
? transportHost[0]
: transportHost;
if (transportHost) {
proxy.sni = transportHost;
}
}
if (!proxy.sni && !isIP(proxy.server)) {
proxy.sni = proxy.server;
}
}
return proxy;
}
function isIP(ip) {
return isIPv4(ip) || isIPv6(ip);
}

View File

@@ -216,14 +216,18 @@ function URI_VMess() {
type: 'vmess', type: 'vmess',
server: params.add, server: params.add,
port: params.port, port: params.port,
cipher: 'auto', // V2rayN has no default cipher! use aes-128-gcm as default. cipher: getIfPresent(params.scy, 'auto'),
uuid: params.id, uuid: params.id,
alterId: getIfPresent(params.aid, 0), alterId: parseInt(getIfPresent(params.aid, 0)),
tls: params.tls === 'tls' || params.tls === true, tls: params.tls === 'tls' || params.tls === true,
'skip-cert-verify': isPresent(params.verify_cert) 'skip-cert-verify': isPresent(params.verify_cert)
? !params.verify_cert ? !params.verify_cert
: undefined, : undefined,
}; };
// https://github.com/2dust/v2rayN/wiki/%E5%88%86%E4%BA%AB%E9%93%BE%E6%8E%A5%E6%A0%BC%E5%BC%8F%E8%AF%B4%E6%98%8E(ver-2)
if (proxy.tls && proxy.sni) {
proxy.sni = params.sni;
}
// handle obfs // handle obfs
if (params.net === 'ws') { if (params.net === 'ws') {
proxy.network = 'ws'; proxy.network = 'ws';
@@ -231,7 +235,9 @@ function URI_VMess() {
path: getIfNotBlank(params.path), path: getIfNotBlank(params.path),
headers: { Host: getIfNotBlank(params.host) }, headers: { Host: getIfNotBlank(params.host) },
}; };
if (proxy.tls && params.host) { // https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml#L413
// sni 优先级应高于 host
if (proxy.tls && !proxy.sni && params.host) {
proxy.sni = params.host; proxy.sni = params.host;
} }
} }
@@ -289,6 +295,16 @@ function Clash_All() {
if (proxy.type === 'vmess') { if (proxy.type === 'vmess') {
proxy.sni = proxy.servername; proxy.sni = proxy.servername;
delete proxy.servername; delete proxy.servername;
if (proxy.tls && !proxy.sni) {
if (proxy.network === 'ws') {
proxy.sni = proxy['ws-opts']?.headers?.Host;
} else if (proxy.network === 'http') {
let httpHost = proxy['http-opts']?.headers?.Host;
proxy.sni = Array.isArray(httpHost)
? httpHost[0]
: httpHost;
}
}
} }
return proxy; return proxy;

View File

@@ -25,6 +25,9 @@ const grammars = String.raw`
proxy.network = "ws"; proxy.network = "ws";
$set(proxy, "ws-opts.path", obfs.path); $set(proxy, "ws-opts.path", obfs.path);
$set(proxy, "ws-opts.headers", obfs['ws-headers']); $set(proxy, "ws-opts.headers", obfs['ws-headers']);
if (proxy['ws-opts'] && proxy['ws-opts']['headers'] && proxy['ws-opts']['headers'].Host) {
proxy['ws-opts']['headers'].Host = proxy['ws-opts']['headers'].Host.replace(/^"(.*)"$/, '$1')
}
} }
} }
} }

View File

@@ -23,6 +23,9 @@
proxy.network = "ws"; proxy.network = "ws";
$set(proxy, "ws-opts.path", obfs.path); $set(proxy, "ws-opts.path", obfs.path);
$set(proxy, "ws-opts.headers", obfs['ws-headers']); $set(proxy, "ws-opts.headers", obfs['ws-headers']);
if (proxy['ws-opts'] && proxy['ws-opts']['headers'] && proxy['ws-opts']['headers'].Host) {
proxy['ws-opts']['headers'].Host = proxy['ws-opts']['headers'].Host.replace(/^"(.*)"$/, '$1')
}
} }
} }
} }

View File

@@ -79,7 +79,7 @@ port = digits:[0-9]+ {
} }
} }
params = "?" head:param tail:("&"@param)* { params = "/"? "?" head:param tail:("&"@param)* {
proxy["skip-cert-verify"] = toBool(params["allowInsecure"]); proxy["skip-cert-verify"] = toBool(params["allowInsecure"]);
proxy.sni = params["sni"] || params["peer"]; proxy.sni = params["sni"] || params["peer"];
@@ -87,6 +87,15 @@ params = "?" head:param tail:("&"@param)* {
proxy.network = "ws"; proxy.network = "ws";
$set(proxy, "ws-opts.path", params["wspath"]); $set(proxy, "ws-opts.path", params["wspath"]);
} }
if (params["type"]) {
proxy.network = params["type"]
if (params["path"]) {
$set(proxy, proxy.network+"-opts.path", decodeURIComponent(params["path"]));
}
if (params["host"]) {
$set(proxy, proxy.network+"-opts.headers.Host", decodeURIComponent(params["host"]));
}
}
proxy.udp = toBool(params["udp"]); proxy.udp = toBool(params["udp"]);
proxy.tfo = toBool(params["tfo"]); proxy.tfo = toBool(params["tfo"]);

View File

@@ -77,7 +77,7 @@ port = digits:[0-9]+ {
} }
} }
params = "?" head:param tail:("&"@param)* { params = "/"? "?" head:param tail:("&"@param)* {
proxy["skip-cert-verify"] = toBool(params["allowInsecure"]); proxy["skip-cert-verify"] = toBool(params["allowInsecure"]);
proxy.sni = params["sni"] || params["peer"]; proxy.sni = params["sni"] || params["peer"];
@@ -85,6 +85,16 @@ params = "?" head:param tail:("&"@param)* {
proxy.network = "ws"; proxy.network = "ws";
$set(proxy, "ws-opts.path", params["wspath"]); $set(proxy, "ws-opts.path", params["wspath"]);
} }
if (params["type"]) {
proxy.network = params["type"]
if (params["path"]) {
$set(proxy, proxy.network+"-opts.path", decodeURIComponent(params["path"]));
}
if (params["host"]) {
$set(proxy, proxy.network+"-opts.headers.Host", decodeURIComponent(params["host"]));
}
}
proxy.udp = toBool(params["udp"]); proxy.udp = toBool(params["udp"]);
proxy.tfo = toBool(params["tfo"]); proxy.tfo = toBool(params["tfo"]);

View File

@@ -55,6 +55,26 @@ export default function Clash_Producer() {
} }
} }
if (
['vmess', 'vless'].includes(proxy.type) &&
proxy.network === 'http'
) {
let httpPath = proxy['http-opts']?.path;
if (
isPresent(proxy, 'http-opts.path') &&
!Array.isArray(httpPath)
) {
proxy['http-opts'].path = [httpPath];
}
let httpHost = proxy['http-opts']?.headers?.Host;
if (
isPresent(proxy, 'http-opts.headers.Host') &&
!Array.isArray(httpHost)
) {
proxy['http-opts'].headers.Host = [httpHost];
}
}
delete proxy['tls-fingerprint']; delete proxy['tls-fingerprint'];
return ' - ' + JSON.stringify(proxy) + '\n'; return ' - ' + JSON.stringify(proxy) + '\n';
}) })

View File

@@ -127,9 +127,7 @@ function trojan(proxy) {
function vmess(proxy) { function vmess(proxy) {
const result = new Result(proxy); const result = new Result(proxy);
result.append( result.append(
`${proxy.name}=vmess,${proxy.server},${proxy.port},${ `${proxy.name}=vmess,${proxy.server},${proxy.port},${proxy.cipher},"${proxy.uuid}"`,
proxy.cipher === 'auto' ? 'none' : proxy.cipher
},"${proxy.uuid}"`,
); );
// transport // transport
@@ -146,12 +144,14 @@ function vmess(proxy) {
); );
} else if (proxy.network === 'http') { } else if (proxy.network === 'http') {
result.append(`,transport=http`); result.append(`,transport=http`);
let httpPath = proxy['http-opts']?.path;
let httpHost = proxy['http-opts']?.headers?.Host;
result.appendIfPresent( result.appendIfPresent(
`,path=${proxy['http-opts'].path}`, `,path=${Array.isArray(httpPath) ? httpPath[0] : httpPath}`,
'http-opts.path', 'http-opts.path',
); );
result.appendIfPresent( result.appendIfPresent(
`,host=${proxy['http-opts'].headers.Host}`, `,host=${Array.isArray(httpHost) ? httpHost[0] : httpHost}`,
'http-opts.headers.Host', 'http-opts.headers.Host',
); );
} else { } else {
@@ -208,12 +208,14 @@ function vless(proxy) {
); );
} else if (proxy.network === 'http') { } else if (proxy.network === 'http') {
result.append(`,transport=http`); result.append(`,transport=http`);
let httpPath = proxy['http-opts']?.path;
let httpHost = proxy['http-opts']?.headers?.Host;
result.appendIfPresent( result.appendIfPresent(
`,path=${proxy['http-opts'].path}`, `,path=${Array.isArray(httpPath) ? httpPath[0] : httpPath}`,
'http-opts.path', 'http-opts.path',
); );
result.appendIfPresent( result.appendIfPresent(
`,host=${proxy['http-opts'].headers.Host}`, `,host=${Array.isArray(httpHost) ? httpHost[0] : httpHost}`,
'http-opts.headers.Host', 'http-opts.headers.Host',
); );
} else { } else {

View File

@@ -62,18 +62,20 @@ function shadowsocks(proxy) {
); );
} }
// tls fingerprint if (needTls(proxy)) {
appendIfPresent( // tls fingerprint
`,tls-cert-sha256=${proxy['tls-fingerprint']}`, appendIfPresent(
'tls-fingerprint', `,tls-cert-sha256=${proxy['tls-fingerprint']}`,
); 'tls-fingerprint',
);
// tls verification // tls verification
appendIfPresent( appendIfPresent(
`,tls-verification=${!proxy['skip-cert-verify']}`, `,tls-verification=${!proxy['skip-cert-verify']}`,
'skip-cert-verify', 'skip-cert-verify',
); );
appendIfPresent(`,tls-host=${proxy.sni}`, 'sni'); appendIfPresent(`,tls-host=${proxy.sni}`, 'sni');
}
// tfo // tfo
appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
@@ -150,18 +152,20 @@ function trojan(proxy) {
append(`,over-tls=true`); append(`,over-tls=true`);
} }
// tls fingerprint if (needTls(proxy)) {
appendIfPresent( // tls fingerprint
`,tls-cert-sha256=${proxy['tls-fingerprint']}`, appendIfPresent(
'tls-fingerprint', `,tls-cert-sha256=${proxy['tls-fingerprint']}`,
); 'tls-fingerprint',
);
// tls verification // tls verification
appendIfPresent( appendIfPresent(
`,tls-verification=${!proxy['skip-cert-verify']}`, `,tls-verification=${!proxy['skip-cert-verify']}`,
'skip-cert-verify', 'skip-cert-verify',
); );
appendIfPresent(`,tls-host=${proxy.sni}`, 'sni'); appendIfPresent(`,tls-host=${proxy.sni}`, 'sni');
}
// tfo // tfo
appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
@@ -206,12 +210,18 @@ function vmess(proxy) {
} else { } else {
throw new Error(`network ${proxy.network} is unsupported`); throw new Error(`network ${proxy.network} is unsupported`);
} }
let transportPath = proxy[`${proxy.network}-opts`]?.path;
let transportHost = proxy[`${proxy.network}-opts`]?.headers?.Host;
appendIfPresent( appendIfPresent(
`,obfs-uri=${proxy[`${proxy.network}-opts`].path}`, `,obfs-uri=${
Array.isArray(transportPath) ? transportPath[0] : transportPath
}`,
`${proxy.network}-opts.path`, `${proxy.network}-opts.path`,
); );
appendIfPresent( appendIfPresent(
`,obfs-host=${proxy[`${proxy.network}-opts`].headers.Host}`, `,obfs-host=${
Array.isArray(transportHost) ? transportHost[0] : transportHost
}`,
`${proxy.network}-opts.headers.Host`, `${proxy.network}-opts.headers.Host`,
); );
} else { } else {
@@ -219,18 +229,20 @@ function vmess(proxy) {
if (proxy.tls) append(`,obfs=over-tls`); if (proxy.tls) append(`,obfs=over-tls`);
} }
// tls fingerprint if (needTls(proxy)) {
appendIfPresent( // tls fingerprint
`,tls-cert-sha256=${proxy['tls-fingerprint']}`, appendIfPresent(
'tls-fingerprint', `,tls-cert-sha256=${proxy['tls-fingerprint']}`,
); 'tls-fingerprint',
);
// tls verification // tls verification
appendIfPresent( appendIfPresent(
`,tls-verification=${!proxy['skip-cert-verify']}`, `,tls-verification=${!proxy['skip-cert-verify']}`,
'skip-cert-verify', 'skip-cert-verify',
); );
appendIfPresent(`,tls-host=${proxy.sni}`, 'sni'); appendIfPresent(`,tls-host=${proxy.sni}`, 'sni');
}
// AEAD // AEAD
if (isPresent(proxy, 'aead')) { if (isPresent(proxy, 'aead')) {
@@ -266,18 +278,20 @@ function http(proxy) {
} }
appendIfPresent(`,over-tls=${proxy.tls}`, 'tls'); appendIfPresent(`,over-tls=${proxy.tls}`, 'tls');
// tls fingerprint if (needTls(proxy)) {
appendIfPresent( // tls fingerprint
`,tls-cert-sha256=${proxy['tls-fingerprint']}`, appendIfPresent(
'tls-fingerprint', `,tls-cert-sha256=${proxy['tls-fingerprint']}`,
); 'tls-fingerprint',
);
// tls verification // tls verification
appendIfPresent( appendIfPresent(
`,tls-verification=${!proxy['skip-cert-verify']}`, `,tls-verification=${!proxy['skip-cert-verify']}`,
'skip-cert-verify', 'skip-cert-verify',
); );
appendIfPresent(`,tls-host=${proxy.sni}`, 'sni'); appendIfPresent(`,tls-host=${proxy.sni}`, 'sni');
}
// tfo // tfo
appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
@@ -306,18 +320,20 @@ function socks5(proxy) {
} }
appendIfPresent(`,over-tls=${proxy.tls}`, 'tls'); appendIfPresent(`,over-tls=${proxy.tls}`, 'tls');
// tls fingerprint if (needTls(proxy)) {
appendIfPresent( // tls fingerprint
`,tls-cert-sha256=${proxy['tls-fingerprint']}`, appendIfPresent(
'tls-fingerprint', `,tls-cert-sha256=${proxy['tls-fingerprint']}`,
); 'tls-fingerprint',
);
// tls verification // tls verification
appendIfPresent( appendIfPresent(
`,tls-verification=${!proxy['skip-cert-verify']}`, `,tls-verification=${!proxy['skip-cert-verify']}`,
'skip-cert-verify', 'skip-cert-verify',
); );
appendIfPresent(`,tls-host=${proxy.sni}`, 'sni'); appendIfPresent(`,tls-host=${proxy.sni}`, 'sni');
}
// tfo // tfo
appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo'); appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
@@ -332,11 +348,5 @@ function socks5(proxy) {
} }
function needTls(proxy) { function needTls(proxy) {
return ( return proxy.tls;
proxy.tls ||
proxy.sni ||
typeof proxy['skip-cert-verify'] !== 'undefined' ||
typeof proxy['tls-fingerprint'] !== 'undefined' ||
typeof proxy['tls-host'] !== 'undefined'
);
} }

View File

@@ -58,6 +58,26 @@ export default function Stash_Producer() {
} }
} }
if (
['vmess', 'vless'].includes(proxy.type) &&
proxy.network === 'http'
) {
let httpPath = proxy['http-opts']?.path;
if (
isPresent(proxy, 'http-opts.path') &&
!Array.isArray(httpPath)
) {
proxy['http-opts'].path = [httpPath];
}
let httpHost = proxy['http-opts']?.headers?.Host;
if (
isPresent(proxy, 'http-opts.headers.Host') &&
!Array.isArray(httpHost)
) {
proxy['http-opts'].headers.Host = [httpHost];
}
}
delete proxy['tls-fingerprint']; delete proxy['tls-fingerprint'];
return ' - ' + JSON.stringify(proxy) + '\n'; return ' - ' + JSON.stringify(proxy) + '\n';
}) })

View File

@@ -301,7 +301,13 @@ function handleTransport(result, proxy) {
if (isPresent(proxy, 'ws-opts.headers')) { if (isPresent(proxy, 'ws-opts.headers')) {
const headers = proxy['ws-opts'].headers; const headers = proxy['ws-opts'].headers;
const value = Object.keys(headers) const value = Object.keys(headers)
.map((k) => `${k}:${headers[k]}`) .map((k) => {
let v = headers[k];
if (['Host'].includes(k)) {
v = `"${v}"`;
}
return `${k}:${v}`;
})
.join('|'); .join('|');
if (isNotBlank(value)) { if (isNotBlank(value)) {
result.append(`,ws-headers=${value}`); result.append(`,ws-headers=${value}`);

View File

@@ -65,17 +65,45 @@ export default function URI_Producer() {
net: proxy.network || 'tcp', net: proxy.network || 'tcp',
tls: proxy.tls ? 'tls' : '', tls: proxy.tls ? 'tls' : '',
}; };
if (proxy.tls && proxy.sni) {
result.sni = proxy.sni;
}
// obfs // obfs
if (proxy.network === 'ws') { if (proxy.network === 'ws') {
result.path = proxy['ws-opts'].path || '/'; result.path = proxy['ws-opts'].path || '/';
result.host = proxy['ws-opts'].headers.Host || proxy.server; if (proxy['ws-opts'].headers.Host) {
result.host = proxy['ws-opts'].headers.Host;
}
} }
result = 'vmess://' + Base64.encode(JSON.stringify(result)); result = 'vmess://' + Base64.encode(JSON.stringify(result));
break; break;
case 'trojan': case 'trojan':
let transport = '';
if (proxy.network) {
transport = `&type=${proxy.network}`;
let transportPath = proxy[`${proxy.network}-opts`]?.path;
let transportHost =
proxy[`${proxy.network}-opts`]?.headers?.Host;
if (transportPath) {
transport += `&path=${encodeURIComponent(
Array.isArray(transportPath)
? transportPath[0]
: transportPath,
)}`;
}
if (transportHost) {
transport += `&host=${encodeURIComponent(
Array.isArray(transportHost)
? transportHost[0]
: transportHost,
)}`;
}
}
result = `trojan://${proxy.password}@${proxy.server}:${ result = `trojan://${proxy.password}@${proxy.server}:${
proxy.port proxy.port
}#${encodeURIComponent(proxy.name)}`; }?sni=${encodeURIComponent(proxy.sni || proxy.server)}${
proxy['skip-cert-verify'] ? '&allowInsecure=1' : ''
}${transport}#${encodeURIComponent(proxy.name)}`;
break; break;
} }
return result; return result;

View File

@@ -19,7 +19,10 @@ export default function register($app) {
if (!$.read(ARTIFACTS_KEY)) $.write({}, ARTIFACTS_KEY); if (!$.read(ARTIFACTS_KEY)) $.write({}, ARTIFACTS_KEY);
// RESTful APIs // RESTful APIs
$app.route('/api/artifacts').get(getAllArtifacts).post(createArtifact); $app.route('/api/artifacts')
.get(getAllArtifacts)
.post(createArtifact)
.put(replaceArtifact);
$app.route('/api/artifact/:name') $app.route('/api/artifact/:name')
.get(getArtifact) .get(getArtifact)
@@ -32,6 +35,12 @@ function getAllArtifacts(req, res) {
success(res, allArtifacts); success(res, allArtifacts);
} }
function replaceArtifact(req, res) {
const allArtifacts = req.body;
$.write(allArtifacts, ARTIFACTS_KEY);
success(res);
}
async function getArtifact(req, res) { async function getArtifact(req, res) {
let { name } = req.params; let { name } = req.params;
name = decodeURIComponent(name); name = decodeURIComponent(name);
@@ -131,7 +140,7 @@ async function deleteArtifact(req, res) {
files[encodeURIComponent(artifact.name)] = { files[encodeURIComponent(artifact.name)] = {
content: '', content: '',
}; };
// 当别的Sub 删了同步订阅 或 gist里面删了 当前设备没有删除 时 无法删除的bug // 当别的Sub 删了同步订阅 或 gist里面删了 当前设备没有删除 时 无法删除的bug
try { try {
await syncToGist(files); await syncToGist(files);
} catch (i) { } catch (i) {

View File

@@ -155,7 +155,7 @@ export function getFlag(name) {
'🇲🇴': ['Macao', '澳门', '澳門', 'CTM'], '🇲🇴': ['Macao', '澳门', '澳門', 'CTM'],
'🇲🇹': ['Malta', '马耳他'], '🇲🇹': ['Malta', '马耳他'],
'🇲🇽': ['Mexico', '墨西哥'], '🇲🇽': ['Mexico', '墨西哥'],
'🇲🇾': ['Malaysia', '马来西亚', '馬來西亞', '吉隆坡', '大馬'], '🇲🇾': ['Malaysia', '马来', '馬來', '吉隆坡', '大馬'],
'🇳🇱': ['Netherlands', '荷兰', '荷蘭', '尼德蘭', '阿姆斯特丹'], '🇳🇱': ['Netherlands', '荷兰', '荷蘭', '尼德蘭', '阿姆斯特丹'],
'🇳🇴': ['Norway', '挪威'], '🇳🇴': ['Norway', '挪威'],
'🇳🇵': ['Nepal', '尼泊尔'], '🇳🇵': ['Nepal', '尼泊尔'],

View File

@@ -1,5 +1,5 @@
#!name=Sub-Store #!name=Sub-Store
#!desc=高级订阅管理工具 @Peng-YM 无 ability 参数版本,不会爆内存, 如果需要使用指定节点功能 例如[加国旗脚本或者cname脚本] 可以用原版 #!desc=高级订阅管理工具 @Peng-YM 无 ability 参数版本,不会爆内存, 如果需要使用指定节点功能 例如[加国旗脚本或者cname脚本] 可以用带 ability 参数
[MITM] [MITM]
hostname = %APPEND% sub.store hostname = %APPEND% sub.store

View File

@@ -0,0 +1,11 @@
#!name=Sub-Store
#!desc=高级订阅管理工具 @Peng-YM 带 ability 参数版本, 可能会爆内存, 如果不需要使用指定节点功能 例如[加国旗脚本或者cname脚本] 可以用不带 ability 参数版本
[MITM]
hostname = %APPEND% sub.store
[Script]
Sub-Store Core=type=http-request,pattern=^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))),script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-1.min.js,requires-body=true,timeout=120,ability=http-client-policy
Sub-Store Simple=type=http-request,pattern=^https?:\/\/sub\.store,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-0.min.js,requires-body=true
Sub-Store Sync=type=cron,cronexp=0 0 * * *,wake-system=1,timeout=120,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/cron-sync-artifacts.min.js

View File

@@ -1,10 +1,11 @@
#!name=Sub-Store #!name=Sub-Store
#!desc=高级订阅管理工具 @Peng-YM #!desc=高级订阅管理工具 @Peng-YM 无 ability 参数版本,不会爆内存, 如果需要使用指定节点功能 例如[加国旗脚本或者cname脚本] 可以用带 ability 参数
[MITM] [MITM]
hostname=%APPEND% sub.store hostname = %APPEND% sub.store
[Script] [Script]
Sub-Store Core=type=http-request,pattern=^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))),script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-1.min.js,requires-body=true,timeout=120,ability=http-client-policy Sub-Store Core=type=http-request,pattern=^https?:\/\/sub\.store\/((download)|api\/(preview|sync|(utils\/node-info))),script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-1.min.js,requires-body=true,timeout=120
Sub-Store Simple=type=http-request,pattern=^https?:\/\/sub\.store,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-0.min.js,requires-body=true Sub-Store Simple=type=http-request,pattern=^https?:\/\/sub\.store,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store-0.min.js,requires-body=true
Sub-Store Sync=type=cron,cronexp=0 0 * * *,wake-system=1,timeout=120,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/cron-sync-artifacts.min.js Sub-Store Sync=type=cron,cronexp=0 0 * * *,wake-system=1,timeout=120,script-path=https://github.com/sub-store-org/Sub-Store/releases/latest/download/cron-sync-artifacts.min.js