feat: 支持 QX VLESS 输出(不支持 XTLS/REALITY)

This commit is contained in:
xream 2024-01-17 21:16:34 +08:00
parent 4966132397
commit 614438ae3d
No known key found for this signature in database
GPG Key ID: 1D2C5225471789F9
3 changed files with 125 additions and 6 deletions

View File

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

@ -106,7 +106,19 @@ function trojan(proxy) {
`,host=${proxy['ws-opts']?.headers?.Host}`, `,host=${proxy['ws-opts']?.headers?.Host}`,
'ws-opts.headers.Host', 'ws-opts.headers.Host',
); );
} else { } else if (proxy.network === 'http') {
result.append(`,transport=http`);
let httpPath = proxy['http-opts']?.path;
let httpHost = proxy['http-opts']?.headers?.Host;
result.appendIfPresent(
`,path=${Array.isArray(httpPath) ? httpPath[0] : httpPath}`,
'http-opts.path',
);
result.appendIfPresent(
`,host=${Array.isArray(httpHost) ? httpHost[0] : httpHost}`,
'http-opts.headers.Host',
);
} else if (!['tcp'].includes(proxy.network)) {
throw new Error(`network ${proxy.network} is unsupported`); throw new Error(`network ${proxy.network} is unsupported`);
} }
} }
@ -159,7 +171,7 @@ function vmess(proxy) {
`,host=${Array.isArray(httpHost) ? httpHost[0] : httpHost}`, `,host=${Array.isArray(httpHost) ? httpHost[0] : httpHost}`,
'http-opts.headers.Host', 'http-opts.headers.Host',
); );
} else { } else if (!['tcp'].includes(proxy.network)) {
throw new Error(`network ${proxy.network} is unsupported`); throw new Error(`network ${proxy.network} is unsupported`);
} }
} else { } else {
@ -195,7 +207,7 @@ function vmess(proxy) {
function vless(proxy) { function vless(proxy) {
if (proxy['reality-opts']) { if (proxy['reality-opts']) {
throw new Error(`reality is unsupported`); throw new Error(`VLESS REALITY is unsupported`);
} }
const result = new Result(proxy); const result = new Result(proxy);
result.append( result.append(
@ -226,7 +238,7 @@ function vless(proxy) {
`,host=${Array.isArray(httpHost) ? httpHost[0] : httpHost}`, `,host=${Array.isArray(httpHost) ? httpHost[0] : httpHost}`,
'http-opts.headers.Host', 'http-opts.headers.Host',
); );
} else { } else if (!['tcp'].includes(proxy.network)) {
throw new Error(`network ${proxy.network} is unsupported`); throw new Error(`network ${proxy.network} is unsupported`);
} }
} else { } else {

View File

@ -3,7 +3,7 @@ import { isPresent, Result } from './utils';
const targetPlatform = 'QX'; const targetPlatform = 'QX';
export default function QX_Producer() { export default function QX_Producer() {
const produce = (proxy) => { const produce = (proxy, type, opts = {}) => {
switch (proxy.type) { switch (proxy.type) {
case 'ss': case 'ss':
return shadowsocks(proxy); return shadowsocks(proxy);
@ -17,6 +17,14 @@ export default function QX_Producer() {
return http(proxy); return http(proxy);
case 'socks5': case 'socks5':
return socks5(proxy); return socks5(proxy);
case 'vless':
if (opts['include-unsupported-proxy']) {
return vless(proxy);
} else {
throw new Error(
`Platform ${targetPlatform}(App Store Release) does not support proxy type: ${proxy.type}`,
);
}
} }
throw new Error( throw new Error(
`Platform ${targetPlatform} does not support proxy type: ${proxy.type}`, `Platform ${targetPlatform} does not support proxy type: ${proxy.type}`,
@ -325,6 +333,105 @@ function vmess(proxy) {
return result.toString(); return result.toString();
} }
function vless(proxy) {
if (typeof proxy.flow !== 'undefined' || proxy['reality-opts']) {
throw new Error(`VLESS XTLS/REALITY is not supported`);
}
const result = new Result(proxy);
const append = result.append.bind(result);
const appendIfPresent = result.appendIfPresent.bind(result);
append(`vless=${proxy.server}:${proxy.port}`);
// The method field for vless should be none.
let cipher = 'none';
// if (proxy.cipher === 'auto') {
// cipher = 'chacha20-ietf-poly1305';
// } else {
// cipher = proxy.cipher;
// }
append(`,method=${cipher}`);
append(`,password=${proxy.uuid}`);
// obfs
if (needTls(proxy)) {
proxy.tls = true;
}
if (isPresent(proxy, 'network')) {
if (proxy.network === 'ws') {
if (proxy.tls) append(`,obfs=wss`);
else append(`,obfs=ws`);
} else if (proxy.network === 'http') {
append(`,obfs=http`);
} else if (!['tcp'].includes(proxy.network)) {
throw new Error(`network ${proxy.network} is unsupported`);
}
let transportPath = proxy[`${proxy.network}-opts`]?.path;
let transportHost = proxy[`${proxy.network}-opts`]?.headers?.Host;
appendIfPresent(
`,obfs-uri=${
Array.isArray(transportPath) ? transportPath[0] : transportPath
}`,
`${proxy.network}-opts.path`,
);
appendIfPresent(
`,obfs-host=${
Array.isArray(transportHost) ? transportHost[0] : transportHost
}`,
`${proxy.network}-opts.headers.Host`,
);
} else {
// over-tls
if (proxy.tls) append(`,obfs=over-tls`);
}
if (needTls(proxy)) {
appendIfPresent(
`,tls-pubkey-sha256=${proxy['tls-pubkey-sha256']}`,
'tls-pubkey-sha256',
);
appendIfPresent(`,tls-alpn=${proxy['tls-alpn']}`, 'tls-alpn');
appendIfPresent(
`,tls-no-session-ticket=${proxy['tls-no-session-ticket']}`,
'tls-no-session-ticket',
);
appendIfPresent(
`,tls-no-session-reuse=${proxy['tls-no-session-reuse']}`,
'tls-no-session-reuse',
);
// tls fingerprint
appendIfPresent(
`,tls-cert-sha256=${proxy['tls-fingerprint']}`,
'tls-fingerprint',
);
// tls verification
appendIfPresent(
`,tls-verification=${!proxy['skip-cert-verify']}`,
'skip-cert-verify',
);
appendIfPresent(`,tls-host=${proxy.sni}`, 'sni');
}
// tfo
appendIfPresent(`,fast-open=${proxy.tfo}`, 'tfo');
// udp
appendIfPresent(`,udp-relay=${proxy.udp}`, 'udp');
// server_check_url
result.appendIfPresent(
`,server_check_url=${proxy['test-url']}`,
'test-url',
);
// tag
append(`,tag=${proxy.name}`);
return result.toString();
}
function http(proxy) { function http(proxy) {
const result = new Result(proxy); const result = new Result(proxy);