diff --git a/backend/package.json b/backend/package.json index 54eeb59..ed9db7a 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "sub-store", - "version": "2.14.190", + "version": "2.14.191", "description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.", "main": "src/main.js", "scripts": { diff --git a/backend/src/core/proxy-utils/index.js b/backend/src/core/proxy-utils/index.js index 01de5e2..4deeded 100644 --- a/backend/src/core/proxy-utils/index.js +++ b/backend/src/core/proxy-utils/index.js @@ -237,6 +237,7 @@ function lastParse(proxy) { delete proxy['ws-path']; delete proxy['ws-headers']; } + if (proxy.type === 'trojan') { if (proxy.network === 'tcp') { delete proxy.network; @@ -253,11 +254,22 @@ function lastParse(proxy) { if (proxy.network) { let transportHost = proxy[`${proxy.network}-opts`]?.headers?.Host; let transporthost = proxy[`${proxy.network}-opts`]?.headers?.host; - if (transporthost && !transportHost) { + if (proxy.network === 'h2') { + if (!transporthost && transportHost) { + proxy[`${proxy.network}-opts`].headers.host = transportHost; + delete proxy[`${proxy.network}-opts`].headers.Host; + } + } else if (transporthost && !transportHost) { proxy[`${proxy.network}-opts`].headers.Host = transporthost; delete proxy[`${proxy.network}-opts`].headers.host; } } + if (proxy.network === 'h2') { + const host = proxy['h2-opts']?.headers?.host; + if (host && !Array.isArray(host)) { + proxy['h2-opts'].headers.host = [host]; + } + } if (proxy.tls && !proxy.sni) { if (proxy.network) { let transportHost = proxy[`${proxy.network}-opts`]?.headers?.Host; diff --git a/backend/src/core/proxy-utils/parsers/index.js b/backend/src/core/proxy-utils/parsers/index.js index 7d81baf..82acaf6 100644 --- a/backend/src/core/proxy-utils/parsers/index.js +++ b/backend/src/core/proxy-utils/parsers/index.js @@ -34,14 +34,24 @@ function URI_SS() { let userInfoStr = Base64.decode(content.split('@')[0]); let query = ''; if (!serverAndPortArray) { - // 暂时先这样处理 目前够用 - if (content.includes('?plugin=')) { - const parsed = content.match(/^(.*)(\?plugin=.*)$/); + if (content.includes('?')) { + const parsed = content.match(/^(.*)(\?.*)$/); content = parsed[1]; query = parsed[2]; } content = Base64.decode(content); if (query) { + console.log(query); + if (/(&|\?)v2ray-plugin=/.test(query)) { + const parsed = query.match(/(&|\?)v2ray-plugin=(.*?)(&|$)/); + let v2rayPlugin = parsed[2]; + if (v2rayPlugin) { + proxy.obfs = 'v2ray-plugin'; + proxy['plugin-opts'] = JSON.parse( + Base64.decode(v2rayPlugin), + ); + } + } content = `${content}${query}`; } userInfoStr = content.split('@')[0]; @@ -57,6 +67,7 @@ function URI_SS() { const userInfo = userInfoStr.split(':'); proxy.cipher = userInfo[0]; proxy.password = userInfo[1]; + // handle obfs const idx = content.indexOf('?plugin='); if (idx !== -1) { @@ -96,6 +107,9 @@ function URI_SS() { if (/(&|\?)uot=(1|true)/i.test(query)) { proxy['udp-over-tcp'] = true; } + if (/(&|\?)tfo=(1|true)/i.test(query)) { + proxy.tfo = true; + } return proxy; }; return { name, test, parse }; @@ -449,7 +463,7 @@ function URI_VLESS() { if (params.serviceName) { opts[`${proxy.network}-service-name`] = params.serviceName; } else if (isShadowrocket && params.path) { - if (!['ws', 'http'].includes(proxy.network)) { + if (!['ws', 'http', 'h2'].includes(proxy.network)) { opts[`${proxy.network}-service-name`] = params.path; delete params.path; } diff --git a/backend/src/core/proxy-utils/producers/clash.js b/backend/src/core/proxy-utils/producers/clash.js index 42e5c76..8ea9d94 100644 --- a/backend/src/core/proxy-utils/producers/clash.js +++ b/backend/src/core/proxy-utils/producers/clash.js @@ -107,6 +107,25 @@ export default function Clash_Producer() { proxy['http-opts'].headers.Host = [httpHost]; } } + if ( + ['vmess', 'vless'].includes(proxy.type) && + proxy.network === 'h2' + ) { + let path = proxy['h2-opts']?.path; + if ( + isPresent(proxy, 'h2-opts.path') && + Array.isArray(path) + ) { + proxy['h2-opts'].path = path[0]; + } + let host = proxy['h2-opts']?.headers?.host; + if ( + isPresent(proxy, 'h2-opts.headers.Host') && + !Array.isArray(host) + ) { + proxy['h2-opts'].headers.host = [host]; + } + } if ( ['trojan', 'tuic', 'hysteria', 'hysteria2'].includes( proxy.type, diff --git a/backend/src/core/proxy-utils/producers/clashmeta.js b/backend/src/core/proxy-utils/producers/clashmeta.js index d3d964a..59f6dcc 100644 --- a/backend/src/core/proxy-utils/producers/clashmeta.js +++ b/backend/src/core/proxy-utils/producers/clashmeta.js @@ -110,7 +110,25 @@ export default function ClashMeta_Producer() { proxy['http-opts'].headers.Host = [httpHost]; } } - + if ( + ['vmess', 'vless'].includes(proxy.type) && + proxy.network === 'h2' + ) { + let path = proxy['h2-opts']?.path; + if ( + isPresent(proxy, 'h2-opts.path') && + Array.isArray(path) + ) { + proxy['h2-opts'].path = path[0]; + } + let host = proxy['h2-opts']?.headers?.host; + if ( + isPresent(proxy, 'h2-opts.headers.Host') && + !Array.isArray(host) + ) { + proxy['h2-opts'].headers.host = [host]; + } + } if ( ['trojan', 'tuic', 'hysteria', 'hysteria2'].includes( proxy.type, diff --git a/backend/src/core/proxy-utils/producers/shadowrocket.js b/backend/src/core/proxy-utils/producers/shadowrocket.js index 84e29f9..c19c28a 100644 --- a/backend/src/core/proxy-utils/producers/shadowrocket.js +++ b/backend/src/core/proxy-utils/producers/shadowrocket.js @@ -126,6 +126,25 @@ export default function ShadowRocket_Producer() { proxy['http-opts'].headers.Host = [httpHost]; } } + if ( + ['vmess', 'vless'].includes(proxy.type) && + proxy.network === 'h2' + ) { + let path = proxy['h2-opts']?.path; + if ( + isPresent(proxy, 'h2-opts.path') && + Array.isArray(path) + ) { + proxy['h2-opts'].path = path[0]; + } + let host = proxy['h2-opts']?.headers?.host; + if ( + isPresent(proxy, 'h2-opts.headers.Host') && + !Array.isArray(host) + ) { + proxy['h2-opts'].headers.host = [host]; + } + } if ( ['trojan', 'tuic', 'hysteria', 'hysteria2'].includes( diff --git a/backend/src/core/proxy-utils/producers/stash.js b/backend/src/core/proxy-utils/producers/stash.js index 3d017da..aaffc97 100644 --- a/backend/src/core/proxy-utils/producers/stash.js +++ b/backend/src/core/proxy-utils/producers/stash.js @@ -206,6 +206,25 @@ export default function Stash_Producer() { proxy['http-opts'].headers.Host = [httpHost]; } } + if ( + ['vmess', 'vless'].includes(proxy.type) && + proxy.network === 'h2' + ) { + let path = proxy['h2-opts']?.path; + if ( + isPresent(proxy, 'h2-opts.path') && + Array.isArray(path) + ) { + proxy['h2-opts'].path = path[0]; + } + let host = proxy['h2-opts']?.headers?.host; + if ( + isPresent(proxy, 'h2-opts.headers.Host') && + !Array.isArray(host) + ) { + proxy['h2-opts'].headers.host = [host]; + } + } if ( ['trojan', 'tuic', 'hysteria', 'hysteria2'].includes( proxy.type, diff --git a/backend/src/core/proxy-utils/producers/surfboard.js b/backend/src/core/proxy-utils/producers/surfboard.js index 5c7658e..08f1675 100644 --- a/backend/src/core/proxy-utils/producers/surfboard.js +++ b/backend/src/core/proxy-utils/producers/surfboard.js @@ -6,6 +6,7 @@ const targetPlatform = 'Surfboard'; export default function Surfboard_Producer() { const produce = (proxy) => { + proxy.name = proxy.name.replace(/=/g, ''); switch (proxy.type) { case 'ss': return shadowsocks(proxy); diff --git a/backend/src/core/proxy-utils/producers/surge.js b/backend/src/core/proxy-utils/producers/surge.js index 2754b80..e3fdf0d 100644 --- a/backend/src/core/proxy-utils/producers/surge.js +++ b/backend/src/core/proxy-utils/producers/surge.js @@ -69,7 +69,7 @@ function shadowsocks(proxy) { `,obfs-uri=${proxy['plugin-opts'].path}`, 'plugin-opts.path', ); - } else { + } else if (!['shadow-tls'].includes(proxy.plugin)) { throw new Error(`plugin ${proxy.plugin} is not supported`); } } @@ -95,6 +95,24 @@ function shadowsocks(proxy) { `,shadow-tls-sni=${proxy['shadow-tls-sni']}`, 'shadow-tls-sni', ); + } else if (['shadow-tls'].includes(proxy.plugin) && proxy['plugin-opts']) { + const password = proxy['plugin-opts'].password; + const host = proxy['plugin-opts'].host; + const version = proxy['plugin-opts'].version; + if (password) { + result.append(`,shadow-tls-password=${password}`); + if (host) { + result.append(`,shadow-tls-sni=${host}`); + } + if (version) { + if (version < 2) { + throw new Error( + `shadow-tls version ${version} is not supported`, + ); + } + result.append(`,shadow-tls-version=${version}`); + } + } } // block-quic diff --git a/backend/src/core/proxy-utils/producers/uri.js b/backend/src/core/proxy-utils/producers/uri.js index 5819606..b304504 100644 --- a/backend/src/core/proxy-utils/producers/uri.js +++ b/backend/src/core/proxy-utils/producers/uri.js @@ -42,6 +42,9 @@ export default function URI_Producer() { if (proxy['udp-over-tcp']) { result = `${result}${proxy.plugin ? '&' : '?'}uot=1`; } + if (proxy.tfo) { + result = `${result}${proxy.plugin ? '&' : '?'}tfo=1`; + } result += `#${encodeURIComponent(proxy.name)}`; break; case 'ssr':