Compare commits

...

5 Commits

Author SHA1 Message Date
xream
4a2a2297f6 feat: Shadowsocks URI 支持 Shadow TLS plugin 2025-02-10 06:32:17 +08:00
xream
07d5a913f0 feat: 同步配置逻辑优化
Some checks are pending
build / build (push) Waiting to run
2025-02-09 20:58:27 +08:00
xream
421df8f0d4 doc: README 2025-02-07 19:43:06 +08:00
xream
e14944dd19 feat: 调整 Egern VMess security 逻辑
Some checks failed
build / build (push) Has been cancelled
2025-02-06 18:18:15 +08:00
xream
bf18c51f6a feat: mihomo 和 Shadowrocket VMess cipher 支持 zero 2025-02-06 18:08:46 +08:00
10 changed files with 98 additions and 35 deletions

View File

@@ -26,7 +26,7 @@ Core functionalities:
### Supported Input Formats
> ⚠️ Do not use `Shadowrocket` to export URI and then import it as input. It is not a standard URI.
> ⚠️ 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.
- [x] Proxy URI Scheme(`socks5`, `socks5+tls`, `http`, `https`(it's ok))

View File

@@ -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 %>
* @version: <%= pkg.version %>
* @author: Peng-YM

View File

@@ -1,7 +1,7 @@
{
"name": "sub-store",
"version": "2.16.28",
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.",
"version": "2.16.32",
"description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and Shadowrocket.",
"main": "src/main.js",
"scripts": {
"preinstall": "npx only-allow pnpm",

View File

@@ -146,11 +146,10 @@ function URI_SS() {
// }
// handle obfs
const idx = content.indexOf('?plugin=');
if (idx !== -1) {
const pluginMatch = content.match(/[?&]plugin=([^&]+)/);
if (pluginMatch) {
const pluginInfo = (
'plugin=' +
decodeURIComponent(content.split('?plugin=')[1].split('&')[0])
'plugin=' + decodeURIComponent(pluginMatch[1])
).split(';');
const params = {};
for (const item of pluginInfo) {
@@ -175,6 +174,16 @@ function URI_SS() {
tls: getIfPresent(params.tls),
};
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:
throw new Error(
`Unsupported plugin option: ${params.plugin}`,

View File

@@ -32,9 +32,10 @@ export default function ClashMeta_Producer() {
isPresent(proxy, 'cipher') &&
![
'auto',
'none',
'zero',
'aes-128-gcm',
'chacha20-poly1305',
'none',
].includes(proxy.cipher)
) {
proxy.cipher = 'auto';

View File

@@ -52,15 +52,8 @@ export default function Egern_Producer() {
'2022-blake3-aes-256-gcm',
].includes(proxy.cipher))) ||
(proxy.type === 'vmess' &&
(![
'auto',
'aes-128-gcm',
'chacha20-poly1305',
'none',
'zero',
].includes(proxy.cipher) ||
(!['http', 'ws', 'tcp'].includes(proxy.network) &&
proxy.network))) ||
!['http', 'ws', 'tcp'].includes(proxy.network) &&
proxy.network) ||
(proxy.type === 'trojan' &&
!['http', 'ws', 'tcp'].includes(proxy.network) &&
proxy.network) ||
@@ -191,6 +184,19 @@ export default function Egern_Producer() {
websocket: proxy.websocket,
};
} else if (proxy.type === 'vmess') {
let security = proxy.cipher;
if (
security &&
![
'auto',
'none',
'zero',
'aes-128-gcm',
'chacha20-poly1305',
].includes(security)
) {
security = 'auto';
}
if (proxy.network === 'ws') {
proxy.transport = {
[proxy.tls ? 'wss' : 'ws']: {
@@ -235,7 +241,7 @@ export default function Egern_Producer() {
server: proxy.server,
port: proxy.port,
user_id: proxy.uuid,
security: proxy.cipher,
security,
tfo: proxy.tfo || proxy['fast-open'],
legacy: proxy.legacy,
udp_relay:

View File

@@ -1,6 +1,6 @@
import { isPresent } from '@/core/proxy-utils/producers/utils';
export default function ShadowRocket_Producer() {
export default function Shadowrocket_Producer() {
const type = 'ALL';
const produce = (proxies, type, opts = {}) => {
const list = proxies
@@ -32,9 +32,10 @@ export default function ShadowRocket_Producer() {
isPresent(proxy, 'cipher') &&
![
'auto',
'none',
'zero',
'aes-128-gcm',
'chacha20-poly1305',
'none',
].includes(proxy.cipher)
) {
proxy.cipher = 'auto';

View File

@@ -54,6 +54,11 @@ export default function URI_Producer() {
}${opts.tls ? ';tls' : ''}`,
);
break;
case 'shadow-tls':
result += encodeURIComponent(
`shadow-tls;host=${opts.host};password=${opts.password};version=${opts.version}`,
);
break;
default:
throw new Error(
`Unsupported plugin option: ${proxy.plugin}`,

View File

@@ -84,6 +84,7 @@ async function doSync() {
const files = {};
try {
const valid = [];
const invalid = [];
const allSubs = $.read(SUBS_KEY);
const allCols = $.read(COLLECTIONS_KEY);
@@ -156,19 +157,26 @@ async function doSync() {
files[encodeURIComponent(artifact.name)] = {
content: output,
};
valid.push(artifact.name);
}
} catch (e) {
$.error(
`同步配置 ${artifact.name} 发生错误: ${e.message ?? e}`,
`生成同步配置 ${artifact.name} 发生错误: ${
e.message ?? e
}`,
);
invalid.push(artifact.name);
}
}),
);
if (invalid.length > 0) {
$.info(`${valid.length} 个同步配置生成成功: ${valid.join(', ')}`);
$.info(`${invalid.length} 个同步配置生成失败: ${invalid.join(', ')}`);
if (valid.length === 0) {
throw new Error(
`同步配置 ${invalid.join(', ')} 发生错误 详情请查看日志`,
`同步配置 ${invalid.join(', ')} 生成失败 详情请查看日志`,
);
}
@@ -184,7 +192,11 @@ async function doSync() {
$.info(JSON.stringify(body, null, 2));
for (const artifact of allArtifacts) {
if (artifact.sync) {
if (
artifact.sync &&
artifact.source &&
valid.includes(artifact.name)
) {
artifact.updated = new Date().getTime();
// extract real url from gist
let files = body.files;
@@ -212,9 +224,18 @@ async function doSync() {
}
$.write(allArtifacts, ARTIFACTS_KEY);
$.notify('🌍 Sub-Store', '全部订阅同步成功');
$.info('上传配置成功');
if (invalid.length > 0) {
$.notify(
'🌍 Sub-Store',
`同步配置成功 ${valid.length} 个, 失败 ${invalid.length} 个, 详情请查看日志`,
);
} else {
$.notify('🌍 Sub-Store', '同步配置完成');
}
} catch (e) {
$.notify('🌍 Sub-Store', '同步订阅失败', `原因:${e.message ?? e}`);
$.error(`无法同步订阅配置到 Gist原因${e}`);
$.notify('🌍 Sub-Store', '同步配置失败', `原因:${e.message ?? e}`);
$.error(`无法同步配置到 Gist原因${e}`);
}
}

View File

@@ -540,6 +540,7 @@ async function syncArtifacts() {
const files = {};
try {
const valid = [];
const invalid = [];
const allSubs = $.read(SUBS_KEY);
const allCols = $.read(COLLECTIONS_KEY);
@@ -614,19 +615,26 @@ async function syncArtifacts() {
files[encodeURIComponent(artifact.name)] = {
content: output,
};
valid.push(artifact.name);
}
} catch (e) {
$.error(
`同步配置 ${artifact.name} 发生错误: ${e.message ?? e}`,
`生成同步配置 ${artifact.name} 发生错误: ${
e.message ?? e
}`,
);
invalid.push(artifact.name);
}
}),
);
if (invalid.length > 0) {
$.info(`${valid.length} 个同步配置生成成功: ${valid.join(', ')}`);
$.info(`${invalid.length} 个同步配置生成失败: ${invalid.join(', ')}`);
if (valid.length === 0) {
throw new Error(
`同步配置 ${invalid.join(', ')} 发生错误 详情请查看日志`,
`同步配置 ${invalid.join(', ')} 生成失败 详情请查看日志`,
);
}
@@ -643,7 +651,11 @@ async function syncArtifacts() {
$.info(JSON.stringify(body, null, 2));
for (const artifact of allArtifacts) {
if (artifact.sync) {
if (
artifact.sync &&
artifact.source &&
valid.includes(artifact.name)
) {
artifact.updated = new Date().getTime();
// extract real url from gist
let files = body.files;
@@ -671,9 +683,17 @@ async function syncArtifacts() {
}
$.write(allArtifacts, ARTIFACTS_KEY);
$.info('全部订阅同步成功');
$.info('上传配置成功');
if (invalid.length > 0) {
throw new Error(
`同步配置成功 ${valid.length} 个, 失败 ${invalid.length} 个, 详情请查看日志`,
);
} else {
$.info(`同步配置成功 ${valid.length}`);
}
} catch (e) {
$.error(`同步订阅失败,原因:${e.message ?? e}`);
$.error(`同步配置失败,原因:${e.message ?? e}`);
throw e;
}
}
@@ -683,7 +703,7 @@ async function syncAllArtifacts(_, res) {
await syncArtifacts();
success(res);
} catch (e) {
$.error(`同步订阅失败,原因:${e.message ?? e}`);
$.error(`同步配置失败,原因:${e.message ?? e}`);
failed(
res,
new InternalServerError(