mirror of
https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-10 00:52:40 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c617eabd90 | ||
|
|
739100c873 | ||
|
|
a4384f4f13 | ||
|
|
468d136f0e |
11
.github/workflows/main.yml
vendored
11
.github/workflows/main.yml
vendored
@@ -59,6 +59,17 @@ jobs:
|
||||
./backend/dist/sub-store-parser.loon.min.js
|
||||
./backend/dist/cron-sync-artifacts.min.js
|
||||
./backend/dist/sub-store.bundle.js
|
||||
- name: Git push assets to "release" branch
|
||||
run: |
|
||||
cd backend/dist || exit 1
|
||||
git init
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git checkout -b release
|
||||
git add .
|
||||
git commit -m "release: ${{ steps.tag.outputs.release_tag }}"
|
||||
git remote add origin "https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}"
|
||||
git push -f -u origin release
|
||||
- name: Sync to GitLab
|
||||
env:
|
||||
GITLAB_PIPELINE_TOKEN: ${{ secrets.GITLAB_PIPELINE_TOKEN }}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sub-store",
|
||||
"version": "2.14.230",
|
||||
"version": "2.14.237",
|
||||
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.",
|
||||
"main": "src/main.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import YAML from '@/utils/yaml';
|
||||
import download from '@/utils/download';
|
||||
import { isIPv4, isIPv6, isValidPortNumber, isNotBlank } from '@/utils';
|
||||
import {
|
||||
isIPv4,
|
||||
isIPv6,
|
||||
isValidPortNumber,
|
||||
isNotBlank,
|
||||
utf8ArrayToStr,
|
||||
} from '@/utils';
|
||||
import PROXY_PROCESSORS, { ApplyProcessor } from './processors';
|
||||
import PROXY_PREPROCESSORS from './preprocessors';
|
||||
import PROXY_PRODUCERS from './producers';
|
||||
@@ -257,6 +263,10 @@ function safeMatch(parser, line) {
|
||||
}
|
||||
|
||||
function lastParse(proxy) {
|
||||
if (proxy.interface) {
|
||||
proxy['interface-name'] = proxy.interface;
|
||||
delete proxy.interface;
|
||||
}
|
||||
if (isValidPortNumber(proxy.port)) {
|
||||
proxy.port = parseInt(proxy.port, 10);
|
||||
}
|
||||
@@ -370,6 +380,18 @@ function lastParse(proxy) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof proxy.name !== 'string') {
|
||||
try {
|
||||
if (proxy.name?.data) {
|
||||
proxy.name = Buffer.from(proxy.name.data).toString('utf8');
|
||||
} else {
|
||||
proxy.name = utf8ArrayToStr(proxy.name);
|
||||
}
|
||||
} catch (e) {
|
||||
$.error(`proxy.name decode failed\nReason: ${e}`);
|
||||
proxy.name = `${proxy.type} ${proxy.server}:${proxy.port}`;
|
||||
}
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
|
||||
@@ -357,11 +357,41 @@ function ScriptOperator(script, targetPlatform, $arguments, source) {
|
||||
};
|
||||
}
|
||||
|
||||
function parseIP4P(IP4P) {
|
||||
let server;
|
||||
let port;
|
||||
try {
|
||||
if (!/^2001::[^:]+:[^:]+:[^:]+$/.test(IP4P)) {
|
||||
throw new Error(`Invalid IP4P: ${IP4P}`);
|
||||
}
|
||||
let array = IP4P.split(':');
|
||||
|
||||
port = parseInt(array[2], 16);
|
||||
let ipab = parseInt(array[3], 16);
|
||||
let ipcd = parseInt(array[4], 16);
|
||||
let ipa = ipab >> 8;
|
||||
let ipb = ipab & 0xff;
|
||||
let ipc = ipcd >> 8;
|
||||
let ipd = ipcd & 0xff;
|
||||
server = `${ipa}.${ipb}.${ipc}.${ipd}`;
|
||||
if (port <= 0 || port > 65535) {
|
||||
throw new Error(`Invalid port number: ${port}`);
|
||||
}
|
||||
if (!isIPv4(server)) {
|
||||
throw new Error(`Invalid IP address: ${server}`);
|
||||
}
|
||||
} catch (e) {
|
||||
// throw new Error(`IP4P 解析失败: ${e}`);
|
||||
$.error(`IP4P 解析失败: ${e}`);
|
||||
}
|
||||
return { server, port };
|
||||
}
|
||||
|
||||
const DOMAIN_RESOLVERS = {
|
||||
Google: async function (domain, type) {
|
||||
Google: async function (domain, type, noCache) {
|
||||
const id = hex_md5(`GOOGLE:${domain}:${type}`);
|
||||
const cached = resourceCache.get(id);
|
||||
if (cached) return cached;
|
||||
if (!noCache && cached) return cached;
|
||||
const resp = await $.http.get({
|
||||
url: `https://8.8.4.4/resolve?name=${encodeURIComponent(
|
||||
domain,
|
||||
@@ -382,10 +412,13 @@ const DOMAIN_RESOLVERS = {
|
||||
resourceCache.set(id, result);
|
||||
return result;
|
||||
},
|
||||
'IP-API': async function (domain) {
|
||||
'IP-API': async function (domain, type, noCache) {
|
||||
if (['IPv6'].includes(type)) {
|
||||
throw new Error(`域名解析服务提供方 IP-API 不支持 ${type}`);
|
||||
}
|
||||
const id = hex_md5(`IP-API:${domain}`);
|
||||
const cached = resourceCache.get(id);
|
||||
if (cached) return cached;
|
||||
if (!noCache && cached) return cached;
|
||||
const resp = await $.http.get({
|
||||
url: `http://ip-api.com/json/${encodeURIComponent(
|
||||
domain,
|
||||
@@ -399,10 +432,10 @@ const DOMAIN_RESOLVERS = {
|
||||
resourceCache.set(id, result);
|
||||
return result;
|
||||
},
|
||||
Cloudflare: async function (domain, type) {
|
||||
Cloudflare: async function (domain, type, noCache) {
|
||||
const id = hex_md5(`CLOUDFLARE:${domain}:${type}`);
|
||||
const cached = resourceCache.get(id);
|
||||
if (cached) return cached;
|
||||
if (!noCache && cached) return cached;
|
||||
const resp = await $.http.get({
|
||||
url: `https://1.0.0.1/dns-query?name=${encodeURIComponent(
|
||||
domain,
|
||||
@@ -423,10 +456,10 @@ const DOMAIN_RESOLVERS = {
|
||||
resourceCache.set(id, result);
|
||||
return result;
|
||||
},
|
||||
Ali: async function (domain, type) {
|
||||
Ali: async function (domain, type, noCache) {
|
||||
const id = hex_md5(`ALI:${domain}:${type}`);
|
||||
const cached = resourceCache.get(id);
|
||||
if (cached) return cached;
|
||||
if (!noCache && cached) return cached;
|
||||
const resp = await $.http.get({
|
||||
url: `http://223.6.6.6/resolve?name=${encodeURIComponent(
|
||||
domain,
|
||||
@@ -443,10 +476,10 @@ const DOMAIN_RESOLVERS = {
|
||||
resourceCache.set(id, result);
|
||||
return result;
|
||||
},
|
||||
Tencent: async function (domain, type) {
|
||||
Tencent: async function (domain, type, noCache) {
|
||||
const id = hex_md5(`ALI:${domain}:${type}`);
|
||||
const cached = resourceCache.get(id);
|
||||
if (cached) return cached;
|
||||
if (!noCache && cached) return cached;
|
||||
const resp = await $.http.get({
|
||||
url: `http://119.28.28.28/d?type=${
|
||||
type === 'IPv6' ? 'AAAA' : 'A'
|
||||
@@ -465,10 +498,13 @@ const DOMAIN_RESOLVERS = {
|
||||
},
|
||||
};
|
||||
|
||||
function ResolveDomainOperator({ provider, type, filter }) {
|
||||
if (type === 'IPv6' && ['IP-API'].includes(provider)) {
|
||||
throw new Error(`域名解析服务提供方 ${provider} 不支持 IPv6`);
|
||||
function ResolveDomainOperator({ provider, type: _type, filter, cache }) {
|
||||
console.log(`cache`, cache);
|
||||
if (['IPv6', 'IP4P'].includes(_type) && ['IP-API'].includes(provider)) {
|
||||
throw new Error(`域名解析服务提供方 ${provider} 不支持 ${_type}`);
|
||||
}
|
||||
let type = ['IPv6', 'IP4P'].includes(_type) ? 'IPv6' : 'IPv4';
|
||||
|
||||
const resolver = DOMAIN_RESOLVERS[provider];
|
||||
if (!resolver) {
|
||||
throw new Error(`找不到域名解析服务提供方: ${provider}`);
|
||||
@@ -490,7 +526,7 @@ function ResolveDomainOperator({ provider, type, filter }) {
|
||||
const currentBatch = [];
|
||||
for (let domain of totalDomain.splice(0, limit)) {
|
||||
currentBatch.push(
|
||||
resolver(domain, type)
|
||||
resolver(domain, type, cache === 'disabled')
|
||||
.then((ip) => {
|
||||
results[domain] = ip;
|
||||
$.info(
|
||||
@@ -509,8 +545,19 @@ function ResolveDomainOperator({ provider, type, filter }) {
|
||||
proxies.forEach((p) => {
|
||||
if (!p['no-resolve']) {
|
||||
if (results[p.server]) {
|
||||
p.server = results[p.server];
|
||||
p.resolved = true;
|
||||
if (_type === 'IP4P') {
|
||||
const { server, port } = parseIP4P(
|
||||
results[p.server],
|
||||
);
|
||||
if (server && port) {
|
||||
p.server = server;
|
||||
p.port = port;
|
||||
p.resolved = true;
|
||||
}
|
||||
} else {
|
||||
p.server = results[p.server];
|
||||
p.resolved = true;
|
||||
}
|
||||
} else {
|
||||
p.resolved = false;
|
||||
}
|
||||
|
||||
@@ -132,7 +132,10 @@ function shadowsocks(proxy) {
|
||||
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||
'allow-other-interface',
|
||||
);
|
||||
result.appendIfPresent(`,interface=${proxy['interface']}`, 'interface');
|
||||
result.appendIfPresent(
|
||||
`,interface=${proxy['interface-name']}`,
|
||||
'interface-name',
|
||||
);
|
||||
|
||||
// shadow-tls
|
||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||
@@ -229,7 +232,10 @@ function trojan(proxy) {
|
||||
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||
'allow-other-interface',
|
||||
);
|
||||
result.appendIfPresent(`,interface=${proxy['interface']}`, 'interface');
|
||||
result.appendIfPresent(
|
||||
`,interface=${proxy['interface-name']}`,
|
||||
'interface-name',
|
||||
);
|
||||
|
||||
// shadow-tls
|
||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||
@@ -315,7 +321,10 @@ function vmess(proxy) {
|
||||
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||
'allow-other-interface',
|
||||
);
|
||||
result.appendIfPresent(`,interface=${proxy['interface']}`, 'interface');
|
||||
result.appendIfPresent(
|
||||
`,interface=${proxy['interface-name']}`,
|
||||
'interface-name',
|
||||
);
|
||||
|
||||
// shadow-tls
|
||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||
@@ -385,7 +394,10 @@ function ssh(proxy) {
|
||||
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||
'allow-other-interface',
|
||||
);
|
||||
result.appendIfPresent(`,interface=${proxy['interface']}`, 'interface');
|
||||
result.appendIfPresent(
|
||||
`,interface=${proxy['interface-name']}`,
|
||||
'interface-name',
|
||||
);
|
||||
|
||||
// block-quic
|
||||
result.appendIfPresent(`,block-quic=${proxy['block-quic']}`, 'block-quic');
|
||||
@@ -445,7 +457,10 @@ function http(proxy) {
|
||||
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||
'allow-other-interface',
|
||||
);
|
||||
result.appendIfPresent(`,interface=${proxy['interface']}`, 'interface');
|
||||
result.appendIfPresent(
|
||||
`,interface=${proxy['interface-name']}`,
|
||||
'interface-name',
|
||||
);
|
||||
|
||||
// shadow-tls
|
||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||
@@ -522,7 +537,10 @@ function socks5(proxy) {
|
||||
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||
'allow-other-interface',
|
||||
);
|
||||
result.appendIfPresent(`,interface=${proxy['interface']}`, 'interface');
|
||||
result.appendIfPresent(
|
||||
`,interface=${proxy['interface-name']}`,
|
||||
'interface-name',
|
||||
);
|
||||
|
||||
// shadow-tls
|
||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||
@@ -597,7 +615,10 @@ function snell(proxy) {
|
||||
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||
'allow-other-interface',
|
||||
);
|
||||
result.appendIfPresent(`,interface=${proxy['interface']}`, 'interface');
|
||||
result.appendIfPresent(
|
||||
`,interface=${proxy['interface-name']}`,
|
||||
'interface-name',
|
||||
);
|
||||
|
||||
// shadow-tls
|
||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||
@@ -687,7 +708,10 @@ function tuic(proxy) {
|
||||
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||
'allow-other-interface',
|
||||
);
|
||||
result.appendIfPresent(`,interface=${proxy['interface']}`, 'interface');
|
||||
result.appendIfPresent(
|
||||
`,interface=${proxy['interface-name']}`,
|
||||
'interface-name',
|
||||
);
|
||||
|
||||
// shadow-tls
|
||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||
@@ -761,7 +785,10 @@ ${proxy.name}=wireguard`);
|
||||
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||
'allow-other-interface',
|
||||
);
|
||||
result.appendIfPresent(`,interface=${proxy['interface']}`, 'interface');
|
||||
result.appendIfPresent(
|
||||
`,interface=${proxy['interface-name']}`,
|
||||
'interface-name',
|
||||
);
|
||||
|
||||
// shadow-tls
|
||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||
@@ -860,7 +887,10 @@ function wireguard_surge(proxy) {
|
||||
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||
'allow-other-interface',
|
||||
);
|
||||
result.appendIfPresent(`,interface=${proxy['interface']}`, 'interface');
|
||||
result.appendIfPresent(
|
||||
`,interface=${proxy['interface-name']}`,
|
||||
'interface-name',
|
||||
);
|
||||
|
||||
// shadow-tls
|
||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||
@@ -936,7 +966,10 @@ function hysteria2(proxy) {
|
||||
`,allow-other-interface=${proxy['allow-other-interface']}`,
|
||||
'allow-other-interface',
|
||||
);
|
||||
result.appendIfPresent(`,interface=${proxy['interface']}`, 'interface');
|
||||
result.appendIfPresent(
|
||||
`,interface=${proxy['interface-name']}`,
|
||||
'interface-name',
|
||||
);
|
||||
|
||||
// shadow-tls
|
||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||
|
||||
@@ -35,6 +35,53 @@ function getIfPresent(obj, defaultValue) {
|
||||
return isPresent(obj) ? obj : defaultValue;
|
||||
}
|
||||
|
||||
const utf8ArrayToStr =
|
||||
typeof TextDecoder !== 'undefined'
|
||||
? (v) => new TextDecoder().decode(new Uint8Array(v))
|
||||
: (function () {
|
||||
var charCache = new Array(128); // Preallocate the cache for the common single byte chars
|
||||
var charFromCodePt = String.fromCodePoint || String.fromCharCode;
|
||||
var result = [];
|
||||
|
||||
return function (array) {
|
||||
var codePt, byte1;
|
||||
var buffLen = array.length;
|
||||
|
||||
result.length = 0;
|
||||
|
||||
for (var i = 0; i < buffLen; ) {
|
||||
byte1 = array[i++];
|
||||
|
||||
if (byte1 <= 0x7f) {
|
||||
codePt = byte1;
|
||||
} else if (byte1 <= 0xdf) {
|
||||
codePt = ((byte1 & 0x1f) << 6) | (array[i++] & 0x3f);
|
||||
} else if (byte1 <= 0xef) {
|
||||
codePt =
|
||||
((byte1 & 0x0f) << 12) |
|
||||
((array[i++] & 0x3f) << 6) |
|
||||
(array[i++] & 0x3f);
|
||||
} else if (String.fromCodePoint) {
|
||||
codePt =
|
||||
((byte1 & 0x07) << 18) |
|
||||
((array[i++] & 0x3f) << 12) |
|
||||
((array[i++] & 0x3f) << 6) |
|
||||
(array[i++] & 0x3f);
|
||||
} else {
|
||||
codePt = 63; // Cannot convert four byte code points, so use "?" instead
|
||||
i += 3;
|
||||
}
|
||||
|
||||
result.push(
|
||||
charCache[codePt] ||
|
||||
(charCache[codePt] = charFromCodePt(codePt)),
|
||||
);
|
||||
}
|
||||
|
||||
return result.join('');
|
||||
};
|
||||
})();
|
||||
|
||||
export {
|
||||
isIPv4,
|
||||
isIPv6,
|
||||
@@ -43,4 +90,5 @@ export {
|
||||
getIfNotBlank,
|
||||
isPresent,
|
||||
getIfPresent,
|
||||
utf8ArrayToStr,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user