Compare commits

..

10 Commits

8 changed files with 201 additions and 19 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "sub-store",
"version": "2.14.120",
"version": "2.14.129",
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.",
"main": "src/main.js",
"scripts": {
@@ -18,6 +18,7 @@
"body-parser": "^1.19.0",
"connect-history-api-fallback": "^2.0.0",
"express": "^4.17.1",
"http-proxy-middleware": "^2.0.6",
"js-base64": "^3.7.2",
"lodash": "^4.17.21",
"request": "^2.88.2",

87
backend/pnpm-lock.yaml generated
View File

@@ -17,6 +17,9 @@ dependencies:
express:
specifier: ^4.17.1
version: registry.npmmirror.com/express@4.17.1
http-proxy-middleware:
specifier: ^2.0.6
version: registry.npmmirror.com/http-proxy-middleware@2.0.6
js-base64:
specifier: ^3.7.2
version: registry.npmmirror.com/js-base64@3.7.2
@@ -2031,6 +2034,14 @@ packages:
chokidar: registry.npmmirror.com/chokidar@3.5.3
dev: true
registry.npmmirror.com/@types/http-proxy@1.17.14:
resolution: {integrity: sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/http-proxy/-/http-proxy-1.17.14.tgz}
name: '@types/http-proxy'
version: 1.17.14
dependencies:
'@types/node': registry.npmmirror.com/@types/node@17.0.35
dev: false
registry.npmmirror.com/@types/json-schema@7.0.11:
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.11.tgz}
name: '@types/json-schema'
@@ -2055,7 +2066,6 @@ packages:
resolution: {integrity: sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/node/-/node-17.0.35.tgz}
name: '@types/node'
version: 17.0.35
dev: true
registry.npmmirror.com/@types/responselike@1.0.0:
resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/responselike/-/responselike-1.0.0.tgz}
@@ -2809,7 +2819,6 @@ packages:
engines: {node: '>=8'}
dependencies:
fill-range: registry.npmmirror.com/fill-range@7.0.1
dev: true
registry.npmmirror.com/brorand@1.1.0:
resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/brorand/-/brorand-1.1.0.tgz}
@@ -4876,7 +4885,6 @@ packages:
engines: {node: '>=8'}
dependencies:
to-regex-range: registry.npmmirror.com/to-regex-range@5.0.1
dev: true
registry.npmmirror.com/finalhandler@1.1.2:
resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/finalhandler/-/finalhandler-1.1.2.tgz}
@@ -5015,6 +5023,18 @@ packages:
readable-stream: registry.npmmirror.com/readable-stream@2.3.7
dev: true
registry.npmmirror.com/follow-redirects@1.15.2:
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz}
name: follow-redirects
version: 1.15.2
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
dev: false
registry.npmmirror.com/for-each@0.3.3:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/for-each/-/for-each-0.3.3.tgz}
name: for-each
@@ -5763,6 +5783,39 @@ packages:
toidentifier: registry.npmmirror.com/toidentifier@1.0.0
dev: false
registry.npmmirror.com/http-proxy-middleware@2.0.6:
resolution: {integrity: sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz}
name: http-proxy-middleware
version: 2.0.6
engines: {node: '>=12.0.0'}
peerDependencies:
'@types/express': ^4.17.13
peerDependenciesMeta:
'@types/express':
optional: true
dependencies:
'@types/http-proxy': registry.npmmirror.com/@types/http-proxy@1.17.14
http-proxy: registry.npmmirror.com/http-proxy@1.18.1
is-glob: registry.npmmirror.com/is-glob@4.0.3
is-plain-obj: registry.npmmirror.com/is-plain-obj@3.0.0
micromatch: registry.npmmirror.com/micromatch@4.0.5
transitivePeerDependencies:
- debug
dev: false
registry.npmmirror.com/http-proxy@1.18.1:
resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/http-proxy/-/http-proxy-1.18.1.tgz}
name: http-proxy
version: 1.18.1
engines: {node: '>=8.0.0'}
dependencies:
eventemitter3: registry.npmmirror.com/eventemitter3@4.0.7
follow-redirects: registry.npmmirror.com/follow-redirects@1.15.2
requires-port: registry.npmmirror.com/requires-port@1.0.0
transitivePeerDependencies:
- debug
dev: false
registry.npmmirror.com/http-signature@1.2.0:
resolution: {integrity: sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/http-signature/-/http-signature-1.2.0.tgz}
name: http-signature
@@ -6116,7 +6169,6 @@ packages:
name: is-extglob
version: 2.1.1
engines: {node: '>=0.10.0'}
dev: true
registry.npmmirror.com/is-fullwidth-code-point@1.0.0:
resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz}
@@ -6159,7 +6211,6 @@ packages:
engines: {node: '>=0.10.0'}
dependencies:
is-extglob: registry.npmmirror.com/is-extglob@2.1.1
dev: true
registry.npmmirror.com/is-installed-globally@0.4.0:
resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz}
@@ -6222,7 +6273,6 @@ packages:
name: is-number
version: 7.0.0
engines: {node: '>=0.12.0'}
dev: true
registry.npmmirror.com/is-obj@2.0.0:
resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-obj/-/is-obj-2.0.0.tgz}
@@ -6245,6 +6295,13 @@ packages:
engines: {node: '>=8'}
dev: true
registry.npmmirror.com/is-plain-obj@3.0.0:
resolution: {integrity: sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz}
name: is-plain-obj
version: 3.0.0
engines: {node: '>=10'}
dev: false
registry.npmmirror.com/is-plain-object@2.0.4:
resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/is-plain-object/-/is-plain-object-2.0.4.tgz}
name: is-plain-object
@@ -6933,6 +6990,16 @@ packages:
- supports-color
dev: true
registry.npmmirror.com/micromatch@4.0.5:
resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/micromatch/-/micromatch-4.0.5.tgz}
name: micromatch
version: 4.0.5
engines: {node: '>=8.6'}
dependencies:
braces: registry.npmmirror.com/braces@3.0.2
picomatch: registry.npmmirror.com/picomatch@2.3.1
dev: false
registry.npmmirror.com/miller-rabin@4.0.1:
resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/miller-rabin/-/miller-rabin-4.0.1.tgz}
name: miller-rabin
@@ -7811,7 +7878,6 @@ packages:
name: picomatch
version: 2.3.1
engines: {node: '>=8.6'}
dev: true
registry.npmmirror.com/pify@2.3.0:
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/pify/-/pify-2.3.0.tgz}
@@ -8441,6 +8507,12 @@ packages:
version: 1.0.1
dev: true
registry.npmmirror.com/requires-port@1.0.0:
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/requires-port/-/requires-port-1.0.0.tgz}
name: requires-port
version: 1.0.0
dev: false
registry.npmmirror.com/resolve-dir@1.0.1:
resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/resolve-dir/-/resolve-dir-1.0.1.tgz}
name: resolve-dir
@@ -9402,7 +9474,6 @@ packages:
engines: {node: '>=8.0'}
dependencies:
is-number: registry.npmmirror.com/is-number@7.0.0
dev: true
registry.npmmirror.com/to-regex@3.0.2:
resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==, registry: http://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/to-regex/-/to-regex-3.0.2.tgz}

View File

@@ -409,10 +409,10 @@ function URI_VLESS() {
function URI_Hysteria2() {
const name = 'URI Hysteria2 Parser';
const test = (line) => {
return /^hysteria2:\/\//.test(line);
return /^(hysteria2|hy2):\/\//.test(line);
};
const parse = (line) => {
line = line.split('hysteria2://')[1];
line = line.split(/(hysteria2|hy2):\/\//)[2];
// eslint-disable-next-line no-unused-vars
let [__, password, server, ___, port, addons, name] =
/^(.*?)@(.*?)(:(\d+))?\/?\?(.*?)(?:#(.*?))$/.exec(line);

View File

@@ -7,6 +7,7 @@ export default function Clash_Producer() {
// https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml#L532
// github.com/Dreamacro/clash/pull/2891/files
// filter unsupported proxies
// https://clash.wiki/configuration/outbound.html#shadowsocks
proxies = proxies.filter((proxy) => {
if (
![
@@ -20,6 +21,23 @@ export default function Clash_Producer() {
'trojan',
'wireguard',
].includes(proxy.type) ||
(proxy.type === 'ss' &&
![
'aes-128-gcm',
'aes-192-gcm',
'aes-256-gcm',
'aes-128-cfb',
'aes-192-cfb',
'aes-256-cfb',
'aes-128-ctr',
'aes-192-ctr',
'aes-256-ctr',
'rc4-md5',
'chacha20-ietf',
'xchacha20',
'chacha20-ietf-poly1305',
'xchacha20-ietf-poly1305',
].includes(proxy.cipher)) ||
(proxy.type === 'snell' && String(proxy.version) === '4') ||
(proxy.type === 'vless' &&
(typeof proxy.flow !== 'undefined' ||

View File

@@ -99,7 +99,7 @@ function trojan(proxy) {
if (proxy.network === 'ws') {
result.append(`,transport=ws`);
result.appendIfPresent(
`,path=${proxy['ws-opts'].path}`,
`,path=${proxy['ws-opts']?.path}`,
'ws-opts.path',
);
result.appendIfPresent(

View File

@@ -3,6 +3,7 @@ import { isPresent } from '@/core/proxy-utils/producers/utils';
export default function Stash_Producer() {
const type = 'ALL';
const produce = (proxies) => {
// https://stash.wiki/proxy-protocols/proxy-types#shadowsocks
return (
'proxies:\n' +
proxies
@@ -22,6 +23,23 @@ export default function Stash_Producer() {
'hysteria',
'hysteria2',
].includes(proxy.type) ||
(proxy.type === 'ss' &&
![
'aes-128-gcm',
'aes-192-gcm',
'aes-256-gcm',
'aes-128-cfb',
'aes-192-cfb',
'aes-256-cfb',
'aes-128-ctr',
'aes-192-ctr',
'aes-256-ctr',
'rc4-md5',
'chacha20-ietf',
'xchacha20',
'chacha20-ietf-poly1305',
'xchacha20-ietf-poly1305',
].includes(proxy.cipher)) ||
(proxy.type === 'snell' &&
String(proxy.version) === '4') ||
(proxy.type === 'vless' && proxy['reality-opts'])

View File

@@ -1,5 +1,7 @@
import express from '@/vendor/express';
import $ from '@/core/app';
import migrate from '@/utils/migration';
import download from '@/utils/download';
import registerSubscriptionRoutes from './subscriptions';
import registerCollectionRoutes from './collections';
@@ -18,8 +20,8 @@ export default function serve() {
let port;
let host;
if ($.env.isNode) {
port = eval('process.env.SUB_STORE_BACKEND_API_PORT');
host = eval('process.env.SUB_STORE_BACKEND_API_HOST');
port = eval('process.env.SUB_STORE_BACKEND_API_PORT') || 3000;
host = eval('process.env.SUB_STORE_BACKEND_API_HOST') || '::';
}
const $app = express({ substore: $, port, host });
// register routes
@@ -41,6 +43,8 @@ export default function serve() {
if ($.env.isNode) {
const path = eval(`require("path")`);
const fs = eval(`require("fs")`);
const data_url = eval('process.env.SUB_STORE_DATA_URL');
const fe_be_path = eval('process.env.SUB_STORE_FRONTEND_BACKEND_PATH');
const fe_port = eval('process.env.SUB_STORE_FRONTEND_PORT') || 3001;
const fe_host =
eval('process.env.SUB_STORE_FRONTEND_HOST') || host || '::';
@@ -59,24 +63,96 @@ export default function serve() {
const express_ = eval(`require("express")`);
const history = eval(`require("connect-history-api-fallback")`);
const { createProxyMiddleware } = eval(
`require("http-proxy-middleware")`,
);
const app = express_();
const staticFileMiddleware = express_.static(fe_path);
let be_api_rewrite = '';
let be_download_rewrite = '';
let be_api = '/api/';
let be_download = '/download/';
if (fe_be_path) {
if (!fe_be_path.startsWith('/')) {
throw new Error(
'SUB_STORE_FRONTEND_BACKEND_PATH should start with /',
);
}
be_api_rewrite = `${
fe_be_path === '/' ? '' : fe_be_path
}${be_api}`;
be_download_rewrite = `${
fe_be_path === '/' ? '' : fe_be_path
}${be_download}`;
app.use(
be_api_rewrite,
createProxyMiddleware({
target: `http://127.0.0.1:${port}`,
changeOrigin: true,
pathRewrite: (path) => {
return path.startsWith(be_api_rewrite)
? path.replace(be_api_rewrite, be_api)
: path;
},
}),
);
app.use(
be_download_rewrite,
createProxyMiddleware({
target: `http://127.0.0.1:${port}`,
changeOrigin: true,
pathRewrite: (path) => {
return path.startsWith(be_download_rewrite)
? path.replace(be_download_rewrite, be_download)
: path;
},
}),
);
}
app.use(staticFileMiddleware);
app.use(
history({
disableDotRule: true,
verbose: true,
verbose: false,
}),
);
app.use(staticFileMiddleware);
const listener = app.listen(fe_port, fe_host, () => {
const { address, port } = listener.address();
$.info(`[FRONTEND] ${address}:${port}`);
const { address: fe_address, port: fe_port } =
listener.address();
$.info(`[FRONTEND] ${fe_address}:${fe_port}`);
if (fe_be_path) {
$.info(
`[FRONTEND -> BACKEND] ${fe_address}:${fe_port}${be_api_rewrite} -> http://127.0.0.1:${port}${be_api}`,
);
$.info(
`[FRONTEND -> BACKEND] ${fe_address}:${fe_port}${be_download_rewrite} -> http://127.0.0.1:${port}${be_download}`,
);
}
});
}
if (data_url) {
$.info(`[BACKEND] downloading data from ${data_url}`);
download(data_url)
.then((content) => {
$.write(content, '#sub-store');
$.cache = JSON.parse(content);
$.persistCache();
migrate();
$.info(`[BACKEND] restored data from ${data_url}`);
})
.catch((e) => {
$.error(`[BACKEND] restore data failed`);
console.error(e);
throw e;
});
}
}
}

View File

@@ -2,8 +2,6 @@
import { ENV } from './open-api';
export default function express({ substore: $, port, host }) {
port = port || 3000;
host = host || '::';
const { isNode } = ENV();
const DEFAULT_HEADERS = {
'Content-Type': 'text/plain;charset=UTF-8',