mirror of
https://github.com/sub-store-org/Sub-Store.git
synced 2025-08-10 00:52:40 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69726cd5c4 | ||
|
|
8918479b9e | ||
|
|
17504ab5aa | ||
|
|
0d8fa91cd5 | ||
|
|
e7dfa1ce38 | ||
|
|
fe937d6ebf | ||
|
|
b7b734f529 | ||
|
|
f5ef6010bc | ||
|
|
0e82a7669d | ||
|
|
6d11ea0fcc | ||
|
|
75f802f607 | ||
|
|
000e90d114 | ||
|
|
c2499f6779 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "sub-store",
|
||||
"version": "2.14.108",
|
||||
"version": "2.14.115",
|
||||
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.",
|
||||
"main": "src/main.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -139,7 +139,7 @@ async function process(proxies, operators = [], targetPlatform, source) {
|
||||
return proxies;
|
||||
}
|
||||
|
||||
function produce(proxies, targetPlatform) {
|
||||
function produce(proxies, targetPlatform, type) {
|
||||
const producer = PROXY_PRODUCERS[targetPlatform];
|
||||
if (!producer) {
|
||||
throw new Error(`Target platform: ${targetPlatform} is not supported!`);
|
||||
@@ -157,7 +157,7 @@ function produce(proxies, targetPlatform) {
|
||||
return proxies
|
||||
.map((proxy) => {
|
||||
try {
|
||||
let line = producer.produce(proxy);
|
||||
let line = producer.produce(proxy, type);
|
||||
if (
|
||||
line.length > 0 &&
|
||||
line.includes('__SubStoreLocalPort__')
|
||||
@@ -182,7 +182,7 @@ function produce(proxies, targetPlatform) {
|
||||
.filter((line) => line.length > 0)
|
||||
.join('\n');
|
||||
} else if (producer.type === 'ALL') {
|
||||
return producer.produce(proxies);
|
||||
return producer.produce(proxies, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,6 +214,12 @@ function safeMatch(parser, line) {
|
||||
}
|
||||
|
||||
function lastParse(proxy) {
|
||||
if (proxy.server) {
|
||||
proxy.server = proxy.server
|
||||
.trim()
|
||||
.replace(/^\[/, '')
|
||||
.replace(/\]$/, '');
|
||||
}
|
||||
if (proxy.type === 'trojan') {
|
||||
if (proxy.network === 'tcp') {
|
||||
delete proxy.network;
|
||||
|
||||
@@ -25,7 +25,10 @@ function Base64Encoded() {
|
||||
];
|
||||
|
||||
const test = function (raw) {
|
||||
return keys.some((k) => raw.indexOf(k) !== -1);
|
||||
return (
|
||||
!/^\w+:\/\/\w+/im.test(raw) &&
|
||||
keys.some((k) => raw.indexOf(k) !== -1)
|
||||
);
|
||||
};
|
||||
const parse = function (raw) {
|
||||
raw = Base64.decode(raw);
|
||||
@@ -37,7 +40,9 @@ function Base64Encoded() {
|
||||
function Clash() {
|
||||
const name = 'Clash Pre-processor';
|
||||
const test = function (raw) {
|
||||
return /proxies/.test(raw);
|
||||
if (!/proxies/.test(raw)) return false;
|
||||
const content = safeLoad(raw);
|
||||
return content.proxies && Array.isArray(content.proxies);
|
||||
};
|
||||
const parse = function (raw) {
|
||||
// Clash YAML format
|
||||
@@ -105,4 +110,4 @@ function FullConfig() {
|
||||
return { name, test, parse };
|
||||
}
|
||||
|
||||
export default [HTML(), Base64Encoded(), Clash(), SSD(), FullConfig()];
|
||||
export default [HTML(), Clash(), Base64Encoded(), SSD(), FullConfig()];
|
||||
|
||||
@@ -2,143 +2,143 @@ import { isPresent } from '@/core/proxy-utils/producers/utils';
|
||||
|
||||
export default function ClashMeta_Producer() {
|
||||
const type = 'ALL';
|
||||
const produce = (proxies) => {
|
||||
return (
|
||||
'proxies:\n' +
|
||||
proxies
|
||||
.filter((proxy) => {
|
||||
const produce = (proxies, type) => {
|
||||
const list = proxies
|
||||
.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 (
|
||||
proxy.type === 'snell' &&
|
||||
String(proxy.version) === '4'
|
||||
isPresent(proxy, 'cipher') &&
|
||||
![
|
||||
'auto',
|
||||
'aes-128-gcm',
|
||||
'chacha20-poly1305',
|
||||
'none',
|
||||
].includes(proxy.cipher)
|
||||
) {
|
||||
return false;
|
||||
proxy.cipher = 'auto';
|
||||
}
|
||||
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 (
|
||||
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 === '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;
|
||||
}
|
||||
} 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 === '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 (
|
||||
['vmess', 'vless'].includes(proxy.type) &&
|
||||
proxy.network === 'http'
|
||||
isPresent(proxy, 'http-opts.path') &&
|
||||
!Array.isArray(httpPath)
|
||||
) {
|
||||
let httpPath = proxy['http-opts']?.path;
|
||||
if (
|
||||
isPresent(proxy, 'http-opts.path') &&
|
||||
!Array.isArray(httpPath)
|
||||
) {
|
||||
proxy['http-opts'].path = [httpPath];
|
||||
}
|
||||
let httpHost = proxy['http-opts']?.headers?.Host;
|
||||
if (
|
||||
isPresent(proxy, 'http-opts.headers.Host') &&
|
||||
!Array.isArray(httpHost)
|
||||
) {
|
||||
proxy['http-opts'].headers.Host = [httpHost];
|
||||
}
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
['trojan', 'tuic', 'hysteria', 'hysteria2'].includes(
|
||||
proxy.type,
|
||||
)
|
||||
) {
|
||||
delete proxy.tls;
|
||||
}
|
||||
if (
|
||||
['trojan', 'tuic', 'hysteria', 'hysteria2'].includes(
|
||||
proxy.type,
|
||||
)
|
||||
) {
|
||||
delete proxy.tls;
|
||||
}
|
||||
|
||||
if (proxy['tls-fingerprint']) {
|
||||
proxy.fingerprint = proxy['tls-fingerprint'];
|
||||
}
|
||||
delete proxy['tls-fingerprint'];
|
||||
delete proxy.subName;
|
||||
delete proxy.collectionName;
|
||||
if (
|
||||
['grpc'].includes(proxy.network) &&
|
||||
proxy[`${proxy.network}-opts`]
|
||||
) {
|
||||
delete proxy[`${proxy.network}-opts`]['_grpc-type'];
|
||||
}
|
||||
return ' - ' + JSON.stringify(proxy) + '\n';
|
||||
})
|
||||
.join('')
|
||||
);
|
||||
if (proxy['tls-fingerprint']) {
|
||||
proxy.fingerprint = proxy['tls-fingerprint'];
|
||||
}
|
||||
delete proxy['tls-fingerprint'];
|
||||
delete proxy.subName;
|
||||
delete proxy.collectionName;
|
||||
if (
|
||||
['grpc'].includes(proxy.network) &&
|
||||
proxy[`${proxy.network}-opts`]
|
||||
) {
|
||||
delete proxy[`${proxy.network}-opts`]['_grpc-type'];
|
||||
}
|
||||
return proxy;
|
||||
});
|
||||
|
||||
return type === 'internal'
|
||||
? list
|
||||
: 'proxies:\n' +
|
||||
list
|
||||
.map((proxy) => ' - ' + JSON.stringify(proxy) + '\n')
|
||||
.join('');
|
||||
};
|
||||
return { type, produce };
|
||||
}
|
||||
|
||||
@@ -81,6 +81,24 @@ export default function ShadowRocket_Producer() {
|
||||
) {
|
||||
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'];
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
/* eslint-disable no-case-declarations */
|
||||
import { Base64 } from 'js-base64';
|
||||
import { isIPv6 } from '@/utils';
|
||||
|
||||
export default function URI_Producer() {
|
||||
const type = 'SINGLE';
|
||||
const produce = (proxy) => {
|
||||
let result = '';
|
||||
if (proxy.server && isIPv6(proxy.server)) {
|
||||
proxy.server = `[${proxy.server}]`;
|
||||
}
|
||||
switch (proxy.type) {
|
||||
case 'ss':
|
||||
const userinfo = `${proxy.cipher}:${proxy.password}`;
|
||||
@@ -222,6 +226,44 @@ export default function URI_Producer() {
|
||||
proxy['skip-cert-verify'] ? '&allowInsecure=1' : ''
|
||||
}${trojanTransport}#${encodeURIComponent(proxy.name)}`;
|
||||
break;
|
||||
case 'hysteria2':
|
||||
let hysteria2params = [];
|
||||
if (proxy['skip-cert-verify']) {
|
||||
hysteria2params.push(`insecure=1`);
|
||||
}
|
||||
if (proxy.obfs) {
|
||||
hysteria2params.push(
|
||||
`obfs=${encodeURIComponent(proxy.obfs)}`,
|
||||
);
|
||||
if (proxy['obfs-password']) {
|
||||
hysteria2params.push(
|
||||
`obfs-password=${encodeURIComponent(
|
||||
proxy['obfs-password'],
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
if (proxy.sni) {
|
||||
hysteria2params.push(
|
||||
`sni=${encodeURIComponent(proxy.sni)}`,
|
||||
);
|
||||
}
|
||||
if (proxy['tls-fingerprint']) {
|
||||
hysteria2params.push(
|
||||
`pinSHA256=${encodeURIComponent(
|
||||
proxy['tls-fingerprint'],
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
if (proxy.tfo) {
|
||||
hysteria2params.push(`fastopen=1`);
|
||||
}
|
||||
result = `hysteria2://${proxy.password}@${proxy.server}:${
|
||||
proxy.port
|
||||
}?${hysteria2params.join('&')}#${encodeURIComponent(
|
||||
proxy.name,
|
||||
)}`;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
@@ -22,12 +22,26 @@ export default function register($app) {
|
||||
// Storage management
|
||||
$app.route('/api/storage')
|
||||
.get((req, res) => {
|
||||
res.json($.read('#sub-store'));
|
||||
res.set('content-type', 'application/json')
|
||||
.set(
|
||||
'content-disposition',
|
||||
'attachment; filename="sub-store.json"',
|
||||
)
|
||||
.send(
|
||||
$.env.isNode
|
||||
? JSON.stringify($.cache)
|
||||
: $.read('#sub-store'),
|
||||
);
|
||||
})
|
||||
.post((req, res) => {
|
||||
const data = req.body;
|
||||
$.write(JSON.stringify(data), '#sub-store');
|
||||
res.end();
|
||||
const { content } = req.body;
|
||||
$.write(content, '#sub-store');
|
||||
if ($.env.isNode) {
|
||||
$.cache = JSON.parse(content);
|
||||
$.persistCache();
|
||||
}
|
||||
migrate();
|
||||
success(res);
|
||||
});
|
||||
|
||||
// Redirect sub.store to vercel webpage
|
||||
|
||||
@@ -10,7 +10,12 @@ export default function register($app) {
|
||||
}
|
||||
|
||||
async function getSettings(req, res) {
|
||||
const settings = $.read(SETTINGS_KEY);
|
||||
let settings = $.read(SETTINGS_KEY);
|
||||
if (!settings) {
|
||||
settings = {};
|
||||
$.write(settings, SETTINGS_KEY);
|
||||
}
|
||||
|
||||
if (!settings.avatarUrl) await updateGitHubAvatar();
|
||||
if (!settings.artifactStore) await updateArtifactStore();
|
||||
success(res, settings);
|
||||
|
||||
Reference in New Issue
Block a user