Compare commits

...

4 Commits

Author SHA1 Message Date
xream
532be2ff8c Stash 正式版支持 VLESS REALITY(xtls-rprx-vision)
Some checks failed
build / build (push) Has been cancelled
2025-05-27 19:46:31 +08:00
xream
37fc7ac88e feat: VMess 支持 kcp/quic(正确处理 type, host, path, fp, alpn, tls等参数)
Some checks failed
build / build (push) Has been cancelled
2025-05-27 03:01:28 +08:00
xream
9e0028219d feat: Shadowrocket 支持 anytls
Some checks failed
build / build (push) Has been cancelled
2025-05-26 17:24:39 +08:00
xream
54750d552b feat: 为 env 响应增加如何使用前端搭配后端的引导说明
Some checks failed
build / build (push) Has been cancelled
2025-05-25 00:58:06 +08:00
7 changed files with 122 additions and 61 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "sub-store", "name": "sub-store",
"version": "2.19.49", "version": "2.19.55",
"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": {

View File

@@ -439,7 +439,16 @@ function URI_VMess() {
type: 'vmess', type: 'vmess',
server, server,
port, port,
cipher: getIfPresent(params.scy, 'auto'), // https://github.com/2dust/v2rayN/wiki/Description-of-VMess-share-link
// https://github.com/XTLS/Xray-core/issues/91
cipher: [
'auto',
'aes-128-gcm',
'chacha20-poly1305',
'none',
].includes(params.scy)
? params.scy
: 'auto',
uuid: params.id, uuid: params.id,
alterId: parseInt( alterId: parseInt(
getIfPresent(params.aid ?? params.alterId, 0), getIfPresent(params.aid ?? params.alterId, 0),
@@ -473,8 +482,8 @@ function URI_VMess() {
['http'].includes(params.type) ['http'].includes(params.type)
) { ) {
proxy.network = 'http'; proxy.network = 'http';
} else if (['grpc'].includes(params.net)) { } else if (['grpc', 'kcp', 'quic'].includes(params.net)) {
proxy.network = 'grpc'; proxy.network = params.net;
} else if ( } else if (
params.net === 'httpupgrade' || params.net === 'httpupgrade' ||
proxy.network === 'httpupgrade' proxy.network === 'httpupgrade'
@@ -524,13 +533,28 @@ function URI_VMess() {
} }
} }
// 传输层应该有配置, 暂时不考虑兼容不给配置的节点 // 传输层应该有配置, 暂时不考虑兼容不给配置的节点
if (transportPath || transportHost) { if (
transportPath ||
transportHost ||
['kcp', 'quic'].includes(proxy.network)
) {
if (['grpc'].includes(proxy.network)) { if (['grpc'].includes(proxy.network)) {
proxy[`${proxy.network}-opts`] = { proxy[`${proxy.network}-opts`] = {
'grpc-service-name': getIfNotBlank(transportPath), 'grpc-service-name': getIfNotBlank(transportPath),
'_grpc-type': getIfNotBlank(params.type), '_grpc-type': getIfNotBlank(params.type),
'_grpc-authority': getIfNotBlank(params.authority), '_grpc-authority': getIfNotBlank(params.authority),
}; };
} else if (['kcp', 'quic'].includes(proxy.network)) {
proxy[`${proxy.network}-opts`] = {
[`_${proxy.network}-type`]: getIfNotBlank(
params.type,
),
[`_${proxy.network}-host`]: getIfNotBlank(
getIfNotBlank(transportHost),
),
[`_${proxy.network}-path`]:
getIfNotBlank(transportPath),
};
} else { } else {
const opts = { const opts = {
path: getIfNotBlank(transportPath), path: getIfNotBlank(transportPath),
@@ -546,6 +570,12 @@ function URI_VMess() {
delete proxy.network; delete proxy.network;
} }
} }
proxy['client-fingerprint'] = params.fp;
proxy.alpn = params.alpn ? params.alpn.split(',') : undefined;
// 然而 wiki 和 app 实测中都没有字段表示这个
// proxy['skip-cert-verify'] = /(TRUE)|1/i.test(params.allowInsecure);
return proxy; return proxy;
} }
}; };

View File

@@ -9,7 +9,7 @@ export default function Shadowrocket_Producer() {
if (opts['include-unsupported-proxy']) return true; if (opts['include-unsupported-proxy']) return true;
if (proxy.type === 'snell' && String(proxy.version) === '4') { if (proxy.type === 'snell' && String(proxy.version) === '4') {
return false; return false;
} else if (['mieru', 'anytls'].includes(proxy.type)) { } else if (['mieru'].includes(proxy.type)) {
return false; return false;
} }
return true; return true;

View File

@@ -44,11 +44,9 @@ export default function Stash_Producer() {
'2022-blake3-aes-256-gcm', '2022-blake3-aes-256-gcm',
].includes(proxy.cipher)) || ].includes(proxy.cipher)) ||
(proxy.type === 'snell' && String(proxy.version) === '4') || (proxy.type === 'snell' && String(proxy.version) === '4') ||
(opts['include-unsupported-proxy'] (proxy.type === 'vless' &&
? proxy.type === 'vless' && proxy['reality-opts'] &&
proxy['reality-opts'] && !['xtls-rprx-vision'].includes(proxy.flow))
!['xtls-rprx-vision'].includes(proxy.flow)
: proxy.type === 'vless' && proxy['reality-opts'])
) { ) {
return false; return false;
} else if (proxy['underlying-proxy'] || proxy['dialer-proxy']) { } else if (proxy['underlying-proxy'] || proxy['dialer-proxy']) {

View File

@@ -119,12 +119,17 @@ export default function URI_Producer() {
v: '2', v: '2',
ps: proxy.name, ps: proxy.name,
add: proxy.server, add: proxy.server,
port: proxy.port, port: `${proxy.port}`,
id: proxy.uuid, id: proxy.uuid,
type, aid: `${proxy.alterId || 0}`,
aid: proxy.alterId || 0, scy: proxy.cipher,
net, net,
type,
tls: proxy.tls ? 'tls' : '', tls: proxy.tls ? 'tls' : '',
alpn: Array.isArray(proxy.alpn)
? proxy.alpn.join(',')
: proxy.alpn,
fp: proxy['client-fingerprint'],
}; };
if (proxy.tls && proxy.sni) { if (proxy.tls && proxy.sni) {
result.sni = proxy.sni; result.sni = proxy.sni;
@@ -135,16 +140,7 @@ export default function URI_Producer() {
proxy[`${proxy.network}-opts`]?.path; proxy[`${proxy.network}-opts`]?.path;
let vmessTransportHost = let vmessTransportHost =
proxy[`${proxy.network}-opts`]?.headers?.Host; proxy[`${proxy.network}-opts`]?.headers?.Host;
if (vmessTransportPath) {
result.path = Array.isArray(vmessTransportPath)
? vmessTransportPath[0]
: vmessTransportPath;
}
if (vmessTransportHost) {
result.host = Array.isArray(vmessTransportHost)
? vmessTransportHost[0]
: vmessTransportHost;
}
if (['grpc'].includes(proxy.network)) { if (['grpc'].includes(proxy.network)) {
result.path = result.path =
proxy[`${proxy.network}-opts`]?.[ proxy[`${proxy.network}-opts`]?.[
@@ -156,6 +152,31 @@ export default function URI_Producer() {
'gun'; 'gun';
result.host = result.host =
proxy[`${proxy.network}-opts`]?.['_grpc-authority']; proxy[`${proxy.network}-opts`]?.['_grpc-authority'];
} else if (['kcp', 'quic'].includes(proxy.network)) {
// https://github.com/XTLS/Xray-core/issues/91
result.type =
proxy[`${proxy.network}-opts`]?.[
`_${proxy.network}-type`
] || 'none';
result.host =
proxy[`${proxy.network}-opts`]?.[
`_${proxy.network}-host`
];
result.path =
proxy[`${proxy.network}-opts`]?.[
`_${proxy.network}-path`
];
} else {
if (vmessTransportPath) {
result.path = Array.isArray(vmessTransportPath)
? vmessTransportPath[0]
: vmessTransportPath;
}
if (vmessTransportHost) {
result.host = Array.isArray(vmessTransportHost)
? vmessTransportHost[0]
: vmessTransportHost;
}
} }
} }
result = 'vmess://' + Base64.encode(JSON.stringify(result)); result = 'vmess://' + Base64.encode(JSON.stringify(result));

View File

@@ -77,7 +77,19 @@ function getEnv(req, res) {
if (req.query.share) { if (req.query.share) {
env.feature.share = true; env.feature.share = true;
} }
success(res, env); res.set('Content-Type', 'application/json;charset=UTF-8').send(
JSON.stringify(
{
status: 'success',
data: {
guide: '⚠️⚠️⚠️ 您当前看到的是后端的响应. 若想配合前端使用, 可访问官方前端 https://sub-store.vercel.app 后自行配置后端地址, 或一键配置后端 https://sub-store.vercel.app?api=https://a.com/xxx (假设 https://a.com 是你后端的域名, /xxx 是自定义路径). 需注意 HTTPS 前端无法请求非本地的 HTTP 后端(部分浏览器上也无法访问本地 HTTP 后端). 请配置反代或在局域网自建 HTTP 前端. 如果还有问题, 可查看此排查说明: https://t.me/zhetengsha/1068',
...env,
},
},
null,
2,
),
);
} }
async function refresh(_, res) { async function refresh(_, res) {

View File

@@ -61,41 +61,41 @@ export function getPlatformFromHeaders(headers) {
return getPlatformFromUserAgent({ ua, UA, accept }); return getPlatformFromUserAgent({ ua, UA, accept });
} }
export function shouldIncludeUnsupportedProxy(platform, ua) { export function shouldIncludeUnsupportedProxy(platform, ua) {
try { // try {
const target = getPlatformFromUserAgent({ // const target = getPlatformFromUserAgent({
UA: ua, // UA: ua,
ua: ua.toLowerCase(), // ua: ua.toLowerCase(),
}); // });
if (!['Stash', 'Egern', 'Loon'].includes(target)) { // if (!['Stash', 'Egern', 'Loon'].includes(target)) {
return false; // return false;
} // }
const coerceVersion = coerce(ua); // const coerceVersion = coerce(ua);
$.log(JSON.stringify(coerceVersion, null, 2)); // $.log(JSON.stringify(coerceVersion, null, 2));
const { version } = coerceVersion; // const { version } = coerceVersion;
if ( // if (
platform === 'Stash' && // platform === 'Stash' &&
target === 'Stash' && // target === 'Stash' &&
gte(version, '3.1.0') // gte(version, '3.1.0')
) { // ) {
return true; // return true;
} // }
if ( // if (
platform === 'Egern' && // platform === 'Egern' &&
target === 'Egern' && // target === 'Egern' &&
gte(version, '1.29.0') // gte(version, '1.29.0')
) { // ) {
return true; // return true;
} // }
// Loon 的 UA 不规范, version 取出来是 build // // Loon 的 UA 不规范, version 取出来是 build
if ( // if (
platform === 'Loon' && // platform === 'Loon' &&
target === 'Loon' && // target === 'Loon' &&
gte(version, '842.0.0') // gte(version, '842.0.0')
) { // ) {
return true; // return true;
} // }
} catch (e) { // } catch (e) {
$.error(`获取版本号失败: ${e}`); // $.error(`获取版本号失败: ${e}`);
} // }
return false; return false;
} }