From e24de8d0b64b85273c489ef0548e9fd419be5731 Mon Sep 17 00:00:00 2001 From: xream Date: Wed, 17 Apr 2024 00:56:53 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=AF=E6=8C=81=20WireGuard=20URI=20?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E5=92=8C=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/package.json | 2 +- backend/src/core/proxy-utils/parsers/index.js | 84 +++++++++++++++++++ .../core/proxy-utils/preprocessors/index.js | 3 + backend/src/core/proxy-utils/producers/uri.js | 45 +++++++++- 4 files changed, 132 insertions(+), 2 deletions(-) diff --git a/backend/package.json b/backend/package.json index 7161e6f1e..35a6cc7e7 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "sub-store", - "version": "2.14.282", + "version": "2.14.283", "description": "Advanced Subscription Manager for QX, Loon, Surge, Stash and ShadowRocket.", "main": "src/main.js", "scripts": { diff --git a/backend/src/core/proxy-utils/parsers/index.js b/backend/src/core/proxy-utils/parsers/index.js index c4b453800..b69aaeb57 100644 --- a/backend/src/core/proxy-utils/parsers/index.js +++ b/backend/src/core/proxy-utils/parsers/index.js @@ -674,6 +674,89 @@ function URI_TUIC() { }; return { name, test, parse }; } +function URI_WireGuard() { + const name = 'URI WireGuard Parser'; + const test = (line) => { + return /^(wireguard|wg):\/\//.test(line); + }; + const parse = (line) => { + line = line.split(/(wireguard|wg):\/\//)[2]; + /* eslint-disable no-unused-vars */ + let [ + __, + ___, + privateKey, + server, + ____, + port, + _____, + addons = '', + name, + ] = /^((.*?)@)?(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line); + /* eslint-enable no-unused-vars */ + + port = parseInt(`${port}`, 10); + if (isNaN(port)) { + port = 51820; + } + privateKey = decodeURIComponent(privateKey); + if (name != null) { + name = decodeURIComponent(name); + } + name = name ?? `WireGuard ${server}:${port}`; + const proxy = { + type: 'wireguard', + name, + server, + port, + 'private-key': privateKey, + udp: true, + }; + for (const addon of addons.split('&')) { + let [key, value] = addon.split('='); + key = key.replace(/_/, '-'); + value = decodeURIComponent(value); + if (['reserved'].includes(key)) { + const parsed = value + .split(',') + .map((i) => parseInt(i.trim(), 10)) + .filter((i) => Number.isInteger(i)); + if (parsed.length === 3) { + proxy[key] = parsed; + } + } else if (['address', 'ip'].includes(key)) { + value.split(',').map((i) => { + const ip = i + .trim() + .replace(/\/\d+$/, '') + .replace(/^\[/, '') + .replace(/\]$/, ''); + if (isIPv4(ip)) { + proxy.ip = ip; + } else if (isIPv6(ip)) { + proxy.ipv6 = ip; + } + }); + } else if (['mtu'].includes(key)) { + const parsed = parseInt(value.trim(), 10); + if (Number.isInteger(parsed)) { + proxy[key] = parsed; + } + } else if (/publickey/i.test(key)) { + proxy['public-key'] = value; + } else if (/privatekey/i.test(key)) { + proxy['private-key'] = value; + } else if (['udp'].includes(key)) { + proxy[key] = /(TRUE)|1/i.test(value); + } else if (!['flag'].includes(key)) { + proxy[key] = value; + } + } + + return proxy; + }; + return { name, test, parse }; +} // Trojan URI format function URI_Trojan() { @@ -1196,6 +1279,7 @@ export default [ URI_VMess(), URI_VLESS(), URI_TUIC(), + URI_WireGuard(), URI_Hysteria(), URI_Hysteria2(), URI_Trojan(), diff --git a/backend/src/core/proxy-utils/preprocessors/index.js b/backend/src/core/proxy-utils/preprocessors/index.js index 2aa2a2987..116a4d465 100644 --- a/backend/src/core/proxy-utils/preprocessors/index.js +++ b/backend/src/core/proxy-utils/preprocessors/index.js @@ -22,6 +22,9 @@ function Base64Encoded() { 'aHR0c', // htt 'dmxlc3M=', // vless 'aHlzdGVyaWEy', // hysteria2 + 'd2lyZWd1YXJkOi8v', // wireguard:// + 'd2c6Ly8=', // wg:// + 'dHVpYzovLw==', // tuic:// ]; const test = function (raw) { diff --git a/backend/src/core/proxy-utils/producers/uri.js b/backend/src/core/proxy-utils/producers/uri.js index fa9cfaef3..6ef95de46 100644 --- a/backend/src/core/proxy-utils/producers/uri.js +++ b/backend/src/core/proxy-utils/producers/uri.js @@ -411,8 +411,51 @@ export default function URI_Producer() { }?${tuicParams.join('&')}#${encodeURIComponent( proxy.name, )}`; - break; } + break; + case 'wireguard': + let wireguardParams = []; + + Object.keys(proxy).forEach((key) => { + if ( + ![ + 'name', + 'type', + 'server', + 'port', + 'ip', + 'ipv6', + 'private-key', + ].includes(key) + ) { + if (['public-key'].includes(key)) { + wireguardParams.push(`publickey=${proxy[key]}`); + } else if (['udp'].includes(key)) { + if (proxy[key]) { + wireguardParams.push(`${key}=1`); + } + } else if (proxy[key]) { + wireguardParams.push( + `${key}=${encodeURIComponent(proxy[key])}`, + ); + } + } + }); + if (proxy.ip && proxy.ipv6) { + wireguardParams.push( + `address=${proxy.ip}/32,${proxy.ipv6}/128`, + ); + } else if (proxy.ip) { + wireguardParams.push(`address=${proxy.ip}/32`); + } else if (proxy.ipv6) { + wireguardParams.push(`address=${proxy.ipv6}/128`); + } + result = `wireguard://${encodeURIComponent( + proxy['private-key'], + )}@${proxy.server}:${proxy.port}/?${wireguardParams.join( + '&', + )}#${encodeURIComponent(proxy.name)}`; + break; } return result; };