diff --git a/backend/package.json b/backend/package.json index 7161e6f..35a6cc7 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 c4b4538..b69aaeb 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 2aa2a29..116a4d4 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 fa9cfae..6ef95de 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; };