mirror of
https://git.mirrors.martin98.com/https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-10 11:28:59 +08:00
feat: 脚本内部 produceArtifact 支持指定 produceType: 'internal', produceOpts: { 'include-unsupported-proxy': true } 来获得内部的数据结构; 订阅链接参数支持 type=internal&includeUnsupportedProxy=true; 文件支持 nunjucks 模板, 为 sing-box 增加的 Filter 用法 sub/col 为订阅/组合订阅中的节点名 {{ '订阅的name' | sub('美国|🇺🇸|us', 'i') }}, subNode/colNode 为订阅/组合订阅中的节点 {{ '订阅的name' | subNode('美国|🇺🇸|us', 'i') }}, 底层 produceArtifact('subscription', 'sing-box', 'internal', '美国|🇺🇸|us', 'i')
This commit is contained in:
parent
12903d77f7
commit
5ecce27f4e
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "sub-store",
|
"name": "sub-store",
|
||||||
"version": "2.14.154",
|
"version": "2.14.155",
|
||||||
"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": {
|
||||||
@ -21,6 +21,7 @@
|
|||||||
"http-proxy-middleware": "^2.0.6",
|
"http-proxy-middleware": "^2.0.6",
|
||||||
"js-base64": "^3.7.2",
|
"js-base64": "^3.7.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
"nunjucks": "^3.2.4",
|
||||||
"request": "^2.88.2",
|
"request": "^2.88.2",
|
||||||
"requests": "^0.3.0",
|
"requests": "^0.3.0",
|
||||||
"semver": "^7.3.7",
|
"semver": "^7.3.7",
|
||||||
|
46
backend/pnpm-lock.yaml
generated
46
backend/pnpm-lock.yaml
generated
@ -26,6 +26,9 @@ dependencies:
|
|||||||
lodash:
|
lodash:
|
||||||
specifier: ^4.17.21
|
specifier: ^4.17.21
|
||||||
version: registry.npmmirror.com/lodash@4.17.21
|
version: registry.npmmirror.com/lodash@4.17.21
|
||||||
|
nunjucks:
|
||||||
|
specifier: ^3.2.4
|
||||||
|
version: registry.npmmirror.com/nunjucks@3.2.4
|
||||||
request:
|
request:
|
||||||
specifier: ^2.88.2
|
specifier: ^2.88.2
|
||||||
version: registry.npmmirror.com/request@2.88.2
|
version: registry.npmmirror.com/request@2.88.2
|
||||||
@ -162,11 +165,6 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/source-map@0.6.1:
|
|
||||||
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
|
|
||||||
engines: {node: '>=0.10.0'}
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
registry.npmmirror.com/@ampproject/remapping@2.2.0:
|
registry.npmmirror.com/@ampproject/remapping@2.2.0:
|
||||||
resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.2.0.tgz}
|
resolution: {integrity: sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@ampproject/remapping/-/remapping-2.2.0.tgz}
|
||||||
name: '@ampproject/remapping'
|
name: '@ampproject/remapping'
|
||||||
@ -2126,6 +2124,12 @@ packages:
|
|||||||
through: registry.npmmirror.com/through@2.3.8
|
through: registry.npmmirror.com/through@2.3.8
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
registry.npmmirror.com/a-sync-waterfall@1.0.1:
|
||||||
|
resolution: {integrity: sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz}
|
||||||
|
name: a-sync-waterfall
|
||||||
|
version: 1.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
registry.npmmirror.com/abbrev@1.1.1:
|
registry.npmmirror.com/abbrev@1.1.1:
|
||||||
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/abbrev/-/abbrev-1.1.1.tgz}
|
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/abbrev/-/abbrev-1.1.1.tgz}
|
||||||
name: abbrev
|
name: abbrev
|
||||||
@ -2464,6 +2468,12 @@ packages:
|
|||||||
is-string: registry.npmmirror.com/is-string@1.0.7
|
is-string: registry.npmmirror.com/is-string@1.0.7
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
registry.npmmirror.com/asap@2.0.6:
|
||||||
|
resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/asap/-/asap-2.0.6.tgz}
|
||||||
|
name: asap
|
||||||
|
version: 2.0.6
|
||||||
|
dev: false
|
||||||
|
|
||||||
registry.npmmirror.com/asn1.js@5.4.1:
|
registry.npmmirror.com/asn1.js@5.4.1:
|
||||||
resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/asn1.js/-/asn1.js-5.4.1.tgz}
|
resolution: {integrity: sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/asn1.js/-/asn1.js-5.4.1.tgz}
|
||||||
name: asn1.js
|
name: asn1.js
|
||||||
@ -3471,6 +3481,13 @@ packages:
|
|||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
registry.npmmirror.com/commander@5.1.0:
|
||||||
|
resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/commander/-/commander-5.1.0.tgz}
|
||||||
|
name: commander
|
||||||
|
version: 5.1.0
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
registry.npmmirror.com/commander@9.3.0:
|
registry.npmmirror.com/commander@9.3.0:
|
||||||
resolution: {integrity: sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/commander/-/commander-9.3.0.tgz}
|
resolution: {integrity: sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/commander/-/commander-9.3.0.tgz}
|
||||||
name: commander
|
name: commander
|
||||||
@ -7379,6 +7396,23 @@ packages:
|
|||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
registry.npmmirror.com/nunjucks@3.2.4:
|
||||||
|
resolution: {integrity: sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/nunjucks/-/nunjucks-3.2.4.tgz}
|
||||||
|
name: nunjucks
|
||||||
|
version: 3.2.4
|
||||||
|
engines: {node: '>= 6.9.0'}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
chokidar: ^3.3.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
chokidar:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
a-sync-waterfall: registry.npmmirror.com/a-sync-waterfall@1.0.1
|
||||||
|
asap: registry.npmmirror.com/asap@2.0.6
|
||||||
|
commander: registry.npmmirror.com/commander@5.1.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
registry.npmmirror.com/oauth-sign@0.9.0:
|
registry.npmmirror.com/oauth-sign@0.9.0:
|
||||||
resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/oauth-sign/-/oauth-sign-0.9.0.tgz}
|
resolution: {integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/oauth-sign/-/oauth-sign-0.9.0.tgz}
|
||||||
name: oauth-sign
|
name: oauth-sign
|
||||||
@ -9320,7 +9354,7 @@ packages:
|
|||||||
dependencies:
|
dependencies:
|
||||||
acorn: registry.npmmirror.com/acorn@8.7.1
|
acorn: registry.npmmirror.com/acorn@8.7.1
|
||||||
commander: registry.npmmirror.com/commander@2.20.3
|
commander: registry.npmmirror.com/commander@2.20.3
|
||||||
source-map: 0.6.1
|
source-map: registry.npmmirror.com/source-map@0.6.1
|
||||||
source-map-support: registry.npmmirror.com/source-map-support@0.5.21
|
source-map-support: registry.npmmirror.com/source-map-support@0.5.21
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ async function process(proxies, operators = [], targetPlatform, source) {
|
|||||||
return proxies;
|
return proxies;
|
||||||
}
|
}
|
||||||
|
|
||||||
function produce(proxies, targetPlatform, type) {
|
function produce(proxies, targetPlatform, type, opts = {}) {
|
||||||
const producer = PROXY_PRODUCERS[targetPlatform];
|
const producer = PROXY_PRODUCERS[targetPlatform];
|
||||||
if (!producer) {
|
if (!producer) {
|
||||||
throw new Error(`Target platform: ${targetPlatform} is not supported!`);
|
throw new Error(`Target platform: ${targetPlatform} is not supported!`);
|
||||||
@ -154,10 +154,10 @@ function produce(proxies, targetPlatform, type) {
|
|||||||
$.info(`Producing proxies for target: ${targetPlatform}`);
|
$.info(`Producing proxies for target: ${targetPlatform}`);
|
||||||
if (typeof producer.type === 'undefined' || producer.type === 'SINGLE') {
|
if (typeof producer.type === 'undefined' || producer.type === 'SINGLE') {
|
||||||
let localPort = 10000;
|
let localPort = 10000;
|
||||||
return proxies
|
const list = proxies
|
||||||
.map((proxy) => {
|
.map((proxy) => {
|
||||||
try {
|
try {
|
||||||
let line = producer.produce(proxy, type);
|
let line = producer.produce(proxy, type, opts);
|
||||||
if (
|
if (
|
||||||
line.length > 0 &&
|
line.length > 0 &&
|
||||||
line.includes('__SubStoreLocalPort__')
|
line.includes('__SubStoreLocalPort__')
|
||||||
@ -179,10 +179,10 @@ function produce(proxies, targetPlatform, type) {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.filter((line) => line.length > 0)
|
.filter((line) => line.length > 0);
|
||||||
.join('\n');
|
return type === 'internal' ? list : list.join('\n');
|
||||||
} else if (producer.type === 'ALL') {
|
} else if (producer.type === 'ALL') {
|
||||||
return producer.produce(proxies, type);
|
return producer.produce(proxies, type, opts);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,136 +2,139 @@ import { isPresent } from '@/core/proxy-utils/producers/utils';
|
|||||||
|
|
||||||
export default function Clash_Producer() {
|
export default function Clash_Producer() {
|
||||||
const type = 'ALL';
|
const type = 'ALL';
|
||||||
const produce = (proxies) => {
|
const produce = (proxies, type, opts = {}) => {
|
||||||
// VLESS XTLS is not supported by Clash
|
// VLESS XTLS is not supported by Clash
|
||||||
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml#L532
|
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml#L532
|
||||||
// github.com/Dreamacro/clash/pull/2891/files
|
// github.com/Dreamacro/clash/pull/2891/files
|
||||||
// filter unsupported proxies
|
// filter unsupported proxies
|
||||||
// https://clash.wiki/configuration/outbound.html#shadowsocks
|
// https://clash.wiki/configuration/outbound.html#shadowsocks
|
||||||
proxies = proxies.filter((proxy) => {
|
const list = proxies
|
||||||
if (
|
.filter((proxy) => {
|
||||||
![
|
if (opts['include-unsupported-proxy']) return true;
|
||||||
'ss',
|
if (
|
||||||
'ssr',
|
|
||||||
'vmess',
|
|
||||||
'vless',
|
|
||||||
'socks5',
|
|
||||||
'http',
|
|
||||||
'snell',
|
|
||||||
'trojan',
|
|
||||||
'wireguard',
|
|
||||||
].includes(proxy.type) ||
|
|
||||||
(proxy.type === 'ss' &&
|
|
||||||
![
|
![
|
||||||
'aes-128-gcm',
|
'ss',
|
||||||
'aes-192-gcm',
|
'ssr',
|
||||||
'aes-256-gcm',
|
'vmess',
|
||||||
'aes-128-cfb',
|
'vless',
|
||||||
'aes-192-cfb',
|
'socks5',
|
||||||
'aes-256-cfb',
|
'http',
|
||||||
'aes-128-ctr',
|
'snell',
|
||||||
'aes-192-ctr',
|
'trojan',
|
||||||
'aes-256-ctr',
|
'wireguard',
|
||||||
'rc4-md5',
|
].includes(proxy.type) ||
|
||||||
'chacha20-ietf',
|
(proxy.type === 'ss' &&
|
||||||
'xchacha20',
|
![
|
||||||
'chacha20-ietf-poly1305',
|
'aes-128-gcm',
|
||||||
'xchacha20-ietf-poly1305',
|
'aes-192-gcm',
|
||||||
].includes(proxy.cipher)) ||
|
'aes-256-gcm',
|
||||||
(proxy.type === 'snell' && String(proxy.version) === '4') ||
|
'aes-128-cfb',
|
||||||
(proxy.type === 'vless' &&
|
'aes-192-cfb',
|
||||||
(typeof proxy.flow !== 'undefined' ||
|
'aes-256-cfb',
|
||||||
proxy['reality-opts']))
|
'aes-128-ctr',
|
||||||
) {
|
'aes-192-ctr',
|
||||||
return false;
|
'aes-256-ctr',
|
||||||
}
|
'rc4-md5',
|
||||||
return true;
|
'chacha20-ietf',
|
||||||
});
|
'xchacha20',
|
||||||
return (
|
'chacha20-ietf-poly1305',
|
||||||
'proxies:\n' +
|
'xchacha20-ietf-poly1305',
|
||||||
proxies
|
].includes(proxy.cipher)) ||
|
||||||
.map((proxy) => {
|
(proxy.type === 'snell' && String(proxy.version) === '4') ||
|
||||||
if (proxy.type === 'vmess') {
|
(proxy.type === 'vless' &&
|
||||||
// handle vmess aead
|
(typeof proxy.flow !== 'undefined' ||
|
||||||
if (isPresent(proxy, 'aead')) {
|
proxy['reality-opts']))
|
||||||
if (proxy.aead) {
|
) {
|
||||||
proxy.alterId = 0;
|
return false;
|
||||||
}
|
}
|
||||||
delete proxy.aead;
|
return true;
|
||||||
}
|
})
|
||||||
if (isPresent(proxy, 'sni')) {
|
.map((proxy) => {
|
||||||
proxy.servername = proxy.sni;
|
if (proxy.type === 'vmess') {
|
||||||
delete proxy.sni;
|
// handle vmess aead
|
||||||
}
|
if (isPresent(proxy, 'aead')) {
|
||||||
// https://dreamacro.github.io/clash/configuration/outbound.html#vmess
|
if (proxy.aead) {
|
||||||
if (
|
proxy.alterId = 0;
|
||||||
isPresent(proxy, 'cipher') &&
|
|
||||||
![
|
|
||||||
'auto',
|
|
||||||
'aes-128-gcm',
|
|
||||||
'chacha20-poly1305',
|
|
||||||
'none',
|
|
||||||
].includes(proxy.cipher)
|
|
||||||
) {
|
|
||||||
proxy.cipher = 'auto';
|
|
||||||
}
|
|
||||||
} else if (proxy.type === 'wireguard') {
|
|
||||||
proxy.keepalive =
|
|
||||||
proxy.keepalive ?? proxy['persistent-keepalive'];
|
|
||||||
proxy['persistent-keepalive'] = proxy.keepalive;
|
|
||||||
proxy['preshared-key'] =
|
|
||||||
proxy['preshared-key'] ?? proxy['pre-shared-key'];
|
|
||||||
proxy['pre-shared-key'] = proxy['preshared-key'];
|
|
||||||
} else if (proxy.type === 'vless') {
|
|
||||||
if (isPresent(proxy, 'sni')) {
|
|
||||||
proxy.servername = proxy.sni;
|
|
||||||
delete proxy.sni;
|
|
||||||
}
|
}
|
||||||
|
delete proxy.aead;
|
||||||
}
|
}
|
||||||
|
if (isPresent(proxy, 'sni')) {
|
||||||
|
proxy.servername = proxy.sni;
|
||||||
|
delete proxy.sni;
|
||||||
|
}
|
||||||
|
// https://dreamacro.github.io/clash/configuration/outbound.html#vmess
|
||||||
|
if (
|
||||||
|
isPresent(proxy, 'cipher') &&
|
||||||
|
![
|
||||||
|
'auto',
|
||||||
|
'aes-128-gcm',
|
||||||
|
'chacha20-poly1305',
|
||||||
|
'none',
|
||||||
|
].includes(proxy.cipher)
|
||||||
|
) {
|
||||||
|
proxy.cipher = 'auto';
|
||||||
|
}
|
||||||
|
} else if (proxy.type === 'wireguard') {
|
||||||
|
proxy.keepalive =
|
||||||
|
proxy.keepalive ?? proxy['persistent-keepalive'];
|
||||||
|
proxy['persistent-keepalive'] = proxy.keepalive;
|
||||||
|
proxy['preshared-key'] =
|
||||||
|
proxy['preshared-key'] ?? proxy['pre-shared-key'];
|
||||||
|
proxy['pre-shared-key'] = proxy['preshared-key'];
|
||||||
|
} else if (proxy.type === 'vless') {
|
||||||
|
if (isPresent(proxy, 'sni')) {
|
||||||
|
proxy.servername = proxy.sni;
|
||||||
|
delete proxy.sni;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
['vmess', 'vless'].includes(proxy.type) &&
|
||||||
|
proxy.network === 'http'
|
||||||
|
) {
|
||||||
|
let httpPath = proxy['http-opts']?.path;
|
||||||
if (
|
if (
|
||||||
['vmess', 'vless'].includes(proxy.type) &&
|
isPresent(proxy, 'http-opts.path') &&
|
||||||
proxy.network === 'http'
|
!Array.isArray(httpPath)
|
||||||
) {
|
) {
|
||||||
let httpPath = proxy['http-opts']?.path;
|
proxy['http-opts'].path = [httpPath];
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
let httpHost = proxy['http-opts']?.headers?.Host;
|
||||||
if (
|
if (
|
||||||
['trojan', 'tuic', 'hysteria', 'hysteria2'].includes(
|
isPresent(proxy, 'http-opts.headers.Host') &&
|
||||||
proxy.type,
|
!Array.isArray(httpHost)
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
delete proxy.tls;
|
proxy['http-opts'].headers.Host = [httpHost];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
['trojan', 'tuic', 'hysteria', 'hysteria2'].includes(
|
||||||
|
proxy.type,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
delete proxy.tls;
|
||||||
|
}
|
||||||
|
|
||||||
if (proxy['tls-fingerprint']) {
|
if (proxy['tls-fingerprint']) {
|
||||||
proxy.fingerprint = proxy['tls-fingerprint'];
|
proxy.fingerprint = proxy['tls-fingerprint'];
|
||||||
}
|
}
|
||||||
delete proxy['tls-fingerprint'];
|
delete proxy['tls-fingerprint'];
|
||||||
delete proxy.subName;
|
delete proxy.subName;
|
||||||
delete proxy.collectionName;
|
delete proxy.collectionName;
|
||||||
if (
|
if (
|
||||||
['grpc'].includes(proxy.network) &&
|
['grpc'].includes(proxy.network) &&
|
||||||
proxy[`${proxy.network}-opts`]
|
proxy[`${proxy.network}-opts`]
|
||||||
) {
|
) {
|
||||||
delete proxy[`${proxy.network}-opts`]['_grpc-type'];
|
delete proxy[`${proxy.network}-opts`]['_grpc-type'];
|
||||||
}
|
}
|
||||||
return ' - ' + JSON.stringify(proxy) + '\n';
|
return proxy;
|
||||||
})
|
});
|
||||||
.join('')
|
return type === 'internal'
|
||||||
);
|
? list
|
||||||
|
: 'proxies:\n' +
|
||||||
|
list
|
||||||
|
.map((proxy) => ' - ' + JSON.stringify(proxy) + '\n')
|
||||||
|
.join('');
|
||||||
};
|
};
|
||||||
return { type, produce };
|
return { type, produce };
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ import Loon_Producer from './loon';
|
|||||||
import URI_Producer from './uri';
|
import URI_Producer from './uri';
|
||||||
import V2Ray_Producer from './v2ray';
|
import V2Ray_Producer from './v2ray';
|
||||||
import QX_Producer from './qx';
|
import QX_Producer from './qx';
|
||||||
import ShadowRocket_Producer from './shadowrocket';
|
import Shadowrocket_Producer from './shadowrocket';
|
||||||
import Surfboard_Producer from './surfboard';
|
import Surfboard_Producer from './surfboard';
|
||||||
import singbox_Producer from './sing-box';
|
import singbox_Producer from './sing-box';
|
||||||
|
|
||||||
@ -19,6 +19,7 @@ function JSON_Producer() {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
QX: QX_Producer(),
|
QX: QX_Producer(),
|
||||||
|
QuantumultX: QX_Producer(),
|
||||||
Surge: Surge_Producer(),
|
Surge: Surge_Producer(),
|
||||||
SurgeMac: SurgeMac_Producer(),
|
SurgeMac: SurgeMac_Producer(),
|
||||||
Loon: Loon_Producer(),
|
Loon: Loon_Producer(),
|
||||||
@ -28,7 +29,8 @@ export default {
|
|||||||
V2Ray: V2Ray_Producer(),
|
V2Ray: V2Ray_Producer(),
|
||||||
JSON: JSON_Producer(),
|
JSON: JSON_Producer(),
|
||||||
Stash: Stash_Producer(),
|
Stash: Stash_Producer(),
|
||||||
ShadowRocket: ShadowRocket_Producer(),
|
Shadowrocket: Shadowrocket_Producer(),
|
||||||
|
ShadowRocket: Shadowrocket_Producer(),
|
||||||
Surfboard: Surfboard_Producer(),
|
Surfboard: Surfboard_Producer(),
|
||||||
'sing-box': singbox_Producer(),
|
'sing-box': singbox_Producer(),
|
||||||
};
|
};
|
||||||
|
@ -2,162 +2,161 @@ 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) => {
|
const produce = (proxies, type, opts = {}) => {
|
||||||
return (
|
const list = proxies
|
||||||
'proxies:\n' +
|
.filter((proxy) => {
|
||||||
proxies
|
if (opts['include-unsupported-proxy']) return true;
|
||||||
.filter((proxy) => {
|
if (proxy.type === 'snell' && String(proxy.version) === '4') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.map((proxy) => {
|
||||||
|
if (proxy.type === 'vmess') {
|
||||||
|
// handle vmess aead
|
||||||
|
if (isPresent(proxy, 'aead')) {
|
||||||
|
if (proxy.aead) {
|
||||||
|
proxy.alterId = 0;
|
||||||
|
}
|
||||||
|
delete proxy.aead;
|
||||||
|
}
|
||||||
|
if (isPresent(proxy, 'sni')) {
|
||||||
|
proxy.servername = proxy.sni;
|
||||||
|
delete proxy.sni;
|
||||||
|
}
|
||||||
|
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml#L400
|
||||||
|
// https://stash.wiki/proxy-protocols/proxy-types#vmess
|
||||||
if (
|
if (
|
||||||
proxy.type === 'snell' &&
|
isPresent(proxy, 'cipher') &&
|
||||||
String(proxy.version) === '4'
|
![
|
||||||
|
'auto',
|
||||||
|
'aes-128-gcm',
|
||||||
|
'chacha20-poly1305',
|
||||||
|
'none',
|
||||||
|
].includes(proxy.cipher)
|
||||||
) {
|
) {
|
||||||
return false;
|
proxy.cipher = 'auto';
|
||||||
}
|
}
|
||||||
return true;
|
} else if (proxy.type === 'tuic') {
|
||||||
})
|
if (isPresent(proxy, 'alpn')) {
|
||||||
.map((proxy) => {
|
proxy.alpn = Array.isArray(proxy.alpn)
|
||||||
if (proxy.type === 'vmess') {
|
? proxy.alpn
|
||||||
// handle vmess aead
|
: [proxy.alpn];
|
||||||
if (isPresent(proxy, 'aead')) {
|
} else {
|
||||||
if (proxy.aead) {
|
proxy.alpn = ['h3'];
|
||||||
proxy.alterId = 0;
|
|
||||||
}
|
|
||||||
delete proxy.aead;
|
|
||||||
}
|
|
||||||
if (isPresent(proxy, 'sni')) {
|
|
||||||
proxy.servername = proxy.sni;
|
|
||||||
delete proxy.sni;
|
|
||||||
}
|
|
||||||
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml#L400
|
|
||||||
// https://stash.wiki/proxy-protocols/proxy-types#vmess
|
|
||||||
if (
|
|
||||||
isPresent(proxy, 'cipher') &&
|
|
||||||
![
|
|
||||||
'auto',
|
|
||||||
'aes-128-gcm',
|
|
||||||
'chacha20-poly1305',
|
|
||||||
'none',
|
|
||||||
].includes(proxy.cipher)
|
|
||||||
) {
|
|
||||||
proxy.cipher = 'auto';
|
|
||||||
}
|
|
||||||
} else if (proxy.type === 'tuic') {
|
|
||||||
if (isPresent(proxy, 'alpn')) {
|
|
||||||
proxy.alpn = Array.isArray(proxy.alpn)
|
|
||||||
? proxy.alpn
|
|
||||||
: [proxy.alpn];
|
|
||||||
} else {
|
|
||||||
proxy.alpn = ['h3'];
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
isPresent(proxy, 'tfo') &&
|
|
||||||
!isPresent(proxy, 'fast-open')
|
|
||||||
) {
|
|
||||||
proxy['fast-open'] = proxy.tfo;
|
|
||||||
}
|
|
||||||
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/adapter/outbound/tuic.go#L197
|
|
||||||
if (
|
|
||||||
(!proxy.token || proxy.token.length === 0) &&
|
|
||||||
!isPresent(proxy, 'version')
|
|
||||||
) {
|
|
||||||
proxy.version = 5;
|
|
||||||
}
|
|
||||||
} else if (proxy.type === 'hysteria') {
|
|
||||||
// auth_str 将会在未来某个时候删除 但是有的机场不规范
|
|
||||||
if (
|
|
||||||
isPresent(proxy, 'auth_str') &&
|
|
||||||
!isPresent(proxy, 'auth-str')
|
|
||||||
) {
|
|
||||||
proxy['auth-str'] = proxy['auth_str'];
|
|
||||||
}
|
|
||||||
if (isPresent(proxy, 'alpn')) {
|
|
||||||
proxy.alpn = Array.isArray(proxy.alpn)
|
|
||||||
? proxy.alpn
|
|
||||||
: [proxy.alpn];
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
isPresent(proxy, 'tfo') &&
|
|
||||||
!isPresent(proxy, 'fast-open')
|
|
||||||
) {
|
|
||||||
proxy['fast-open'] = proxy.tfo;
|
|
||||||
}
|
|
||||||
} else if (proxy.type === 'hysteria2') {
|
|
||||||
if (
|
|
||||||
proxy['obfs-password'] &&
|
|
||||||
proxy.obfs == 'salamander'
|
|
||||||
) {
|
|
||||||
proxy.obfs = proxy['obfs-password'];
|
|
||||||
delete proxy['obfs-password'];
|
|
||||||
}
|
|
||||||
if (isPresent(proxy, 'alpn')) {
|
|
||||||
proxy.alpn = Array.isArray(proxy.alpn)
|
|
||||||
? proxy.alpn
|
|
||||||
: [proxy.alpn];
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
isPresent(proxy, 'tfo') &&
|
|
||||||
!isPresent(proxy, 'fast-open')
|
|
||||||
) {
|
|
||||||
proxy['fast-open'] = proxy.tfo;
|
|
||||||
}
|
|
||||||
} else if (proxy.type === 'wireguard') {
|
|
||||||
proxy.keepalive =
|
|
||||||
proxy.keepalive ?? proxy['persistent-keepalive'];
|
|
||||||
proxy['persistent-keepalive'] = proxy.keepalive;
|
|
||||||
proxy['preshared-key'] =
|
|
||||||
proxy['preshared-key'] ?? proxy['pre-shared-key'];
|
|
||||||
proxy['pre-shared-key'] = proxy['preshared-key'];
|
|
||||||
} else if (proxy.type === 'vless') {
|
|
||||||
if (isPresent(proxy, 'sni')) {
|
|
||||||
proxy.servername = proxy.sni;
|
|
||||||
delete proxy.sni;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
isPresent(proxy, 'tfo') &&
|
||||||
|
!isPresent(proxy, 'fast-open')
|
||||||
|
) {
|
||||||
|
proxy['fast-open'] = proxy.tfo;
|
||||||
|
}
|
||||||
|
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/adapter/outbound/tuic.go#L197
|
||||||
|
if (
|
||||||
|
(!proxy.token || proxy.token.length === 0) &&
|
||||||
|
!isPresent(proxy, 'version')
|
||||||
|
) {
|
||||||
|
proxy.version = 5;
|
||||||
|
}
|
||||||
|
} else if (proxy.type === 'hysteria') {
|
||||||
|
// auth_str 将会在未来某个时候删除 但是有的机场不规范
|
||||||
|
if (
|
||||||
|
isPresent(proxy, 'auth_str') &&
|
||||||
|
!isPresent(proxy, 'auth-str')
|
||||||
|
) {
|
||||||
|
proxy['auth-str'] = proxy['auth_str'];
|
||||||
|
}
|
||||||
|
if (isPresent(proxy, 'alpn')) {
|
||||||
|
proxy.alpn = Array.isArray(proxy.alpn)
|
||||||
|
? proxy.alpn
|
||||||
|
: [proxy.alpn];
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
isPresent(proxy, 'tfo') &&
|
||||||
|
!isPresent(proxy, 'fast-open')
|
||||||
|
) {
|
||||||
|
proxy['fast-open'] = proxy.tfo;
|
||||||
|
}
|
||||||
|
} else if (proxy.type === 'hysteria2') {
|
||||||
|
if (proxy['obfs-password'] && proxy.obfs == 'salamander') {
|
||||||
|
proxy.obfs = proxy['obfs-password'];
|
||||||
|
delete proxy['obfs-password'];
|
||||||
|
}
|
||||||
|
if (isPresent(proxy, 'alpn')) {
|
||||||
|
proxy.alpn = Array.isArray(proxy.alpn)
|
||||||
|
? proxy.alpn
|
||||||
|
: [proxy.alpn];
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
isPresent(proxy, 'tfo') &&
|
||||||
|
!isPresent(proxy, 'fast-open')
|
||||||
|
) {
|
||||||
|
proxy['fast-open'] = proxy.tfo;
|
||||||
|
}
|
||||||
|
} else if (proxy.type === 'wireguard') {
|
||||||
|
proxy.keepalive =
|
||||||
|
proxy.keepalive ?? proxy['persistent-keepalive'];
|
||||||
|
proxy['persistent-keepalive'] = proxy.keepalive;
|
||||||
|
proxy['preshared-key'] =
|
||||||
|
proxy['preshared-key'] ?? proxy['pre-shared-key'];
|
||||||
|
proxy['pre-shared-key'] = proxy['preshared-key'];
|
||||||
|
} else if (proxy.type === 'vless') {
|
||||||
|
if (isPresent(proxy, 'sni')) {
|
||||||
|
proxy.servername = proxy.sni;
|
||||||
|
delete proxy.sni;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
['vmess', 'vless'].includes(proxy.type) &&
|
||||||
|
proxy.network === 'http'
|
||||||
|
) {
|
||||||
|
let httpPath = proxy['http-opts']?.path;
|
||||||
if (
|
if (
|
||||||
['vmess', 'vless'].includes(proxy.type) &&
|
isPresent(proxy, 'http-opts.path') &&
|
||||||
proxy.network === 'http'
|
!Array.isArray(httpPath)
|
||||||
) {
|
) {
|
||||||
let httpPath = proxy['http-opts']?.path;
|
proxy['http-opts'].path = [httpPath];
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
let httpHost = proxy['http-opts']?.headers?.Host;
|
||||||
|
if (
|
||||||
|
isPresent(proxy, 'http-opts.headers.Host') &&
|
||||||
|
!Array.isArray(httpHost)
|
||||||
|
) {
|
||||||
|
proxy['http-opts'].headers.Host = [httpHost];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
['trojan', 'tuic', 'hysteria', 'hysteria2'].includes(
|
['trojan', 'tuic', 'hysteria', 'hysteria2'].includes(
|
||||||
proxy.type,
|
proxy.type,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
delete proxy.tls;
|
delete proxy.tls;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proxy['tls-fingerprint']) {
|
if (proxy['tls-fingerprint']) {
|
||||||
proxy.fingerprint = proxy['tls-fingerprint'];
|
proxy.fingerprint = proxy['tls-fingerprint'];
|
||||||
}
|
}
|
||||||
delete proxy['tls-fingerprint'];
|
delete proxy['tls-fingerprint'];
|
||||||
delete proxy.subName;
|
delete proxy.subName;
|
||||||
delete proxy.collectionName;
|
delete proxy.collectionName;
|
||||||
if (
|
if (
|
||||||
['grpc'].includes(proxy.network) &&
|
['grpc'].includes(proxy.network) &&
|
||||||
proxy[`${proxy.network}-opts`]
|
proxy[`${proxy.network}-opts`]
|
||||||
) {
|
) {
|
||||||
delete proxy[`${proxy.network}-opts`]['_grpc-type'];
|
delete proxy[`${proxy.network}-opts`]['_grpc-type'];
|
||||||
}
|
}
|
||||||
return ' - ' + JSON.stringify(proxy) + '\n';
|
return proxy;
|
||||||
})
|
});
|
||||||
.join('')
|
return type === 'internal'
|
||||||
);
|
? list
|
||||||
|
: 'proxies:\n' +
|
||||||
|
list
|
||||||
|
.map((proxy) => {
|
||||||
|
return ' - ' + JSON.stringify(proxy) + '\n';
|
||||||
|
})
|
||||||
|
.join('');
|
||||||
};
|
};
|
||||||
return { type, produce };
|
return { type, produce };
|
||||||
}
|
}
|
||||||
|
@ -582,7 +582,7 @@ const wireguardParser = (proxy = {}) => {
|
|||||||
|
|
||||||
export default function singbox_Producer() {
|
export default function singbox_Producer() {
|
||||||
const type = 'ALL';
|
const type = 'ALL';
|
||||||
const produce = (proxies, type) => {
|
const produce = (proxies, type, opts = {}) => {
|
||||||
const list = [];
|
const list = [];
|
||||||
ClashMeta_Producer()
|
ClashMeta_Producer()
|
||||||
.produce(proxies, 'internal', { 'include-unsupported-proxy': true })
|
.produce(proxies, 'internal', { 'include-unsupported-proxy': true })
|
||||||
@ -610,9 +610,15 @@ export default function singbox_Producer() {
|
|||||||
list.push(ssParser(proxy));
|
list.push(ssParser(proxy));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// case 'ssr':
|
case 'ssr':
|
||||||
// list.push(ssrParser(proxy));
|
if (opts['include-unsupported-proxy']) {
|
||||||
// break;
|
list.push(ssrParser(proxy));
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
`Platform sing-box does not support proxy type: ${proxy.type}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'vmess':
|
case 'vmess':
|
||||||
if (
|
if (
|
||||||
!proxy.network ||
|
!proxy.network ||
|
||||||
|
@ -20,7 +20,15 @@ async function downloadSubscription(req, res) {
|
|||||||
req.query.target || getPlatformFromHeaders(req.headers) || 'JSON';
|
req.query.target || getPlatformFromHeaders(req.headers) || 'JSON';
|
||||||
|
|
||||||
$.info(`正在下载订阅:${name}`);
|
$.info(`正在下载订阅:${name}`);
|
||||||
let { url, ua, content, mergeSources, ignoreFailedRemoteSub } = req.query;
|
let {
|
||||||
|
url,
|
||||||
|
ua,
|
||||||
|
content,
|
||||||
|
mergeSources,
|
||||||
|
ignoreFailedRemoteSub,
|
||||||
|
produceType,
|
||||||
|
includeUnsupportedProxy,
|
||||||
|
} = req.query;
|
||||||
if (url) {
|
if (url) {
|
||||||
url = decodeURIComponent(url);
|
url = decodeURIComponent(url);
|
||||||
$.info(`指定远程订阅 URL: ${url}`);
|
$.info(`指定远程订阅 URL: ${url}`);
|
||||||
@ -41,6 +49,14 @@ async function downloadSubscription(req, res) {
|
|||||||
ignoreFailedRemoteSub = decodeURIComponent(ignoreFailedRemoteSub);
|
ignoreFailedRemoteSub = decodeURIComponent(ignoreFailedRemoteSub);
|
||||||
$.info(`指定忽略失败的远程订阅: ${ignoreFailedRemoteSub}`);
|
$.info(`指定忽略失败的远程订阅: ${ignoreFailedRemoteSub}`);
|
||||||
}
|
}
|
||||||
|
if (produceType) {
|
||||||
|
produceType = decodeURIComponent(produceType);
|
||||||
|
$.info(`指定生产类型: ${produceType}`);
|
||||||
|
}
|
||||||
|
if (includeUnsupportedProxy) {
|
||||||
|
includeUnsupportedProxy = decodeURIComponent(includeUnsupportedProxy);
|
||||||
|
$.info(`包含不支持的节点: ${includeUnsupportedProxy}`);
|
||||||
|
}
|
||||||
|
|
||||||
const allSubs = $.read(SUBS_KEY);
|
const allSubs = $.read(SUBS_KEY);
|
||||||
const sub = findByName(allSubs, name);
|
const sub = findByName(allSubs, name);
|
||||||
@ -55,6 +71,10 @@ async function downloadSubscription(req, res) {
|
|||||||
content,
|
content,
|
||||||
mergeSources,
|
mergeSources,
|
||||||
ignoreFailedRemoteSub,
|
ignoreFailedRemoteSub,
|
||||||
|
produceType,
|
||||||
|
produceOpts: {
|
||||||
|
'include-unsupported-proxy': includeUnsupportedProxy,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (sub.source !== 'local' || url) {
|
if (sub.source !== 'local' || url) {
|
||||||
@ -121,12 +141,22 @@ async function downloadCollection(req, res) {
|
|||||||
|
|
||||||
$.info(`正在下载组合订阅:${name}`);
|
$.info(`正在下载组合订阅:${name}`);
|
||||||
|
|
||||||
let { ignoreFailedRemoteSub } = req.query;
|
let { ignoreFailedRemoteSub, produceType, includeUnsupportedProxy } =
|
||||||
|
req.query;
|
||||||
|
|
||||||
if (ignoreFailedRemoteSub != null && ignoreFailedRemoteSub !== '') {
|
if (ignoreFailedRemoteSub != null && ignoreFailedRemoteSub !== '') {
|
||||||
ignoreFailedRemoteSub = decodeURIComponent(ignoreFailedRemoteSub);
|
ignoreFailedRemoteSub = decodeURIComponent(ignoreFailedRemoteSub);
|
||||||
$.info(`指定忽略失败的远程订阅: ${ignoreFailedRemoteSub}`);
|
$.info(`指定忽略失败的远程订阅: ${ignoreFailedRemoteSub}`);
|
||||||
}
|
}
|
||||||
|
if (produceType) {
|
||||||
|
produceType = decodeURIComponent(produceType);
|
||||||
|
$.info(`指定生产类型: ${produceType}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (includeUnsupportedProxy) {
|
||||||
|
includeUnsupportedProxy = decodeURIComponent(includeUnsupportedProxy);
|
||||||
|
$.info(`包含不支持的节点: ${includeUnsupportedProxy}`);
|
||||||
|
}
|
||||||
|
|
||||||
if (collection) {
|
if (collection) {
|
||||||
try {
|
try {
|
||||||
@ -135,6 +165,10 @@ async function downloadCollection(req, res) {
|
|||||||
name,
|
name,
|
||||||
platform,
|
platform,
|
||||||
ignoreFailedRemoteSub,
|
ignoreFailedRemoteSub,
|
||||||
|
produceType,
|
||||||
|
produceOpts: {
|
||||||
|
'include-unsupported-proxy': includeUnsupportedProxy,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// forward flow header from the first subscription in this collection
|
// forward flow header from the first subscription in this collection
|
||||||
|
@ -3,6 +3,7 @@ import { ProxyUtils } from '@/core/proxy-utils';
|
|||||||
import { findByName } from '@/utils/database';
|
import { findByName } from '@/utils/database';
|
||||||
import { success, failed } from './response';
|
import { success, failed } from './response';
|
||||||
import download from '@/utils/download';
|
import download from '@/utils/download';
|
||||||
|
import { render } from '@/utils/tpl';
|
||||||
import { SUBS_KEY } from '@/constants';
|
import { SUBS_KEY } from '@/constants';
|
||||||
import $ from '@/core/app';
|
import $ from '@/core/app';
|
||||||
|
|
||||||
@ -59,10 +60,14 @@ async function previewFile(req, res) {
|
|||||||
}
|
}
|
||||||
// parse proxies
|
// parse proxies
|
||||||
const files = (Array.isArray(content) ? content : [content]).flat();
|
const files = (Array.isArray(content) ? content : [content]).flat();
|
||||||
const filesContent = files
|
let filesContent = files
|
||||||
.filter((i) => i != null && i !== '')
|
.filter((i) => i != null && i !== '')
|
||||||
.join('\n');
|
.join('\n');
|
||||||
|
|
||||||
|
if (file.isTpl) {
|
||||||
|
filesContent = await render(filesContent);
|
||||||
|
}
|
||||||
|
|
||||||
// apply processors
|
// apply processors
|
||||||
const processed =
|
const processed =
|
||||||
Array.isArray(file.process) && file.process.length > 0
|
Array.isArray(file.process) && file.process.length > 0
|
||||||
|
@ -13,6 +13,7 @@ import download from '@/utils/download';
|
|||||||
import { ProxyUtils } from '@/core/proxy-utils';
|
import { ProxyUtils } from '@/core/proxy-utils';
|
||||||
import { RuleUtils } from '@/core/rule-utils';
|
import { RuleUtils } from '@/core/rule-utils';
|
||||||
import { syncToGist } from '@/restful/artifacts';
|
import { syncToGist } from '@/restful/artifacts';
|
||||||
|
import { render } from '@/utils/tpl';
|
||||||
|
|
||||||
export default function register($app) {
|
export default function register($app) {
|
||||||
// Initialization
|
// Initialization
|
||||||
@ -33,6 +34,8 @@ async function produceArtifact({
|
|||||||
mergeSources,
|
mergeSources,
|
||||||
ignoreFailedRemoteSub,
|
ignoreFailedRemoteSub,
|
||||||
ignoreFailedRemoteFile,
|
ignoreFailedRemoteFile,
|
||||||
|
produceType,
|
||||||
|
produceOpts = {},
|
||||||
}) {
|
}) {
|
||||||
platform = platform || 'JSON';
|
platform = platform || 'JSON';
|
||||||
|
|
||||||
@ -154,7 +157,7 @@ async function produceArtifact({
|
|||||||
exist[proxy.name] = true;
|
exist[proxy.name] = true;
|
||||||
}
|
}
|
||||||
// produce
|
// produce
|
||||||
return ProxyUtils.produce(proxies, platform);
|
return ProxyUtils.produce(proxies, platform, produceType, produceOpts);
|
||||||
} else if (type === 'collection') {
|
} else if (type === 'collection') {
|
||||||
const allSubs = $.read(SUBS_KEY);
|
const allSubs = $.read(SUBS_KEY);
|
||||||
const allCols = $.read(COLLECTIONS_KEY);
|
const allCols = $.read(COLLECTIONS_KEY);
|
||||||
@ -301,7 +304,7 @@ async function produceArtifact({
|
|||||||
}
|
}
|
||||||
exist[proxy.name] = true;
|
exist[proxy.name] = true;
|
||||||
}
|
}
|
||||||
return ProxyUtils.produce(proxies, platform);
|
return ProxyUtils.produce(proxies, platform, produceType, produceOpts);
|
||||||
} else if (type === 'rule') {
|
} else if (type === 'rule') {
|
||||||
const allRules = $.read(RULES_KEY);
|
const allRules = $.read(RULES_KEY);
|
||||||
const rule = findByName(allRules, name);
|
const rule = findByName(allRules, name);
|
||||||
@ -419,10 +422,13 @@ async function produceArtifact({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const files = (Array.isArray(raw) ? raw : [raw]).flat();
|
const files = (Array.isArray(raw) ? raw : [raw]).flat();
|
||||||
const filesContent = files
|
let filesContent = files
|
||||||
.filter((i) => i != null && i !== '')
|
.filter((i) => i != null && i !== '')
|
||||||
.join('\n');
|
.join('\n');
|
||||||
|
|
||||||
|
if (file.isTpl) {
|
||||||
|
filesContent = await render(filesContent);
|
||||||
|
}
|
||||||
// apply processors
|
// apply processors
|
||||||
const processed =
|
const processed =
|
||||||
Array.isArray(file.process) && file.process.length > 0
|
Array.isArray(file.process) && file.process.length > 0
|
||||||
|
@ -20,7 +20,7 @@ export function getPlatformFromHeaders(headers) {
|
|||||||
} else if (UA.indexOf('Decar') !== -1 || UA.indexOf('Loon') !== -1) {
|
} else if (UA.indexOf('Decar') !== -1 || UA.indexOf('Loon') !== -1) {
|
||||||
return 'Loon';
|
return 'Loon';
|
||||||
} else if (UA.indexOf('Shadowrocket') !== -1) {
|
} else if (UA.indexOf('Shadowrocket') !== -1) {
|
||||||
return 'ShadowRocket';
|
return 'Shadowrocket';
|
||||||
} else if (UA.indexOf('Stash') !== -1) {
|
} else if (UA.indexOf('Stash') !== -1) {
|
||||||
return 'Stash';
|
return 'Stash';
|
||||||
} else if (
|
} else if (
|
||||||
|
210
backend/src/utils/tpl.js
Normal file
210
backend/src/utils/tpl.js
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
import nunjucks from 'nunjucks';
|
||||||
|
import { ProxyUtils } from '@/core/proxy-utils';
|
||||||
|
import { produceArtifact } from '@/restful/sync';
|
||||||
|
import lodash from 'lodash';
|
||||||
|
import $ from '@/core/app';
|
||||||
|
import scriptResourceCache from '@/utils/script-resource-cache';
|
||||||
|
import { getFlowHeaders, parseFlowHeaders, flowTransfer } from '@/utils/flow';
|
||||||
|
const flowUtils = { getFlowHeaders, parseFlowHeaders, flowTransfer };
|
||||||
|
const n = nunjucks.configure({ autoescape: false });
|
||||||
|
|
||||||
|
n.addFilter(
|
||||||
|
'produceArtifact',
|
||||||
|
(...args) => {
|
||||||
|
const callback = args.pop();
|
||||||
|
const name = args[0];
|
||||||
|
const type = args[1];
|
||||||
|
const platform = args[2];
|
||||||
|
const produceType = args[3];
|
||||||
|
const nameRegex = args[4];
|
||||||
|
const nameRegexFlags = args[5];
|
||||||
|
produceArtifact({
|
||||||
|
type,
|
||||||
|
name,
|
||||||
|
platform,
|
||||||
|
produceType,
|
||||||
|
})
|
||||||
|
.then((artifact) => {
|
||||||
|
callback(
|
||||||
|
null,
|
||||||
|
artifact.filter(({ tag }) =>
|
||||||
|
nameRegex
|
||||||
|
? new RegExp(nameRegex, nameRegexFlags).test(tag)
|
||||||
|
: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
$.error(`produceArtifact filter error: ${e.message ?? e}`);
|
||||||
|
callback(e);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
n.addFilter(
|
||||||
|
'subNode',
|
||||||
|
(...args) => {
|
||||||
|
const callback = args.pop();
|
||||||
|
const name = args[0];
|
||||||
|
const nameRegex = args[1];
|
||||||
|
const nameRegexFlags = args[2];
|
||||||
|
produceArtifact({
|
||||||
|
type: 'subscription',
|
||||||
|
name,
|
||||||
|
platform: 'sing-box',
|
||||||
|
produceType: 'internal',
|
||||||
|
})
|
||||||
|
.then((artifact) => {
|
||||||
|
callback(
|
||||||
|
null,
|
||||||
|
JSON.stringify(
|
||||||
|
artifact.filter(({ tag }) =>
|
||||||
|
nameRegex
|
||||||
|
? new RegExp(nameRegex, nameRegexFlags).test(
|
||||||
|
tag,
|
||||||
|
)
|
||||||
|
: true,
|
||||||
|
),
|
||||||
|
).replace(/(^\[|\]$)/g, ''),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
$.error(`subNode filter error: ${e.message ?? e}`);
|
||||||
|
callback(e);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
n.addFilter(
|
||||||
|
'colNode',
|
||||||
|
(...args) => {
|
||||||
|
const callback = args.pop();
|
||||||
|
const name = args[0];
|
||||||
|
const nameRegex = args[1];
|
||||||
|
const nameRegexFlags = args[2];
|
||||||
|
produceArtifact({
|
||||||
|
type: 'collection',
|
||||||
|
name,
|
||||||
|
platform: 'sing-box',
|
||||||
|
produceType: 'internal',
|
||||||
|
})
|
||||||
|
.then((artifact) => {
|
||||||
|
callback(
|
||||||
|
null,
|
||||||
|
JSON.stringify(
|
||||||
|
artifact.filter(({ tag }) =>
|
||||||
|
nameRegex
|
||||||
|
? new RegExp(nameRegex, nameRegexFlags).test(
|
||||||
|
tag,
|
||||||
|
)
|
||||||
|
: true,
|
||||||
|
),
|
||||||
|
).replace(/(^\[|\]$)/g, ''),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
$.error(`colNode filter error: ${e.message ?? e}`);
|
||||||
|
callback(e);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
n.addFilter(
|
||||||
|
'sub',
|
||||||
|
(...args) => {
|
||||||
|
const callback = args.pop();
|
||||||
|
const name = args[0];
|
||||||
|
const nameRegex = args[1];
|
||||||
|
const nameRegexFlags = args[2];
|
||||||
|
produceArtifact({
|
||||||
|
type: 'subscription',
|
||||||
|
name,
|
||||||
|
platform: 'sing-box',
|
||||||
|
produceType: 'internal',
|
||||||
|
})
|
||||||
|
.then((artifact) => {
|
||||||
|
callback(
|
||||||
|
null,
|
||||||
|
JSON.stringify(
|
||||||
|
artifact
|
||||||
|
.filter(({ tag }) =>
|
||||||
|
nameRegex
|
||||||
|
? new RegExp(
|
||||||
|
nameRegex,
|
||||||
|
nameRegexFlags,
|
||||||
|
).test(tag)
|
||||||
|
: true,
|
||||||
|
)
|
||||||
|
.map((p) => p.tag),
|
||||||
|
).replace(/(^\[|\]$)/g, ''),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
$.error(`sub filter error: ${e.message ?? e}`);
|
||||||
|
callback(e);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
n.addFilter(
|
||||||
|
'col',
|
||||||
|
(...args) => {
|
||||||
|
const callback = args.pop();
|
||||||
|
const name = args[0];
|
||||||
|
const nameRegex = args[1];
|
||||||
|
const nameRegexFlags = args[2];
|
||||||
|
produceArtifact({
|
||||||
|
type: 'collection',
|
||||||
|
name,
|
||||||
|
platform: 'sing-box',
|
||||||
|
produceType: 'internal',
|
||||||
|
})
|
||||||
|
.then((artifact) => {
|
||||||
|
callback(
|
||||||
|
null,
|
||||||
|
JSON.stringify(
|
||||||
|
artifact
|
||||||
|
.filter(({ tag }) =>
|
||||||
|
nameRegex
|
||||||
|
? new RegExp(
|
||||||
|
nameRegex,
|
||||||
|
nameRegexFlags,
|
||||||
|
).test(tag)
|
||||||
|
: true,
|
||||||
|
)
|
||||||
|
.map((p) => p.tag),
|
||||||
|
).replace(/(^\[|\]$)/g, ''),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
$.error(`col filter error: ${e.message ?? e}`);
|
||||||
|
callback(e);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
export const render = async (tpl = '', data = {}) => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
n.renderString(
|
||||||
|
tpl,
|
||||||
|
{
|
||||||
|
$substore: $,
|
||||||
|
lodash: lodash,
|
||||||
|
ProxyUtils: ProxyUtils,
|
||||||
|
scriptResourceCache: scriptResourceCache,
|
||||||
|
flowUtils: flowUtils,
|
||||||
|
// produceArtifact: produceArtifact,
|
||||||
|
...data,
|
||||||
|
},
|
||||||
|
(e, result) => {
|
||||||
|
if (e) {
|
||||||
|
$.error(`rendering error: ${e.message ?? e}`);
|
||||||
|
resolve('');
|
||||||
|
} else {
|
||||||
|
resolve(result);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
Loading…
x
Reference in New Issue
Block a user