mirror of
https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-10 00:52:40 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ae286727e |
@@ -26,13 +26,13 @@ Core functionalities:
|
|||||||
|
|
||||||
### Supported Input Formats
|
### Supported Input Formats
|
||||||
|
|
||||||
> ⚠️ Do not use `Shadowrocket` or `NekoBox` to export URI and then import it as input. The URIs exported in this way may not be standard URIs.
|
> ⚠️ Do not use `Shadowrocket` to export URI and then import it as input. It is not a standard URI.
|
||||||
|
|
||||||
- [x] Proxy URI Scheme(`socks5`, `socks5+tls`, `http`, `https`(it's ok))
|
- [x] Proxy URI Scheme(`socks5`, `socks5+tls`, `http`, `https`(it's ok))
|
||||||
|
|
||||||
example: `socks5+tls://user:pass@ip:port#name`
|
example: `socks5+tls://user:pass@ip:port#name`
|
||||||
|
|
||||||
- [x] URI(SOCKS, SS, SSR, VMess, VLESS, Trojan, Hysteria, Hysteria 2, TUIC v5, WireGuard)
|
- [x] URI(SS, SSR, VMess, VLESS, Trojan, Hysteria, Hysteria 2, TUIC v5, WireGuard)
|
||||||
- [x] Clash Proxies YAML
|
- [x] Clash Proxies YAML
|
||||||
- [x] Clash Proxy JSON(single line)
|
- [x] Clash Proxy JSON(single line)
|
||||||
- [x] QX (SS, SSR, VMess, Trojan, HTTP, SOCKS5, VLESS)
|
- [x] QX (SS, SSR, VMess, Trojan, HTTP, SOCKS5, VLESS)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* ╚════██║██║ ██║██╔══██╗╚════╝╚════██║ ██║ ██║ ██║██╔══██╗██╔══╝
|
* ╚════██║██║ ██║██╔══██╗╚════╝╚════██║ ██║ ██║ ██║██╔══██╗██╔══╝
|
||||||
* ███████║╚██████╔╝██████╔╝ ███████║ ██║ ╚██████╔╝██║ ██║███████╗
|
* ███████║╚██████╔╝██████╔╝ ███████║ ██║ ╚██████╔╝██║ ██║███████╗
|
||||||
* ╚══════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝
|
* ╚══════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝
|
||||||
* Advanced Subscription Manager for QX, Loon, Surge, Stash and Shadowrocket!
|
* Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket!
|
||||||
* @updated: <%= updated %>
|
* @updated: <%= updated %>
|
||||||
* @version: <%= pkg.version %>
|
* @version: <%= pkg.version %>
|
||||||
* @author: Peng-YM
|
* @author: Peng-YM
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "sub-store",
|
"name": "sub-store",
|
||||||
"version": "2.16.47",
|
"version": "2.16.24",
|
||||||
"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": {
|
||||||
"preinstall": "npx only-allow pnpm",
|
"preinstall": "npx only-allow pnpm",
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
isIPv4,
|
isIPv4,
|
||||||
isIPv6,
|
isIPv6,
|
||||||
isValidPortNumber,
|
isValidPortNumber,
|
||||||
isValidUUID,
|
|
||||||
isNotBlank,
|
isNotBlank,
|
||||||
ipAddress,
|
ipAddress,
|
||||||
getRandomPort,
|
getRandomPort,
|
||||||
@@ -22,7 +21,6 @@ import { findByName } from '@/utils/database';
|
|||||||
import { produceArtifact } from '@/restful/sync';
|
import { produceArtifact } from '@/restful/sync';
|
||||||
import { getFlag, removeFlag, getISO, MMDB } from '@/utils/geo';
|
import { getFlag, removeFlag, getISO, MMDB } from '@/utils/geo';
|
||||||
import Gist from '@/utils/gist';
|
import Gist from '@/utils/gist';
|
||||||
import { isPresent } from './producers/utils';
|
|
||||||
|
|
||||||
function preprocess(raw) {
|
function preprocess(raw) {
|
||||||
for (const processor of PROXY_PREPROCESSORS) {
|
for (const processor of PROXY_PREPROCESSORS) {
|
||||||
@@ -77,16 +75,7 @@ function parse(raw) {
|
|||||||
$.error(`Failed to parse line: ${line}`);
|
$.error(`Failed to parse line: ${line}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return proxies.filter((proxy) => {
|
return proxies;
|
||||||
if (['vless', 'vmess'].includes(proxy.type)) {
|
|
||||||
const isProxyUUIDValid = isValidUUID(proxy.uuid);
|
|
||||||
if (!isProxyUUIDValid) {
|
|
||||||
$.error(`UUID is invalid: ${proxy.name} ${proxy.uuid}`);
|
|
||||||
}
|
|
||||||
return isProxyUUIDValid;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function processFn(
|
async function processFn(
|
||||||
@@ -225,22 +214,10 @@ function produce(proxies, targetPlatform, type, opts = {}) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// filter unsupported proxies
|
// filter unsupported proxies
|
||||||
proxies = proxies.filter((proxy) => {
|
proxies = proxies.filter(
|
||||||
// 检查代理是否支持目标平台
|
(proxy) =>
|
||||||
if (proxy.supported && proxy.supported[targetPlatform] === false) {
|
!(proxy.supported && proxy.supported[targetPlatform] === false),
|
||||||
return false;
|
);
|
||||||
}
|
|
||||||
|
|
||||||
// 对于 vless 和 vmess 代理,需要额外验证 UUID
|
|
||||||
if (['vless', 'vmess'].includes(proxy.type)) {
|
|
||||||
const isProxyUUIDValid = isValidUUID(proxy.uuid);
|
|
||||||
if (!isProxyUUIDValid)
|
|
||||||
$.error(`UUID is invalid: ${proxy.name} ${proxy.uuid}`);
|
|
||||||
return isProxyUUIDValid;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
proxies = proxies.map((proxy) => {
|
proxies = proxies.map((proxy) => {
|
||||||
proxy._resolved = proxy.resolved;
|
proxy._resolved = proxy.resolved;
|
||||||
@@ -595,20 +572,6 @@ function lastParse(proxy) {
|
|||||||
if (!proxy['tls-fingerprint'] && caStr) {
|
if (!proxy['tls-fingerprint'] && caStr) {
|
||||||
proxy['tls-fingerprint'] = rs.generateFingerprint(caStr);
|
proxy['tls-fingerprint'] = rs.generateFingerprint(caStr);
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
['shadowsocks'].includes(proxy.type) &&
|
|
||||||
isPresent(proxy, 'shadow-tls-password')
|
|
||||||
) {
|
|
||||||
proxy.plugin = 'shadow-tls';
|
|
||||||
proxy['plugin-opts'] = {
|
|
||||||
host: proxy['shadow-tls-sni'],
|
|
||||||
password: proxy['shadow-tls-password'],
|
|
||||||
version: proxy['shadow-tls-version'],
|
|
||||||
};
|
|
||||||
delete proxy['shadow-tls-sni'];
|
|
||||||
delete proxy['shadow-tls-password'];
|
|
||||||
delete proxy['shadow-tls-version'];
|
|
||||||
}
|
|
||||||
return proxy;
|
return proxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import getSurgeParser from './peggy/surge';
|
|||||||
import getLoonParser from './peggy/loon';
|
import getLoonParser from './peggy/loon';
|
||||||
import getQXParser from './peggy/qx';
|
import getQXParser from './peggy/qx';
|
||||||
import getTrojanURIParser from './peggy/trojan-uri';
|
import getTrojanURIParser from './peggy/trojan-uri';
|
||||||
import $ from '@/core/app';
|
|
||||||
|
|
||||||
import { Base64 } from 'js-base64';
|
import { Base64 } from 'js-base64';
|
||||||
|
|
||||||
@@ -41,21 +40,8 @@ function URI_PROXY() {
|
|||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
let [__, type, tls, username, password, server, port, query, name] =
|
let [__, type, tls, username, password, server, port, query, name] =
|
||||||
line.match(
|
line.match(
|
||||||
/^(socks5|http|http)(\+tls|s)?:\/\/(?:(.*?):(.*?)@)?(.*?)(?::(\d+?))?(\?.*?)?(?:#(.*?))?$/,
|
/^(socks5|http|http)(\+tls|s)?:\/\/(?:(.*?):(.*?)@)?(.*?):(\d+?)(\?.*?)?(?:#(.*?))?$/,
|
||||||
);
|
);
|
||||||
if (port) {
|
|
||||||
port = parseInt(port, 10);
|
|
||||||
} else {
|
|
||||||
if (tls) {
|
|
||||||
port = 443;
|
|
||||||
} else if (type === 'http') {
|
|
||||||
port = 80;
|
|
||||||
} else {
|
|
||||||
$.error(`port is not present in line: ${line}`);
|
|
||||||
throw new Error(`port is not present in line: ${line}`);
|
|
||||||
}
|
|
||||||
$.info(`port is not present in line: ${line}, set to ${port}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const proxy = {
|
const proxy = {
|
||||||
name:
|
name:
|
||||||
@@ -76,46 +62,7 @@ function URI_PROXY() {
|
|||||||
};
|
};
|
||||||
return { name, test, parse };
|
return { name, test, parse };
|
||||||
}
|
}
|
||||||
function URI_SOCKS() {
|
|
||||||
const name = 'URI SOCKS Parser';
|
|
||||||
const test = (line) => {
|
|
||||||
return /^socks:\/\//.test(line);
|
|
||||||
};
|
|
||||||
const parse = (line) => {
|
|
||||||
// parse url
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
|
||||||
let [__, type, auth, server, port, query, name] = line.match(
|
|
||||||
/^(socks)?:\/\/(?:(.*)@)?(.*?)(?::(\d+?))?(\?.*?)?(?:#(.*?))?$/,
|
|
||||||
);
|
|
||||||
if (port) {
|
|
||||||
port = parseInt(port, 10);
|
|
||||||
} else {
|
|
||||||
$.error(`port is not present in line: ${line}`);
|
|
||||||
throw new Error(`port is not present in line: ${line}`);
|
|
||||||
}
|
|
||||||
let username, password;
|
|
||||||
if (auth) {
|
|
||||||
const parsed = Base64.decode(decodeURIComponent(auth)).split(':');
|
|
||||||
username = parsed[0];
|
|
||||||
password = parsed[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
const proxy = {
|
|
||||||
name:
|
|
||||||
name != null
|
|
||||||
? decodeURIComponent(name)
|
|
||||||
: `${type} ${server}:${port}`,
|
|
||||||
type: 'socks5',
|
|
||||||
server,
|
|
||||||
port,
|
|
||||||
username,
|
|
||||||
password,
|
|
||||||
};
|
|
||||||
|
|
||||||
return proxy;
|
|
||||||
};
|
|
||||||
return { name, test, parse };
|
|
||||||
}
|
|
||||||
// Parse SS URI format (only supports new SIP002, legacy format is depreciated).
|
// Parse SS URI format (only supports new SIP002, legacy format is depreciated).
|
||||||
// reference: https://github.com/shadowsocks/shadowsocks-org/wiki/SIP002-URI-Scheme
|
// reference: https://github.com/shadowsocks/shadowsocks-org/wiki/SIP002-URI-Scheme
|
||||||
function URI_SS() {
|
function URI_SS() {
|
||||||
@@ -152,7 +99,6 @@ function URI_SS() {
|
|||||||
query = parsed[2];
|
query = parsed[2];
|
||||||
}
|
}
|
||||||
content = Base64.decode(content);
|
content = Base64.decode(content);
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
if (/(&|\?)v2ray-plugin=/.test(query)) {
|
if (/(&|\?)v2ray-plugin=/.test(query)) {
|
||||||
const parsed = query.match(/(&|\?)v2ray-plugin=(.*?)(&|$)/);
|
const parsed = query.match(/(&|\?)v2ray-plugin=(.*?)(&|$)/);
|
||||||
@@ -166,11 +112,8 @@ function URI_SS() {
|
|||||||
}
|
}
|
||||||
content = `${content}${query}`;
|
content = `${content}${query}`;
|
||||||
}
|
}
|
||||||
userInfoStr = content.match(/(^.*)@/)?.[1];
|
userInfoStr = content.split('@')[0];
|
||||||
serverAndPortArray = content.match(/@([^/@]*)(\/|$)/);
|
serverAndPortArray = content.match(/@([^/]*)(\/|$)/);
|
||||||
} else if (content.includes('?')) {
|
|
||||||
const parsed = content.match(/(\?.*)$/);
|
|
||||||
query = parsed[1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const serverAndPort = serverAndPortArray[1];
|
const serverAndPort = serverAndPortArray[1];
|
||||||
@@ -189,10 +132,11 @@ function URI_SS() {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
// handle obfs
|
// handle obfs
|
||||||
const pluginMatch = content.match(/[?&]plugin=([^&]+)/);
|
const idx = content.indexOf('?plugin=');
|
||||||
if (pluginMatch) {
|
if (idx !== -1) {
|
||||||
const pluginInfo = (
|
const pluginInfo = (
|
||||||
'plugin=' + decodeURIComponent(pluginMatch[1])
|
'plugin=' +
|
||||||
|
decodeURIComponent(content.split('?plugin=')[1].split('&')[0])
|
||||||
).split(';');
|
).split(';');
|
||||||
const params = {};
|
const params = {};
|
||||||
for (const item of pluginInfo) {
|
for (const item of pluginInfo) {
|
||||||
@@ -217,16 +161,6 @@ function URI_SS() {
|
|||||||
tls: getIfPresent(params.tls),
|
tls: getIfPresent(params.tls),
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
case 'shadow-tls': {
|
|
||||||
proxy.plugin = 'shadow-tls';
|
|
||||||
const version = getIfNotBlank(params['version']);
|
|
||||||
proxy['plugin-opts'] = {
|
|
||||||
host: getIfNotBlank(params['host']),
|
|
||||||
password: getIfNotBlank(params['password']),
|
|
||||||
version: version ? parseInt(version, 10) : undefined,
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unsupported plugin option: ${params.plugin}`,
|
`Unsupported plugin option: ${params.plugin}`,
|
||||||
@@ -595,9 +529,6 @@ function URI_VLESS() {
|
|||||||
if (params.sid) {
|
if (params.sid) {
|
||||||
opts['short-id'] = params.sid;
|
opts['short-id'] = params.sid;
|
||||||
}
|
}
|
||||||
if (params.spx) {
|
|
||||||
opts['_spider-x'] = params.spx;
|
|
||||||
}
|
|
||||||
if (Object.keys(opts).length > 0) {
|
if (Object.keys(opts).length > 0) {
|
||||||
// proxy[`${params.security}-opts`] = opts;
|
// proxy[`${params.security}-opts`] = opts;
|
||||||
proxy[`${params.security}-opts`] = opts;
|
proxy[`${params.security}-opts`] = opts;
|
||||||
@@ -665,12 +596,8 @@ function URI_VLESS() {
|
|||||||
// mKCP 的伪装头部类型。当前可选值有 none / srtp / utp / wechat-video / dtls / wireguard。省略时默认值为 none,即不使用伪装头部,但不可以为空字符串。
|
// mKCP 的伪装头部类型。当前可选值有 none / srtp / utp / wechat-video / dtls / wireguard。省略时默认值为 none,即不使用伪装头部,但不可以为空字符串。
|
||||||
proxy.headerType = params.headerType || 'none';
|
proxy.headerType = params.headerType || 'none';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.mode) {
|
|
||||||
proxy._mode = params.mode;
|
|
||||||
}
|
|
||||||
if (params.extra) {
|
if (params.extra) {
|
||||||
proxy._extra = params.extra;
|
proxy.extra = params.extra;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -839,11 +766,8 @@ function URI_TUIC() {
|
|||||||
const parse = (line) => {
|
const parse = (line) => {
|
||||||
line = line.split(/tuic:\/\//)[1];
|
line = line.split(/tuic:\/\//)[1];
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
let [__, auth, server, port, addons = '', name] =
|
let [__, uuid, password, server, ___, port, ____, addons = '', name] =
|
||||||
/^(.*?)@(.*?)(?::(\d+))?\/?(?:\?(.*?))?(?:#(.*?))?$/.exec(line);
|
/^(.*?):(.*?)@(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line);
|
||||||
auth = decodeURIComponent(auth);
|
|
||||||
let [uuid, ...passwordParts] = auth.split(':');
|
|
||||||
let password = passwordParts.join(':');
|
|
||||||
port = parseInt(`${port}`, 10);
|
port = parseInt(`${port}`, 10);
|
||||||
if (isNaN(port)) {
|
if (isNaN(port)) {
|
||||||
port = 443;
|
port = 443;
|
||||||
@@ -865,14 +789,12 @@ function URI_TUIC() {
|
|||||||
|
|
||||||
for (const addon of addons.split('&')) {
|
for (const addon of addons.split('&')) {
|
||||||
let [key, value] = addon.split('=');
|
let [key, value] = addon.split('=');
|
||||||
key = key.replace(/_/g, '-');
|
key = key.replace(/_/, '-');
|
||||||
value = decodeURIComponent(value);
|
value = decodeURIComponent(value);
|
||||||
if (['alpn'].includes(key)) {
|
if (['alpn'].includes(key)) {
|
||||||
proxy[key] = value ? value.split(',') : undefined;
|
proxy[key] = value ? value.split(',') : undefined;
|
||||||
} else if (['allow-insecure'].includes(key)) {
|
} else if (['allow-insecure'].includes(key)) {
|
||||||
proxy['skip-cert-verify'] = /(TRUE)|1/i.test(value);
|
proxy['skip-cert-verify'] = /(TRUE)|1/i.test(value);
|
||||||
} else if (['fast-open'].includes(key)) {
|
|
||||||
proxy.tfo = true;
|
|
||||||
} else if (['disable-sni', 'reduce-rtt'].includes(key)) {
|
} else if (['disable-sni', 'reduce-rtt'].includes(key)) {
|
||||||
proxy[key] = /(TRUE)|1/i.test(value);
|
proxy[key] = /(TRUE)|1/i.test(value);
|
||||||
} else {
|
} else {
|
||||||
@@ -1512,7 +1434,6 @@ function isIP(ip) {
|
|||||||
|
|
||||||
export default [
|
export default [
|
||||||
URI_PROXY(),
|
URI_PROXY(),
|
||||||
URI_SOCKS(),
|
|
||||||
URI_SS(),
|
URI_SS(),
|
||||||
URI_SSR(),
|
URI_SSR(),
|
||||||
URI_VMess(),
|
URI_VMess(),
|
||||||
|
|||||||
@@ -80,9 +80,6 @@ port = digits:[0-9]+ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
params = "?" head:param tail:("&"@param)* {
|
params = "?" head:param tail:("&"@param)* {
|
||||||
for (const [key, value] of Object.entries(params)) {
|
|
||||||
params[key] = decodeURIComponent(value);
|
|
||||||
}
|
|
||||||
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"];
|
||||||
proxy['client-fingerprint'] = params.fp;
|
proxy['client-fingerprint'] = params.fp;
|
||||||
@@ -118,27 +115,6 @@ params = "?" head:param tail:("&"@param)* {
|
|||||||
$set(proxy, proxy.network+"-opts.v2ray-http-upgrade-fast-open", true);
|
$set(proxy, proxy.network+"-opts.v2ray-http-upgrade-fast-open", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (['reality'].includes(params.security)) {
|
|
||||||
const opts = {};
|
|
||||||
if (params.pbk) {
|
|
||||||
opts['public-key'] = params.pbk;
|
|
||||||
}
|
|
||||||
if (params.sid) {
|
|
||||||
opts['short-id'] = params.sid;
|
|
||||||
}
|
|
||||||
if (params.spx) {
|
|
||||||
opts['_spider-x'] = params.spx;
|
|
||||||
}
|
|
||||||
if (params.mode) {
|
|
||||||
proxy._mode = params.mode;
|
|
||||||
}
|
|
||||||
if (params.extra) {
|
|
||||||
proxy._extra = params.extra;
|
|
||||||
}
|
|
||||||
if (Object.keys(opts).length > 0) {
|
|
||||||
$set(proxy, params.security+"-opts", opts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy.udp = toBool(params["udp"]);
|
proxy.udp = toBool(params["udp"]);
|
||||||
|
|||||||
@@ -78,9 +78,6 @@ port = digits:[0-9]+ {
|
|||||||
}
|
}
|
||||||
|
|
||||||
params = "?" head:param tail:("&"@param)* {
|
params = "?" head:param tail:("&"@param)* {
|
||||||
for (const [key, value] of Object.entries(params)) {
|
|
||||||
params[key] = decodeURIComponent(value);
|
|
||||||
}
|
|
||||||
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"];
|
||||||
proxy['client-fingerprint'] = params.fp;
|
proxy['client-fingerprint'] = params.fp;
|
||||||
@@ -116,27 +113,6 @@ params = "?" head:param tail:("&"@param)* {
|
|||||||
$set(proxy, proxy.network+"-opts.v2ray-http-upgrade-fast-open", true);
|
$set(proxy, proxy.network+"-opts.v2ray-http-upgrade-fast-open", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (['reality'].includes(params.security)) {
|
|
||||||
const opts = {};
|
|
||||||
if (params.pbk) {
|
|
||||||
opts['public-key'] = params.pbk;
|
|
||||||
}
|
|
||||||
if (params.sid) {
|
|
||||||
opts['short-id'] = params.sid;
|
|
||||||
}
|
|
||||||
if (params.spx) {
|
|
||||||
opts['_spider-x'] = params.spx;
|
|
||||||
}
|
|
||||||
if (params.mode) {
|
|
||||||
proxy._mode = params.mode;
|
|
||||||
}
|
|
||||||
if (params.extra) {
|
|
||||||
proxy._extra = params.extra;
|
|
||||||
}
|
|
||||||
if (Object.keys(opts).length > 0) {
|
|
||||||
$set(proxy, params.security+"-opts", opts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy.udp = toBool(params["udp"]);
|
proxy.udp = toBool(params["udp"]);
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ function Base64Encoded() {
|
|||||||
const keys = [
|
const keys = [
|
||||||
'dm1lc3M', // vmess
|
'dm1lc3M', // vmess
|
||||||
'c3NyOi8v', // ssr://
|
'c3NyOi8v', // ssr://
|
||||||
'c29ja3M6Ly', // socks://
|
|
||||||
'dHJvamFu', // trojan
|
'dHJvamFu', // trojan
|
||||||
'c3M6Ly', // ss:/
|
'c3M6Ly', // ss:/
|
||||||
'c3NkOi8v', // ssd://
|
'c3NkOi8v', // ssd://
|
||||||
|
|||||||
@@ -365,9 +365,7 @@ function ScriptOperator(script, targetPlatform, $arguments, source, $options) {
|
|||||||
if (output?.$file?.type === 'mihomoProfile') {
|
if (output?.$file?.type === 'mihomoProfile') {
|
||||||
try {
|
try {
|
||||||
let patch = YAML.safeLoad(script);
|
let patch = YAML.safeLoad(script);
|
||||||
// if (typeof patch !== 'object') patch = {};
|
if (typeof patch !== 'object') patch = {};
|
||||||
if (typeof patch !== 'object')
|
|
||||||
throw new Error('patch is not an object');
|
|
||||||
output.$content = ProxyUtils.yaml.safeDump(
|
output.$content = ProxyUtils.yaml.safeDump(
|
||||||
deepMerge(
|
deepMerge(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export default function Clash_Producer() {
|
|||||||
proxy['preshared-key'] =
|
proxy['preshared-key'] =
|
||||||
proxy['preshared-key'] ?? proxy['pre-shared-key'];
|
proxy['preshared-key'] ?? proxy['pre-shared-key'];
|
||||||
proxy['pre-shared-key'] = proxy['preshared-key'];
|
proxy['pre-shared-key'] = proxy['preshared-key'];
|
||||||
} else if (proxy.type === 'snell' && proxy.version < 3) {
|
} else if (proxy.type === 'snell') {
|
||||||
delete proxy.udp;
|
delete proxy.udp;
|
||||||
} else if (proxy.type === 'vless') {
|
} else if (proxy.type === 'vless') {
|
||||||
if (isPresent(proxy, 'sni')) {
|
if (isPresent(proxy, 'sni')) {
|
||||||
|
|||||||
@@ -32,10 +32,9 @@ export default function ClashMeta_Producer() {
|
|||||||
isPresent(proxy, 'cipher') &&
|
isPresent(proxy, 'cipher') &&
|
||||||
![
|
![
|
||||||
'auto',
|
'auto',
|
||||||
'none',
|
|
||||||
'zero',
|
|
||||||
'aes-128-gcm',
|
'aes-128-gcm',
|
||||||
'chacha20-poly1305',
|
'chacha20-poly1305',
|
||||||
|
'none',
|
||||||
].includes(proxy.cipher)
|
].includes(proxy.cipher)
|
||||||
) {
|
) {
|
||||||
proxy.cipher = 'auto';
|
proxy.cipher = 'auto';
|
||||||
@@ -87,7 +86,7 @@ export default function ClashMeta_Producer() {
|
|||||||
proxy['preshared-key'] =
|
proxy['preshared-key'] =
|
||||||
proxy['preshared-key'] ?? proxy['pre-shared-key'];
|
proxy['preshared-key'] ?? proxy['pre-shared-key'];
|
||||||
proxy['pre-shared-key'] = proxy['preshared-key'];
|
proxy['pre-shared-key'] = proxy['preshared-key'];
|
||||||
} else if (proxy.type === 'snell' && proxy.version < 3) {
|
} else if (proxy.type === 'snell') {
|
||||||
delete proxy.udp;
|
delete proxy.udp;
|
||||||
} else if (proxy.type === 'vless') {
|
} else if (proxy.type === 'vless') {
|
||||||
if (isPresent(proxy, 'sni')) {
|
if (isPresent(proxy, 'sni')) {
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import { isPresent } from './utils';
|
|
||||||
|
|
||||||
export default function Egern_Producer() {
|
export default function Egern_Producer() {
|
||||||
const type = 'ALL';
|
const type = 'ALL';
|
||||||
const produce = (proxies, type) => {
|
const produce = (proxies, type, opts = {}) => {
|
||||||
// https://egernapp.com/zh-CN/docs/configuration/proxies
|
// https://egernapp.com/zh-CN/docs/configuration/proxies
|
||||||
const list = proxies
|
const list = proxies
|
||||||
.filter((proxy) => {
|
.filter((proxy) => {
|
||||||
@@ -50,12 +48,23 @@ export default function Egern_Producer() {
|
|||||||
'salsa20',
|
'salsa20',
|
||||||
'chacha20',
|
'chacha20',
|
||||||
'chacha20-ietf',
|
'chacha20-ietf',
|
||||||
'2022-blake3-aes-128-gcm',
|
...(opts['include-unsupported-proxy']
|
||||||
'2022-blake3-aes-256-gcm',
|
? [
|
||||||
|
'2022-blake3-aes-128-gcm',
|
||||||
|
'2022-blake3-aes-256-gcm',
|
||||||
|
]
|
||||||
|
: []),
|
||||||
].includes(proxy.cipher))) ||
|
].includes(proxy.cipher))) ||
|
||||||
(proxy.type === 'vmess' &&
|
(proxy.type === 'vmess' &&
|
||||||
!['http', 'ws', 'tcp'].includes(proxy.network) &&
|
(![
|
||||||
proxy.network) ||
|
'auto',
|
||||||
|
'aes-128-gcm',
|
||||||
|
'chacha20-poly1305',
|
||||||
|
'none',
|
||||||
|
'zero',
|
||||||
|
].includes(proxy.cipher) ||
|
||||||
|
(!['http', 'ws', 'tcp'].includes(proxy.network) &&
|
||||||
|
proxy.network))) ||
|
||||||
(proxy.type === 'trojan' &&
|
(proxy.type === 'trojan' &&
|
||||||
!['http', 'ws', 'tcp'].includes(proxy.network) &&
|
!['http', 'ws', 'tcp'].includes(proxy.network) &&
|
||||||
proxy.network) ||
|
proxy.network) ||
|
||||||
@@ -73,7 +82,6 @@ export default function Egern_Producer() {
|
|||||||
return true;
|
return true;
|
||||||
})
|
})
|
||||||
.map((proxy) => {
|
.map((proxy) => {
|
||||||
const original = { ...proxy };
|
|
||||||
if (proxy.tls && !proxy.sni) {
|
if (proxy.tls && !proxy.sni) {
|
||||||
proxy.sni = proxy.server;
|
proxy.sni = proxy.server;
|
||||||
}
|
}
|
||||||
@@ -187,20 +195,6 @@ export default function Egern_Producer() {
|
|||||||
websocket: proxy.websocket,
|
websocket: proxy.websocket,
|
||||||
};
|
};
|
||||||
} else if (proxy.type === 'vmess') {
|
} else if (proxy.type === 'vmess') {
|
||||||
// Egern:传输层,支持 ws/wss/http1/http2/tls,不配置则为 tcp
|
|
||||||
let security = proxy.cipher;
|
|
||||||
if (
|
|
||||||
security &&
|
|
||||||
![
|
|
||||||
'auto',
|
|
||||||
'none',
|
|
||||||
'zero',
|
|
||||||
'aes-128-gcm',
|
|
||||||
'chacha20-poly1305',
|
|
||||||
].includes(security)
|
|
||||||
) {
|
|
||||||
security = 'auto';
|
|
||||||
}
|
|
||||||
if (proxy.network === 'ws') {
|
if (proxy.network === 'ws') {
|
||||||
proxy.transport = {
|
proxy.transport = {
|
||||||
[proxy.tls ? 'wss' : 'ws']: {
|
[proxy.tls ? 'wss' : 'ws']: {
|
||||||
@@ -216,7 +210,7 @@ export default function Egern_Producer() {
|
|||||||
};
|
};
|
||||||
} else if (proxy.network === 'http') {
|
} else if (proxy.network === 'http') {
|
||||||
proxy.transport = {
|
proxy.transport = {
|
||||||
http1: {
|
http: {
|
||||||
method: proxy['http-opts']?.method,
|
method: proxy['http-opts']?.method,
|
||||||
path: proxy['http-opts']?.path,
|
path: proxy['http-opts']?.path,
|
||||||
headers: {
|
headers: {
|
||||||
@@ -229,27 +223,9 @@ export default function Egern_Producer() {
|
|||||||
skip_tls_verify: proxy['skip-cert-verify'],
|
skip_tls_verify: proxy['skip-cert-verify'],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} else if (proxy.network === 'h2') {
|
} else if (proxy.network === 'tcp' || !proxy.network) {
|
||||||
proxy.transport = {
|
proxy.transport = {
|
||||||
http2: {
|
[proxy.tls ? 'tls' : 'tcp']: {
|
||||||
method: proxy['h2-opts']?.method,
|
|
||||||
path: proxy['h2-opts']?.path,
|
|
||||||
headers: {
|
|
||||||
Host: Array.isArray(
|
|
||||||
proxy['h2-opts']?.headers?.Host,
|
|
||||||
)
|
|
||||||
? proxy['h2-opts']?.headers?.Host[0]
|
|
||||||
: proxy['h2-opts']?.headers?.Host,
|
|
||||||
},
|
|
||||||
skip_tls_verify: proxy['skip-cert-verify'],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
} else if (
|
|
||||||
(proxy.network === 'tcp' || !proxy.network) &&
|
|
||||||
proxy.tls
|
|
||||||
) {
|
|
||||||
proxy.transport = {
|
|
||||||
tls: {
|
|
||||||
sni: proxy.tls ? proxy.sni : undefined,
|
sni: proxy.tls ? proxy.sni : undefined,
|
||||||
skip_tls_verify: proxy.tls
|
skip_tls_verify: proxy.tls
|
||||||
? proxy['skip-cert-verify']
|
? proxy['skip-cert-verify']
|
||||||
@@ -263,7 +239,7 @@ export default function Egern_Producer() {
|
|||||||
server: proxy.server,
|
server: proxy.server,
|
||||||
port: proxy.port,
|
port: proxy.port,
|
||||||
user_id: proxy.uuid,
|
user_id: proxy.uuid,
|
||||||
security,
|
security: proxy.cipher,
|
||||||
tfo: proxy.tfo || proxy['fast-open'],
|
tfo: proxy.tfo || proxy['fast-open'],
|
||||||
legacy: proxy.legacy,
|
legacy: proxy.legacy,
|
||||||
udp_relay:
|
udp_relay:
|
||||||
@@ -273,6 +249,8 @@ export default function Egern_Producer() {
|
|||||||
// sni: proxy.sni,
|
// sni: proxy.sni,
|
||||||
// skip_tls_verify: proxy['skip-cert-verify'],
|
// skip_tls_verify: proxy['skip-cert-verify'],
|
||||||
};
|
};
|
||||||
|
} else if (proxy.type === 'snell') {
|
||||||
|
delete proxy.udp;
|
||||||
} else if (proxy.type === 'vless') {
|
} else if (proxy.type === 'vless') {
|
||||||
if (proxy.network === 'ws') {
|
if (proxy.network === 'ws') {
|
||||||
proxy.transport = {
|
proxy.transport = {
|
||||||
@@ -329,39 +307,6 @@ export default function Egern_Producer() {
|
|||||||
// skip_tls_verify: proxy['skip-cert-verify'],
|
// skip_tls_verify: proxy['skip-cert-verify'],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (
|
|
||||||
[
|
|
||||||
'http',
|
|
||||||
'socks5',
|
|
||||||
'ss',
|
|
||||||
'trojan',
|
|
||||||
'vless',
|
|
||||||
'vmess',
|
|
||||||
].includes(original.type)
|
|
||||||
) {
|
|
||||||
if (isPresent(original, 'shadow-tls-password')) {
|
|
||||||
if (original['shadow-tls-version'] != 3)
|
|
||||||
throw new Error(
|
|
||||||
`shadow-tls version ${original['shadow-tls-version']} is not supported`,
|
|
||||||
);
|
|
||||||
proxy.shadow_tls = {
|
|
||||||
password: original['shadow-tls-password'],
|
|
||||||
sni: original['shadow-tls-sni'],
|
|
||||||
};
|
|
||||||
} else if (
|
|
||||||
['shadow-tls'].includes(original.plugin) &&
|
|
||||||
original['plugin-opts']
|
|
||||||
) {
|
|
||||||
if (original['plugin-opts'].version != 3)
|
|
||||||
throw new Error(
|
|
||||||
`shadow-tls version ${original['plugin-opts'].version} is not supported`,
|
|
||||||
);
|
|
||||||
proxy.shadow_tls = {
|
|
||||||
password: original['plugin-opts'].password,
|
|
||||||
sni: original['plugin-opts'].host,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete proxy.subName;
|
delete proxy.subName;
|
||||||
delete proxy.collectionName;
|
delete proxy.collectionName;
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ export default function Loon_Producer() {
|
|||||||
const produce = (proxy, type, opts = {}) => {
|
const produce = (proxy, type, opts = {}) => {
|
||||||
switch (proxy.type) {
|
switch (proxy.type) {
|
||||||
case 'ss':
|
case 'ss':
|
||||||
return shadowsocks(proxy);
|
return shadowsocks(proxy, opts['include-unsupported-proxy']);
|
||||||
case 'ssr':
|
case 'ssr':
|
||||||
return shadowsocksr(proxy);
|
return shadowsocksr(proxy, opts['include-unsupported-proxy']);
|
||||||
case 'trojan':
|
case 'trojan':
|
||||||
return trojan(proxy);
|
return trojan(proxy);
|
||||||
case 'vmess':
|
case 'vmess':
|
||||||
@@ -40,7 +40,7 @@ export default function Loon_Producer() {
|
|||||||
return { produce };
|
return { produce };
|
||||||
}
|
}
|
||||||
|
|
||||||
function shadowsocks(proxy) {
|
function shadowsocks(proxy, includeUnsupportedProxy) {
|
||||||
const result = new Result(proxy);
|
const result = new Result(proxy);
|
||||||
if (
|
if (
|
||||||
![
|
![
|
||||||
@@ -74,6 +74,8 @@ function shadowsocks(proxy) {
|
|||||||
`${proxy.name}=shadowsocks,${proxy.server},${proxy.port},${proxy.cipher},"${proxy.password}"`,
|
`${proxy.name}=shadowsocks,${proxy.server},${proxy.port},${proxy.cipher},"${proxy.password}"`,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let isShadowTLS;
|
||||||
|
|
||||||
// obfs
|
// obfs
|
||||||
if (isPresent(proxy, 'plugin')) {
|
if (isPresent(proxy, 'plugin')) {
|
||||||
if (proxy.plugin === 'obfs') {
|
if (proxy.plugin === 'obfs') {
|
||||||
@@ -105,6 +107,7 @@ function shadowsocks(proxy) {
|
|||||||
);
|
);
|
||||||
// udp-port
|
// udp-port
|
||||||
result.appendIfPresent(`,udp-port=${proxy['udp-port']}`, 'udp-port');
|
result.appendIfPresent(`,udp-port=${proxy['udp-port']}`, 'udp-port');
|
||||||
|
isShadowTLS = true;
|
||||||
} else if (['shadow-tls'].includes(proxy.plugin) && proxy['plugin-opts']) {
|
} else if (['shadow-tls'].includes(proxy.plugin) && proxy['plugin-opts']) {
|
||||||
const password = proxy['plugin-opts'].password;
|
const password = proxy['plugin-opts'].password;
|
||||||
const host = proxy['plugin-opts'].host;
|
const host = proxy['plugin-opts'].host;
|
||||||
@@ -127,6 +130,7 @@ function shadowsocks(proxy) {
|
|||||||
`,udp-port=${proxy['udp-port']}`,
|
`,udp-port=${proxy['udp-port']}`,
|
||||||
'udp-port',
|
'udp-port',
|
||||||
);
|
);
|
||||||
|
isShadowTLS = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,6 +142,11 @@ function shadowsocks(proxy) {
|
|||||||
result.append(`,udp=true`);
|
result.append(`,udp=true`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!includeUnsupportedProxy && isShadowTLS) {
|
||||||
|
throw new Error(
|
||||||
|
`shadow-tls is not supported(请使用 includeUnsupportedProxy 参数)`,
|
||||||
|
);
|
||||||
|
}
|
||||||
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||||
result.appendIfPresent(`,ip-mode=${ip_version}`, 'ip-version');
|
result.appendIfPresent(`,ip-mode=${ip_version}`, 'ip-version');
|
||||||
|
|
||||||
@@ -161,6 +170,8 @@ function shadowsocksr(proxy, includeUnsupportedProxy) {
|
|||||||
result.appendIfPresent(`,obfs=${proxy.obfs}`, 'obfs');
|
result.appendIfPresent(`,obfs=${proxy.obfs}`, 'obfs');
|
||||||
result.appendIfPresent(`,obfs-param=${proxy['obfs-param']}`, 'obfs-param');
|
result.appendIfPresent(`,obfs-param=${proxy['obfs-param']}`, 'obfs-param');
|
||||||
|
|
||||||
|
let isShadowTLS;
|
||||||
|
|
||||||
// shadow-tls
|
// shadow-tls
|
||||||
if (isPresent(proxy, 'shadow-tls-password')) {
|
if (isPresent(proxy, 'shadow-tls-password')) {
|
||||||
result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`);
|
result.append(`,shadow-tls-password=${proxy['shadow-tls-password']}`);
|
||||||
@@ -175,6 +186,7 @@ function shadowsocksr(proxy, includeUnsupportedProxy) {
|
|||||||
);
|
);
|
||||||
// udp-port
|
// udp-port
|
||||||
result.appendIfPresent(`,udp-port=${proxy['udp-port']}`, 'udp-port');
|
result.appendIfPresent(`,udp-port=${proxy['udp-port']}`, 'udp-port');
|
||||||
|
isShadowTLS = true;
|
||||||
} else if (['shadow-tls'].includes(proxy.plugin) && proxy['plugin-opts']) {
|
} else if (['shadow-tls'].includes(proxy.plugin) && proxy['plugin-opts']) {
|
||||||
const password = proxy['plugin-opts'].password;
|
const password = proxy['plugin-opts'].password;
|
||||||
const host = proxy['plugin-opts'].host;
|
const host = proxy['plugin-opts'].host;
|
||||||
@@ -197,6 +209,7 @@ function shadowsocksr(proxy, includeUnsupportedProxy) {
|
|||||||
`,udp-port=${proxy['udp-port']}`,
|
`,udp-port=${proxy['udp-port']}`,
|
||||||
'udp-port',
|
'udp-port',
|
||||||
);
|
);
|
||||||
|
isShadowTLS = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,6 +221,11 @@ function shadowsocksr(proxy, includeUnsupportedProxy) {
|
|||||||
result.append(`,udp=true`);
|
result.append(`,udp=true`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!includeUnsupportedProxy && isShadowTLS) {
|
||||||
|
throw new Error(
|
||||||
|
`shadow-tls is not supported(请使用 includeUnsupportedProxy 参数)`,
|
||||||
|
);
|
||||||
|
}
|
||||||
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
const ip_version = ipVersions[proxy['ip-version']] || proxy['ip-version'];
|
||||||
result.appendIfPresent(`,ip-mode=${ip_version}`, 'ip-version');
|
result.appendIfPresent(`,ip-mode=${ip_version}`, 'ip-version');
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { isPresent } from '@/core/proxy-utils/producers/utils';
|
import { isPresent } from '@/core/proxy-utils/producers/utils';
|
||||||
|
|
||||||
export default function Shadowrocket_Producer() {
|
export default function ShadowRocket_Producer() {
|
||||||
const type = 'ALL';
|
const type = 'ALL';
|
||||||
const produce = (proxies, type, opts = {}) => {
|
const produce = (proxies, type, opts = {}) => {
|
||||||
const list = proxies
|
const list = proxies
|
||||||
@@ -32,10 +32,9 @@ export default function Shadowrocket_Producer() {
|
|||||||
isPresent(proxy, 'cipher') &&
|
isPresent(proxy, 'cipher') &&
|
||||||
![
|
![
|
||||||
'auto',
|
'auto',
|
||||||
'none',
|
|
||||||
'zero',
|
|
||||||
'aes-128-gcm',
|
'aes-128-gcm',
|
||||||
'chacha20-poly1305',
|
'chacha20-poly1305',
|
||||||
|
'none',
|
||||||
].includes(proxy.cipher)
|
].includes(proxy.cipher)
|
||||||
) {
|
) {
|
||||||
proxy.cipher = 'auto';
|
proxy.cipher = 'auto';
|
||||||
@@ -103,7 +102,7 @@ export default function Shadowrocket_Producer() {
|
|||||||
proxy['preshared-key'] =
|
proxy['preshared-key'] =
|
||||||
proxy['preshared-key'] ?? proxy['pre-shared-key'];
|
proxy['preshared-key'] ?? proxy['pre-shared-key'];
|
||||||
proxy['pre-shared-key'] = proxy['preshared-key'];
|
proxy['pre-shared-key'] = proxy['preshared-key'];
|
||||||
} else if (proxy.type === 'snell' && proxy.version < 3) {
|
} else if (proxy.type === 'snell') {
|
||||||
delete proxy.udp;
|
delete proxy.udp;
|
||||||
} else if (proxy.type === 'vless') {
|
} else if (proxy.type === 'vless') {
|
||||||
if (isPresent(proxy, 'sni')) {
|
if (isPresent(proxy, 'sni')) {
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ export default function Stash_Producer() {
|
|||||||
proxy['preshared-key'] =
|
proxy['preshared-key'] =
|
||||||
proxy['preshared-key'] ?? proxy['pre-shared-key'];
|
proxy['preshared-key'] ?? proxy['pre-shared-key'];
|
||||||
proxy['pre-shared-key'] = proxy['preshared-key'];
|
proxy['pre-shared-key'] = proxy['preshared-key'];
|
||||||
} else if (proxy.type === 'snell' && proxy.version < 3) {
|
} else if (proxy.type === 'snell') {
|
||||||
delete proxy.udp;
|
delete proxy.udp;
|
||||||
} else if (proxy.type === 'vless') {
|
} else if (proxy.type === 'vless') {
|
||||||
if (isPresent(proxy, 'sni')) {
|
if (isPresent(proxy, 'sni')) {
|
||||||
|
|||||||
@@ -27,11 +27,6 @@ export default function URI_Producer() {
|
|||||||
proxy.server = `[${proxy.server}]`;
|
proxy.server = `[${proxy.server}]`;
|
||||||
}
|
}
|
||||||
switch (proxy.type) {
|
switch (proxy.type) {
|
||||||
case 'socks5':
|
|
||||||
result = `socks://${encodeURIComponent(
|
|
||||||
Base64.encode(`${proxy.username}:${proxy.password}`),
|
|
||||||
)}@${proxy.server}:${proxy.port}#${proxy.name}`;
|
|
||||||
break;
|
|
||||||
case 'ss':
|
case 'ss':
|
||||||
const userinfo = `${proxy.cipher}:${proxy.password}`;
|
const userinfo = `${proxy.cipher}:${proxy.password}`;
|
||||||
result = `ss://${
|
result = `ss://${
|
||||||
@@ -59,11 +54,6 @@ export default function URI_Producer() {
|
|||||||
}${opts.tls ? ';tls' : ''}`,
|
}${opts.tls ? ';tls' : ''}`,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'shadow-tls':
|
|
||||||
result += encodeURIComponent(
|
|
||||||
`shadow-tls;host=${opts.host};password=${opts.password};version=${opts.version}`,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unsupported plugin option: ${proxy.plugin}`,
|
`Unsupported plugin option: ${proxy.plugin}`,
|
||||||
@@ -159,7 +149,6 @@ export default function URI_Producer() {
|
|||||||
const isReality = proxy['reality-opts'];
|
const isReality = proxy['reality-opts'];
|
||||||
let sid = '';
|
let sid = '';
|
||||||
let pbk = '';
|
let pbk = '';
|
||||||
let spx = '';
|
|
||||||
if (isReality) {
|
if (isReality) {
|
||||||
security = 'reality';
|
security = 'reality';
|
||||||
const publicKey = proxy['reality-opts']?.['public-key'];
|
const publicKey = proxy['reality-opts']?.['public-key'];
|
||||||
@@ -170,10 +159,6 @@ export default function URI_Producer() {
|
|||||||
if (shortId) {
|
if (shortId) {
|
||||||
sid = `&sid=${encodeURIComponent(shortId)}`;
|
sid = `&sid=${encodeURIComponent(shortId)}`;
|
||||||
}
|
}
|
||||||
const spiderX = proxy['reality-opts']?.['_spider-x'];
|
|
||||||
if (spiderX) {
|
|
||||||
spx = `&spx=${encodeURIComponent(spiderX)}`;
|
|
||||||
}
|
|
||||||
} else if (proxy.tls) {
|
} else if (proxy.tls) {
|
||||||
security = 'tls';
|
security = 'tls';
|
||||||
}
|
}
|
||||||
@@ -204,12 +189,8 @@ export default function URI_Producer() {
|
|||||||
flow = `&flow=${encodeURIComponent(proxy.flow)}`;
|
flow = `&flow=${encodeURIComponent(proxy.flow)}`;
|
||||||
}
|
}
|
||||||
let extra = '';
|
let extra = '';
|
||||||
if (proxy._extra) {
|
if (proxy.extra) {
|
||||||
extra = `&extra=${encodeURIComponent(proxy._extra)}`;
|
extra = `&extra=${encodeURIComponent(proxy.extra)}`;
|
||||||
}
|
|
||||||
let mode = '';
|
|
||||||
if (proxy._mode) {
|
|
||||||
mode = `&mode=${encodeURIComponent(proxy._mode)}`;
|
|
||||||
}
|
}
|
||||||
let vlessType = proxy.network;
|
let vlessType = proxy.network;
|
||||||
if (
|
if (
|
||||||
@@ -277,7 +258,7 @@ export default function URI_Producer() {
|
|||||||
proxy.port
|
proxy.port
|
||||||
}?security=${encodeURIComponent(
|
}?security=${encodeURIComponent(
|
||||||
security,
|
security,
|
||||||
)}${vlessTransport}${alpn}${allowInsecure}${sni}${fp}${flow}${sid}${spx}${pbk}${mode}${extra}#${encodeURIComponent(
|
)}${vlessTransport}${alpn}${allowInsecure}${sni}${fp}${flow}${sid}${pbk}${extra}#${encodeURIComponent(
|
||||||
proxy.name,
|
proxy.name,
|
||||||
)}`;
|
)}`;
|
||||||
break;
|
break;
|
||||||
@@ -347,41 +328,11 @@ export default function URI_Producer() {
|
|||||||
: proxy.alpn.join(','),
|
: proxy.alpn.join(','),
|
||||||
)}`;
|
)}`;
|
||||||
}
|
}
|
||||||
const trojanIsReality = proxy['reality-opts'];
|
|
||||||
let trojanSid = '';
|
|
||||||
let trojanPbk = '';
|
|
||||||
let trojanSpx = '';
|
|
||||||
let trojanSecurity = '';
|
|
||||||
let trojanMode = '';
|
|
||||||
let trojanExtra = '';
|
|
||||||
if (trojanIsReality) {
|
|
||||||
trojanSecurity = `&security=reality`;
|
|
||||||
const publicKey = proxy['reality-opts']?.['public-key'];
|
|
||||||
if (publicKey) {
|
|
||||||
trojanPbk = `&pbk=${encodeURIComponent(publicKey)}`;
|
|
||||||
}
|
|
||||||
const shortId = proxy['reality-opts']?.['short-id'];
|
|
||||||
if (shortId) {
|
|
||||||
trojanSid = `&sid=${encodeURIComponent(shortId)}`;
|
|
||||||
}
|
|
||||||
const spiderX = proxy['reality-opts']?.['_spider-x'];
|
|
||||||
if (spiderX) {
|
|
||||||
trojanSpx = `&spx=${encodeURIComponent(spiderX)}`;
|
|
||||||
}
|
|
||||||
if (proxy._extra) {
|
|
||||||
trojanExtra = `&extra=${encodeURIComponent(
|
|
||||||
proxy._extra,
|
|
||||||
)}`;
|
|
||||||
}
|
|
||||||
if (proxy._mode) {
|
|
||||||
trojanMode = `&mode=${encodeURIComponent(proxy._mode)}`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result = `trojan://${proxy.password}@${proxy.server}:${
|
result = `trojan://${proxy.password}@${proxy.server}:${
|
||||||
proxy.port
|
proxy.port
|
||||||
}?sni=${encodeURIComponent(proxy.sni || proxy.server)}${
|
}?sni=${encodeURIComponent(proxy.sni || proxy.server)}${
|
||||||
proxy['skip-cert-verify'] ? '&allowInsecure=1' : ''
|
proxy['skip-cert-verify'] ? '&allowInsecure=1' : ''
|
||||||
}${trojanTransport}${trojanAlpn}${trojanFp}${trojanSecurity}${trojanSid}${trojanPbk}${trojanSpx}${trojanMode}${trojanExtra}#${encodeURIComponent(
|
}${trojanTransport}${trojanAlpn}${trojanFp}#${encodeURIComponent(
|
||||||
proxy.name,
|
proxy.name,
|
||||||
)}`;
|
)}`;
|
||||||
break;
|
break;
|
||||||
@@ -521,13 +472,10 @@ export default function URI_Producer() {
|
|||||||
['disable-sni', 'reduce-rtt'].includes(key) &&
|
['disable-sni', 'reduce-rtt'].includes(key) &&
|
||||||
proxy[key]
|
proxy[key]
|
||||||
) {
|
) {
|
||||||
tuicParams.push(`${i.replace(/-/g, '_')}=1`);
|
tuicParams.push(`${i}=1`);
|
||||||
} else if (proxy[key]) {
|
} else if (proxy[key]) {
|
||||||
tuicParams.push(
|
tuicParams.push(
|
||||||
`${i.replace(
|
`${i}=${encodeURIComponent(proxy[key])}`,
|
||||||
/-/g,
|
|
||||||
'_',
|
|
||||||
)}=${encodeURIComponent(proxy[key])}`,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ async function doSync() {
|
|||||||
const files = {};
|
const files = {};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const valid = [];
|
|
||||||
const invalid = [];
|
const invalid = [];
|
||||||
const allSubs = $.read(SUBS_KEY);
|
const allSubs = $.read(SUBS_KEY);
|
||||||
const allCols = $.read(COLLECTIONS_KEY);
|
const allCols = $.read(COLLECTIONS_KEY);
|
||||||
@@ -157,26 +156,19 @@ async function doSync() {
|
|||||||
files[encodeURIComponent(artifact.name)] = {
|
files[encodeURIComponent(artifact.name)] = {
|
||||||
content: output,
|
content: output,
|
||||||
};
|
};
|
||||||
|
|
||||||
valid.push(artifact.name);
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
$.error(
|
$.error(
|
||||||
`生成同步配置 ${artifact.name} 发生错误: ${
|
`同步配置 ${artifact.name} 发生错误: ${e.message ?? e}`,
|
||||||
e.message ?? e
|
|
||||||
}`,
|
|
||||||
);
|
);
|
||||||
invalid.push(artifact.name);
|
invalid.push(artifact.name);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
$.info(`${valid.length} 个同步配置生成成功: ${valid.join(', ')}`);
|
if (invalid.length > 0) {
|
||||||
$.info(`${invalid.length} 个同步配置生成失败: ${invalid.join(', ')}`);
|
|
||||||
|
|
||||||
if (valid.length === 0) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`同步配置 ${invalid.join(', ')} 生成失败 详情请查看日志`,
|
`同步配置 ${invalid.join(', ')} 发生错误 详情请查看日志`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,11 +184,7 @@ async function doSync() {
|
|||||||
$.info(JSON.stringify(body, null, 2));
|
$.info(JSON.stringify(body, null, 2));
|
||||||
|
|
||||||
for (const artifact of allArtifacts) {
|
for (const artifact of allArtifacts) {
|
||||||
if (
|
if (artifact.sync) {
|
||||||
artifact.sync &&
|
|
||||||
artifact.source &&
|
|
||||||
valid.includes(artifact.name)
|
|
||||||
) {
|
|
||||||
artifact.updated = new Date().getTime();
|
artifact.updated = new Date().getTime();
|
||||||
// extract real url from gist
|
// extract real url from gist
|
||||||
let files = body.files;
|
let files = body.files;
|
||||||
@@ -224,18 +212,9 @@ async function doSync() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$.write(allArtifacts, ARTIFACTS_KEY);
|
$.write(allArtifacts, ARTIFACTS_KEY);
|
||||||
$.info('上传配置成功');
|
$.notify('🌍 Sub-Store', '全部订阅同步成功!');
|
||||||
|
|
||||||
if (invalid.length > 0) {
|
|
||||||
$.notify(
|
|
||||||
'🌍 Sub-Store',
|
|
||||||
`同步配置成功 ${valid.length} 个, 失败 ${invalid.length} 个, 详情请查看日志`,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$.notify('🌍 Sub-Store', '同步配置完成');
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
$.notify('🌍 Sub-Store', '同步配置失败', `原因:${e.message ?? e}`);
|
$.notify('🌍 Sub-Store', '同步订阅失败', `原因:${e.message ?? e}`);
|
||||||
$.error(`无法同步配置到 Gist,原因:${e}`);
|
$.error(`无法同步订阅配置到 Gist,原因:${e}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,18 +59,7 @@ function getCollection(req, res) {
|
|||||||
res.set('content-type', 'application/json')
|
res.set('content-type', 'application/json')
|
||||||
.set(
|
.set(
|
||||||
'content-disposition',
|
'content-disposition',
|
||||||
`attachment; filename="${encodeURIComponent(
|
`attachment; filename="${encodeURIComponent(name)}.json"`,
|
||||||
`sub-store_collection_${name}_${new Date()
|
|
||||||
.toLocaleString('zh-CN', {
|
|
||||||
year: 'numeric',
|
|
||||||
day: 'numeric',
|
|
||||||
month: 'numeric',
|
|
||||||
hour: 'numeric',
|
|
||||||
minute: 'numeric',
|
|
||||||
second: 'numeric',
|
|
||||||
})
|
|
||||||
.replace(/\D/g, '')}.json`,
|
|
||||||
)}"`,
|
|
||||||
)
|
)
|
||||||
.send(JSON.stringify(collection));
|
.send(JSON.stringify(collection));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -209,18 +209,7 @@ function getWholeFile(req, res) {
|
|||||||
res.set('content-type', 'application/json')
|
res.set('content-type', 'application/json')
|
||||||
.set(
|
.set(
|
||||||
'content-disposition',
|
'content-disposition',
|
||||||
`attachment; filename="${encodeURIComponent(
|
`attachment; filename="${encodeURIComponent(name)}.json"`,
|
||||||
`sub-store_file_${name}_${new Date()
|
|
||||||
.toLocaleString('zh-CN', {
|
|
||||||
year: 'numeric',
|
|
||||||
day: 'numeric',
|
|
||||||
month: 'numeric',
|
|
||||||
hour: 'numeric',
|
|
||||||
minute: 'numeric',
|
|
||||||
second: 'numeric',
|
|
||||||
})
|
|
||||||
.replace(/\D/g, '')}.json`,
|
|
||||||
)}"`,
|
|
||||||
)
|
)
|
||||||
.send(JSON.stringify(file));
|
.send(JSON.stringify(file));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -27,18 +27,7 @@ export default function register($app) {
|
|||||||
res.set('content-type', 'application/json')
|
res.set('content-type', 'application/json')
|
||||||
.set(
|
.set(
|
||||||
'content-disposition',
|
'content-disposition',
|
||||||
`attachment; filename="${encodeURIComponent(
|
'attachment; filename="sub-store.json"',
|
||||||
`sub-store_data_${new Date()
|
|
||||||
.toLocaleString('zh-CN', {
|
|
||||||
year: 'numeric',
|
|
||||||
day: 'numeric',
|
|
||||||
month: 'numeric',
|
|
||||||
hour: 'numeric',
|
|
||||||
minute: 'numeric',
|
|
||||||
second: 'numeric',
|
|
||||||
})
|
|
||||||
.replace(/\D/g, '')}.json`,
|
|
||||||
)}"`,
|
|
||||||
)
|
)
|
||||||
.send(
|
.send(
|
||||||
$.env.isNode
|
$.env.isNode
|
||||||
|
|||||||
@@ -15,48 +15,46 @@ export default function register($app) {
|
|||||||
async function previewFile(req, res) {
|
async function previewFile(req, res) {
|
||||||
try {
|
try {
|
||||||
const file = req.body;
|
const file = req.body;
|
||||||
let content = '';
|
let content;
|
||||||
if (file.type !== 'mihomoProfile') {
|
if (
|
||||||
if (
|
file.source === 'local' &&
|
||||||
file.source === 'local' &&
|
!['localFirst', 'remoteFirst'].includes(file.mergeSources)
|
||||||
!['localFirst', 'remoteFirst'].includes(file.mergeSources)
|
) {
|
||||||
) {
|
content = file.content;
|
||||||
content = file.content;
|
} else {
|
||||||
} else {
|
const errors = {};
|
||||||
const errors = {};
|
content = await Promise.all(
|
||||||
content = await Promise.all(
|
file.url
|
||||||
file.url
|
.split(/[\r\n]+/)
|
||||||
.split(/[\r\n]+/)
|
.map((i) => i.trim())
|
||||||
.map((i) => i.trim())
|
.filter((i) => i.length)
|
||||||
.filter((i) => i.length)
|
.map(async (url) => {
|
||||||
.map(async (url) => {
|
try {
|
||||||
try {
|
return await download(url, file.ua);
|
||||||
return await download(url, file.ua);
|
} catch (err) {
|
||||||
} catch (err) {
|
errors[url] = err;
|
||||||
errors[url] = err;
|
$.error(
|
||||||
$.error(
|
`文件 ${file.name} 的远程文件 ${url} 发生错误: ${err}`,
|
||||||
`文件 ${file.name} 的远程文件 ${url} 发生错误: ${err}`,
|
);
|
||||||
);
|
return '';
|
||||||
return '';
|
}
|
||||||
}
|
}),
|
||||||
}),
|
);
|
||||||
);
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!file.ignoreFailedRemoteFile &&
|
!file.ignoreFailedRemoteFile &&
|
||||||
Object.keys(errors).length > 0
|
Object.keys(errors).length > 0
|
||||||
) {
|
) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`文件 ${file.name} 的远程文件 ${Object.keys(
|
`文件 ${file.name} 的远程文件 ${Object.keys(errors).join(
|
||||||
errors,
|
', ',
|
||||||
).join(', ')} 发生错误, 请查看日志`,
|
)} 发生错误, 请查看日志`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (file.mergeSources === 'localFirst') {
|
if (file.mergeSources === 'localFirst') {
|
||||||
content.unshift(file.content);
|
content.unshift(file.content);
|
||||||
} else if (file.mergeSources === 'remoteFirst') {
|
} else if (file.mergeSources === 'remoteFirst') {
|
||||||
content.push(file.content);
|
content.push(file.content);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// parse proxies
|
// parse proxies
|
||||||
|
|||||||
@@ -264,18 +264,7 @@ function getSubscription(req, res) {
|
|||||||
res.set('content-type', 'application/json')
|
res.set('content-type', 'application/json')
|
||||||
.set(
|
.set(
|
||||||
'content-disposition',
|
'content-disposition',
|
||||||
`attachment; filename="${encodeURIComponent(
|
`attachment; filename="${encodeURIComponent(name)}.json"`,
|
||||||
`sub-store_subscription_${name}_${new Date()
|
|
||||||
.toLocaleString('zh-CN', {
|
|
||||||
year: 'numeric',
|
|
||||||
day: 'numeric',
|
|
||||||
month: 'numeric',
|
|
||||||
hour: 'numeric',
|
|
||||||
minute: 'numeric',
|
|
||||||
second: 'numeric',
|
|
||||||
})
|
|
||||||
.replace(/\D/g, '')}.json`,
|
|
||||||
)}"`,
|
|
||||||
)
|
)
|
||||||
.send(JSON.stringify(sub));
|
.send(JSON.stringify(sub));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -410,117 +410,105 @@ async function produceArtifact({
|
|||||||
const allFiles = $.read(FILES_KEY);
|
const allFiles = $.read(FILES_KEY);
|
||||||
const file = findByName(allFiles, name);
|
const file = findByName(allFiles, name);
|
||||||
if (!file) throw new Error(`找不到文件 ${name}`);
|
if (!file) throw new Error(`找不到文件 ${name}`);
|
||||||
let raw = '';
|
let raw;
|
||||||
console.log(file);
|
if (content && !['localFirst', 'remoteFirst'].includes(mergeSources)) {
|
||||||
if (file.type !== 'mihomoProfile') {
|
raw = content;
|
||||||
|
} else if (url) {
|
||||||
|
const errors = {};
|
||||||
|
raw = await Promise.all(
|
||||||
|
url
|
||||||
|
.split(/[\r\n]+/)
|
||||||
|
.map((i) => i.trim())
|
||||||
|
.filter((i) => i.length)
|
||||||
|
.map(async (url) => {
|
||||||
|
try {
|
||||||
|
return await download(
|
||||||
|
url,
|
||||||
|
ua || file.ua,
|
||||||
|
undefined,
|
||||||
|
file.proxy || proxy,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
noCache,
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
errors[url] = err;
|
||||||
|
$.error(
|
||||||
|
`文件 ${file.name} 的远程文件 ${url} 发生错误: ${err}`,
|
||||||
|
);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
let fileIgnoreFailedRemoteFile = file.ignoreFailedRemoteFile;
|
||||||
if (
|
if (
|
||||||
content &&
|
ignoreFailedRemoteFile != null &&
|
||||||
!['localFirst', 'remoteFirst'].includes(mergeSources)
|
ignoreFailedRemoteFile !== ''
|
||||||
) {
|
) {
|
||||||
raw = content;
|
fileIgnoreFailedRemoteFile = ignoreFailedRemoteFile;
|
||||||
} else if (url) {
|
}
|
||||||
const errors = {};
|
if (!fileIgnoreFailedRemoteFile && Object.keys(errors).length > 0) {
|
||||||
raw = await Promise.all(
|
throw new Error(
|
||||||
url
|
`文件 ${file.name} 的远程文件 ${Object.keys(errors).join(
|
||||||
.split(/[\r\n]+/)
|
', ',
|
||||||
.map((i) => i.trim())
|
)} 发生错误, 请查看日志`,
|
||||||
.filter((i) => i.length)
|
|
||||||
.map(async (url) => {
|
|
||||||
try {
|
|
||||||
return await download(
|
|
||||||
url,
|
|
||||||
ua || file.ua,
|
|
||||||
undefined,
|
|
||||||
file.proxy || proxy,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
noCache,
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
errors[url] = err;
|
|
||||||
$.error(
|
|
||||||
`文件 ${file.name} 的远程文件 ${url} 发生错误: ${err}`,
|
|
||||||
);
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
let fileIgnoreFailedRemoteFile = file.ignoreFailedRemoteFile;
|
}
|
||||||
if (
|
if (mergeSources === 'localFirst') {
|
||||||
ignoreFailedRemoteFile != null &&
|
raw.unshift(content);
|
||||||
ignoreFailedRemoteFile !== ''
|
} else if (mergeSources === 'remoteFirst') {
|
||||||
) {
|
raw.push(content);
|
||||||
fileIgnoreFailedRemoteFile = ignoreFailedRemoteFile;
|
}
|
||||||
}
|
} else if (
|
||||||
if (
|
file.source === 'local' &&
|
||||||
!fileIgnoreFailedRemoteFile &&
|
!['localFirst', 'remoteFirst'].includes(file.mergeSources)
|
||||||
Object.keys(errors).length > 0
|
) {
|
||||||
) {
|
raw = file.content;
|
||||||
throw new Error(
|
} else {
|
||||||
`文件 ${file.name} 的远程文件 ${Object.keys(
|
const errors = {};
|
||||||
errors,
|
raw = await Promise.all(
|
||||||
).join(', ')} 发生错误, 请查看日志`,
|
file.url
|
||||||
);
|
.split(/[\r\n]+/)
|
||||||
}
|
.map((i) => i.trim())
|
||||||
if (mergeSources === 'localFirst') {
|
.filter((i) => i.length)
|
||||||
raw.unshift(content);
|
.map(async (url) => {
|
||||||
} else if (mergeSources === 'remoteFirst') {
|
try {
|
||||||
raw.push(content);
|
return await download(
|
||||||
}
|
url,
|
||||||
} else if (
|
ua || file.ua,
|
||||||
file.source === 'local' &&
|
undefined,
|
||||||
!['localFirst', 'remoteFirst'].includes(file.mergeSources)
|
file.proxy || proxy,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
noCache,
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
errors[url] = err;
|
||||||
|
$.error(
|
||||||
|
`文件 ${file.name} 的远程文件 ${url} 发生错误: ${err}`,
|
||||||
|
);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
let fileIgnoreFailedRemoteFile = file.ignoreFailedRemoteFile;
|
||||||
|
if (
|
||||||
|
ignoreFailedRemoteFile != null &&
|
||||||
|
ignoreFailedRemoteFile !== ''
|
||||||
) {
|
) {
|
||||||
raw = file.content;
|
fileIgnoreFailedRemoteFile = ignoreFailedRemoteFile;
|
||||||
} else {
|
}
|
||||||
const errors = {};
|
if (!fileIgnoreFailedRemoteFile && Object.keys(errors).length > 0) {
|
||||||
raw = await Promise.all(
|
throw new Error(
|
||||||
file.url
|
`文件 ${file.name} 的远程文件 ${Object.keys(errors).join(
|
||||||
.split(/[\r\n]+/)
|
', ',
|
||||||
.map((i) => i.trim())
|
)} 发生错误, 请查看日志`,
|
||||||
.filter((i) => i.length)
|
|
||||||
.map(async (url) => {
|
|
||||||
try {
|
|
||||||
return await download(
|
|
||||||
url,
|
|
||||||
ua || file.ua,
|
|
||||||
undefined,
|
|
||||||
file.proxy || proxy,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
noCache,
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
errors[url] = err;
|
|
||||||
$.error(
|
|
||||||
`文件 ${file.name} 的远程文件 ${url} 发生错误: ${err}`,
|
|
||||||
);
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
let fileIgnoreFailedRemoteFile = file.ignoreFailedRemoteFile;
|
}
|
||||||
if (
|
if (file.mergeSources === 'localFirst') {
|
||||||
ignoreFailedRemoteFile != null &&
|
raw.unshift(file.content);
|
||||||
ignoreFailedRemoteFile !== ''
|
} else if (file.mergeSources === 'remoteFirst') {
|
||||||
) {
|
raw.push(file.content);
|
||||||
fileIgnoreFailedRemoteFile = ignoreFailedRemoteFile;
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
!fileIgnoreFailedRemoteFile &&
|
|
||||||
Object.keys(errors).length > 0
|
|
||||||
) {
|
|
||||||
throw new Error(
|
|
||||||
`文件 ${file.name} 的远程文件 ${Object.keys(
|
|
||||||
errors,
|
|
||||||
).join(', ')} 发生错误, 请查看日志`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (file.mergeSources === 'localFirst') {
|
|
||||||
raw.unshift(file.content);
|
|
||||||
} else if (file.mergeSources === 'remoteFirst') {
|
|
||||||
raw.push(file.content);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const files = (Array.isArray(raw) ? raw : [raw]).flat();
|
const files = (Array.isArray(raw) ? raw : [raw]).flat();
|
||||||
@@ -552,7 +540,6 @@ async function syncArtifacts() {
|
|||||||
const files = {};
|
const files = {};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const valid = [];
|
|
||||||
const invalid = [];
|
const invalid = [];
|
||||||
const allSubs = $.read(SUBS_KEY);
|
const allSubs = $.read(SUBS_KEY);
|
||||||
const allCols = $.read(COLLECTIONS_KEY);
|
const allCols = $.read(COLLECTIONS_KEY);
|
||||||
@@ -627,26 +614,19 @@ async function syncArtifacts() {
|
|||||||
files[encodeURIComponent(artifact.name)] = {
|
files[encodeURIComponent(artifact.name)] = {
|
||||||
content: output,
|
content: output,
|
||||||
};
|
};
|
||||||
|
|
||||||
valid.push(artifact.name);
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
$.error(
|
$.error(
|
||||||
`生成同步配置 ${artifact.name} 发生错误: ${
|
`同步配置 ${artifact.name} 发生错误: ${e.message ?? e}`,
|
||||||
e.message ?? e
|
|
||||||
}`,
|
|
||||||
);
|
);
|
||||||
invalid.push(artifact.name);
|
invalid.push(artifact.name);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
$.info(`${valid.length} 个同步配置生成成功: ${valid.join(', ')}`);
|
if (invalid.length > 0) {
|
||||||
$.info(`${invalid.length} 个同步配置生成失败: ${invalid.join(', ')}`);
|
|
||||||
|
|
||||||
if (valid.length === 0) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`同步配置 ${invalid.join(', ')} 生成失败 详情请查看日志`,
|
`同步配置 ${invalid.join(', ')} 发生错误 详情请查看日志`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -663,11 +643,7 @@ async function syncArtifacts() {
|
|||||||
$.info(JSON.stringify(body, null, 2));
|
$.info(JSON.stringify(body, null, 2));
|
||||||
|
|
||||||
for (const artifact of allArtifacts) {
|
for (const artifact of allArtifacts) {
|
||||||
if (
|
if (artifact.sync) {
|
||||||
artifact.sync &&
|
|
||||||
artifact.source &&
|
|
||||||
valid.includes(artifact.name)
|
|
||||||
) {
|
|
||||||
artifact.updated = new Date().getTime();
|
artifact.updated = new Date().getTime();
|
||||||
// extract real url from gist
|
// extract real url from gist
|
||||||
let files = body.files;
|
let files = body.files;
|
||||||
@@ -695,17 +671,9 @@ async function syncArtifacts() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$.write(allArtifacts, ARTIFACTS_KEY);
|
$.write(allArtifacts, ARTIFACTS_KEY);
|
||||||
$.info('上传配置成功');
|
$.info('全部订阅同步成功!');
|
||||||
|
|
||||||
if (invalid.length > 0) {
|
|
||||||
throw new Error(
|
|
||||||
`同步配置成功 ${valid.length} 个, 失败 ${invalid.length} 个, 详情请查看日志`,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
$.info(`同步配置成功 ${valid.length} 个`);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
$.error(`同步配置失败,原因:${e.message ?? e}`);
|
$.error(`同步订阅失败,原因:${e.message ?? e}`);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -715,7 +683,7 @@ async function syncAllArtifacts(_, res) {
|
|||||||
await syncArtifacts();
|
await syncArtifacts();
|
||||||
success(res);
|
success(res);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
$.error(`同步配置失败,原因:${e.message ?? e}`);
|
$.error(`同步订阅失败,原因:${e.message ?? e}`);
|
||||||
failed(
|
failed(
|
||||||
res,
|
res,
|
||||||
new InternalServerError(
|
new InternalServerError(
|
||||||
|
|||||||
@@ -117,17 +117,7 @@ function numberToString(value) {
|
|||||||
: BigInt(value).toString();
|
: BigInt(value).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
function isValidUUID(uuid) {
|
|
||||||
return (
|
|
||||||
typeof uuid === 'string' &&
|
|
||||||
/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(
|
|
||||||
uuid,
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
isValidUUID,
|
|
||||||
ipAddress,
|
ipAddress,
|
||||||
isIPv4,
|
isIPv4,
|
||||||
isIPv6,
|
isIPv6,
|
||||||
|
|||||||
Reference in New Issue
Block a user