diff --git a/config-sub-converter/scripts/convert-awg-to-clash.js b/config-sub-converter/scripts/convert-awg-to-clash.js new file mode 100644 index 0000000..1fefc8a --- /dev/null +++ b/config-sub-converter/scripts/convert-awg-to-clash.js @@ -0,0 +1,176 @@ +/** + * Sub Store JS script: AmneziaWG/ProtonVPN (WG INI) -> Clash (wireguard proxy) + * + * Expected input: text like: + * [Interface] + * Address = ... + * DNS = ... + * PrivateKey = ... + * ... + * [Peer] + * PublicKey = ... + * PresharedKey = ... + * AllowedIPs = ... + * Endpoint = host:port + * + * Output: YAML fragment: + * proxies: + * - name: "..." + * type: wireguard + * ... + */ +function parseIniWG(text) { + const lines = text + .replace(/\r\n/g, "\n") + .split("\n") + .map((l) => l.trim()) + .filter((l) => l.length > 0 && !l.startsWith("#") && !l.startsWith(";")); + + let section = null; + const data = { Interface: {}, Peer: {} }; + + for (const line of lines) { + const mSec = line.match(/^\[(.+?)\]$/); + if (mSec) { + section = mSec[1]; + continue; + } + const mKV = line.match(/^([^=]+?)\s*=\s*(.+)$/); + if (!mKV || !section) continue; + + const key = mKV[1].trim(); + const value = mKV[2].trim(); + + if (section.toLowerCase() === "interface") data.Interface[key] = value; + else if (section.toLowerCase() === "peer") data.Peer[key] = value; + } + return data; +} + +function splitList(val) { + // "a, b, c" -> ["a","b","c"] + return String(val || "") + .split(",") + .map((s) => s.trim()) + .filter(Boolean); +} + +function parseEndpoint(endpoint) { + // supports: host:port (IPv6 in brackets not handled here; can add if needed) + const m = String(endpoint || "").match(/^(.+?):(\d+)$/); + if (!m) return { host: "", port: 0 }; + return { host: m[1], port: Number(m[2]) }; +} + +function toNumIfPossible(v) { + const s = String(v ?? "").trim(); + if (s === "") return null; + if (/^-?\d+$/.test(s)) return Number(s); + return s; +} + +function yamlEscapeString(s) { + // simplest safe quoting + const str = String(s ?? ""); + return `"${str.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`; +} + +function yamlScalar(v) { + if (v === null || v === undefined) return "null"; + if (typeof v === "number" && Number.isFinite(v)) return String(v); + if (typeof v === "boolean") return v ? "true" : "false"; + return yamlEscapeString(v); +} + +function yamlInlineArray(arr) { + const a = Array.isArray(arr) ? arr : []; + return `[${a.map((x) => yamlScalar(x)).join(", ")}]`; +} + +function buildClashProxyFromWG(wg, proxyName) { + const i = wg.Interface || {}; + const p = wg.Peer || {}; + + const address = i.Address || ""; + const dnsList = splitList(i.DNS); + + const { host, port } = parseEndpoint(p.Endpoint); + + const allowed = splitList(p.AllowedIPs); + + // Amnezia fields (case-insensitive keys are NOT guaranteed in input, handle both) + const pick = (k) => (i[k] !== undefined ? i[k] : i[k.toLowerCase()] !== undefined ? i[k.toLowerCase()] : undefined); + + const amzKeys = [ + ["jc", pick("Jc")], + ["jmin", pick("Jmin")], + ["jmax", pick("Jmax")], + ["s1", pick("S1")], + ["s2", pick("S2")], + ["h1", pick("H1")], + ["h2", pick("H2")], + ["h3", pick("H3")], + ["h4", pick("H4")], + ]; + + const amzObj = {}; + for (const [k, v] of amzKeys) { + if (v !== undefined) amzObj[k] = toNumIfPossible(v); + } + + // Compose YAML (manual, predictable formatting) + const name = proxyName && String(proxyName).trim() ? String(proxyName).trim() : "amz-wg"; + + let out = ""; + out += "proxies:\n"; + out += ` - name: ${yamlEscapeString(name)}\n`; + out += ` type: wireguard\n`; + out += ` ip: ${yamlScalar(address)}\n`; + out += ` private-key: ${yamlScalar(i.PrivateKey || "")}\n`; + out += ` peers:\n`; + out += ` - server: ${yamlScalar(host)}\n`; + out += ` port: ${yamlScalar(port)}\n`; + out += ` public-key: ${yamlScalar(p.PublicKey || "")}\n`; + if (p.PresharedKey) out += ` pre-shared-key: ${yamlScalar(p.PresharedKey)}\n`; + out += ` allowed-ips: ${yamlInlineArray(allowed)}\n`; + out += ` udp: true\n`; + out += ` remote-dns-resolve: true\n`; + if (dnsList.length) out += ` dns: ${yamlInlineArray(dnsList)}\n`; + if (Object.keys(amzObj).length) { + out += ` amnezia-wg-option:\n`; + for (const k of Object.keys(amzObj)) { + out += ` ${k}: ${yamlScalar(amzObj[k])}\n`; + } + } + + return out; +} + +/** + * Sub Store entrypoint. + * Most Sub Store scripts expose a function like: + * module.exports = async (ctx) => { ... } + * where ctx has raw subscription text in ctx.content / ctx.body / etc. + * + * To be robust across environments, we try common fields. + */ +module.exports = async (ctx) => { + const input = + (ctx && (ctx.content || ctx.body || ctx.data || ctx.text)) ?? + ""; + + const wg = parseIniWG(String(input)); + + // Try to derive a name if Sub Store provides something (optional) + // Fallback: "amz-wg" + const derivedName = + (ctx && (ctx.name || ctx.profileName || ctx.filename)) || + "amz-wg"; + + const yaml = buildClashProxyFromWG(wg, derivedName); + + // Return in whatever field Sub Store expects + // Common patterns: return string, or set ctx.content + if (ctx) ctx.content = yaml; + return yaml; +}; diff --git a/proxy-provider/scarus/basic_amnezia_configs/KZ.conf b/proxy-provider/scarus/basic_amnezia_configs/KZ.conf deleted file mode 100644 index f624837..0000000 --- a/proxy-provider/scarus/basic_amnezia_configs/KZ.conf +++ /dev/null @@ -1,24 +0,0 @@ -# Generated on: 2025-12-02 09:51:50 -# VPN Key: vpn://vpn://AAAA_3icdY1PC4IwGIe_iuxcHYwKu4VQIB4Uieo0xlw2dH-cm6Hid2-bRKdOL7zPw--ZAEeMgGMAToyTkaIgU4RRw8AqACXpsKJSU8H_GFjwJ61gT1S3SKF9IknhAuxjAh1RPcUE6kH6EFpm1vI381WkElpg0XjtXTlkLLNrhms12Fv6CWXA7EJGv2CJNPIdl63J4HgbX8Yy2qebq8riXCZJURcoqW67_pynbSPDcHtoHtEdgXn-AEBTVs8= -# Keenetic: interface Wireguard0 wireguard asc 4 10 50 110 20 211644422 533572853 237534087 1314455475 - -[Interface] -Address = 100.70.184.183/32 -DNS = 8.8.8.8, 8.8.4.4 -PrivateKey = ZiA7zQ9osP4nEoB5jryU99gpHFg6cTprfiaA1nV/pks= -Jc = 4 -Jmin = 10 -Jmax = 50 -S1 = 110 -S2 = 20 -H1 = 211644422 -H2 = 533572853 -H3 = 237534087 -H4 = 1314455475 - -[Peer] -PublicKey = 5uUhd8S8MjnULEEAiSQysBi+JO6zfrXC0QIIsqsjUkc= -PresharedKey = aJ4XS6+QgVasEcGP+5DInldM5i/YSR6PPmmix0wMtFA= -AllowedIPs = 0.0.0.0/0, ::/0 -Endpoint = 5.189.202.78:46358 -PersistentKeepalive = 25 diff --git a/proxy-provider/scarus/basic_amnezia_configs/NetherlAWG4874.conf b/proxy-provider/scarus/basic_amnezia_configs/NetherlAWG4874.conf deleted file mode 100644 index 7eac198..0000000 --- a/proxy-provider/scarus/basic_amnezia_configs/NetherlAWG4874.conf +++ /dev/null @@ -1,20 +0,0 @@ -[Interface] -PrivateKey = mJd8aibZI0iuQqPxpTdbs1Enb9+Ury7ido20lu2NrWo= -Address = 10.136.82.167/32 -DNS = 1.1.1.1, 8.8.4.4 -MTU = 1380 -Jc = 43 -Jmin = 50 -Jmax = 70 -S1 = 110 -S2 = 120 -H1 = 1593635057 -H2 = 430880481 -H3 = 1214405368 -H4 = 1739253821 -[Peer] -PublicKey = gbUPMNfaxgRSGD3xcnnbAJSclxfnOyh4U1qqmYMWmCI= -PresharedKey = SCz82d6cfj9bfdlUyHwEBYC3u4T3znL6wFpJ7dMQYbM= -AllowedIPs = 0.0.0.0/0, ::/0 -PersistentKeepalive = 25 -Endpoint = nl02awg.kcufwfgnkr.net:60136 \ No newline at end of file diff --git a/proxy-provider/scarus/basic_amnezia_configs/PL.conf b/proxy-provider/scarus/basic_amnezia_configs/PL.conf deleted file mode 100644 index 5f3ef65..0000000 --- a/proxy-provider/scarus/basic_amnezia_configs/PL.conf +++ /dev/null @@ -1,24 +0,0 @@ -# Generated on: 2025-12-02 09:35:19 -# VPN Key: vpn://vpn://AAAA_3icdY1PC4IwGIe_iuxcHYwKu4VQIB4Uieo0xlw2dH-cm6Hid2-bRKdOL7zPw--ZAEeMgGMAToyTkaIgU4RRw8AqACXpsKJSU8H_GFjwJ61gT1S3SKF9IknhAuxjAh1RPcUE6kH6EFpm1vI381WkElpg0XjtXTlkLLNrhms12Fv6CWXA7EJGv2CJNPIdl63J4HgbX8Yy2qebq8riXCZJURcoqW67_pynbSPDcHtoHtEdgXn-AEBTVs8= -# Keenetic: interface Wireguard0 wireguard asc 2 10 50 18 122 1512494805 1147470590 1658720028 1826833034 - -[Interface] -Address = 100.71.64.86/32 -DNS = 8.8.8.8, 8.8.4.4 -PrivateKey = /K20yRTTw44Ged/fXjdf4hSLnr33igHMl0SAXy0aMCE= -Jc = 2 -Jmin = 10 -Jmax = 50 -S1 = 18 -S2 = 122 -H1 = 1512494805 -H2 = 1147470590 -H3 = 1658720028 -H4 = 1826833034 - -[Peer] -PublicKey = Z01PDi29KeHvdtThNoSmXdxG4zyT1yFbulcI7AA5nQg= -PresharedKey = uExSfwmdNaUTiJmyNNMuoDavJEKdrdsAqNaVcZ/U00Y= -AllowedIPs = 0.0.0.0/0, ::/0 -Endpoint = 212.23.222.12:37089 -PersistentKeepalive = 25 diff --git a/proxy-provider/scarus/basic_amnezia_configs/US.conf b/proxy-provider/scarus/basic_amnezia_configs/US.conf deleted file mode 100644 index e750803..0000000 --- a/proxy-provider/scarus/basic_amnezia_configs/US.conf +++ /dev/null @@ -1,24 +0,0 @@ -# Generated on: 2025-12-02 09:46:50 -# VPN Key: vpn://vpn://AAAA_3icdY1PC4IwGIe_iuxcHYwKu4VQIB4Uieo0xlw2dH-cm6Hid2-bRKdOL7zPw--ZAEeMgGMAToyTkaIgU4RRw8AqACXpsKJSU8H_GFjwJ61gT1S3SKF9IknhAuxjAh1RPcUE6kH6EFpm1vI381WkElpg0XjtXTlkLLNrhms12Fv6CWXA7EJGv2CJNPIdl63J4HgbX8Yy2qebq8riXCZJURcoqW67_pynbSPDcHtoHtEdgXn-AEBTVs8= -# Keenetic: interface Wireguard0 wireguard asc 3 10 50 145 34 203715079 914012290 174842657 1514769902 - -[Interface] -Address = 100.71.64.155/32 -DNS = 8.8.8.8, 8.8.4.4 -PrivateKey = Vuk0huRtjGpA7KtWuQN/kJE0CRFOFs3JysN71nDFGqg= -Jc = 3 -Jmin = 10 -Jmax = 50 -S1 = 145 -S2 = 34 -H1 = 203715079 -H2 = 914012290 -H3 = 174842657 -H4 = 1514769902 - -[Peer] -PublicKey = ZqTlR9tYsMacuawQQaU6UCoXdT1exYJD2tzFXTpN9zs= -PresharedKey = oOJNRLL+5aOgimi28Lwq18w6xCrry4AFLt68fhbUSlk= -AllowedIPs = 0.0.0.0/0, ::/0 -Endpoint = 5.8.93.236:42854 -PersistentKeepalive = 25 diff --git a/proxy-provider/scarus/hynet.txt b/proxy-provider/scarus/hynet.txt deleted file mode 100644 index 62fdc6d..0000000 --- a/proxy-provider/scarus/hynet.txt +++ /dev/null @@ -1,12 +0,0 @@ -ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTpER1E3THlXRHBSOVFrU2ZvZi1zcnN3@151.243.101.40:2060#%E2%9A%A1%D0%92%D0%B5%D0%BB%D0%B8%D0%BA%D0%BE%D0%B1%D1%80%D0%B8%D1%82%D0%B0%D0%BD%D0%B8%D1%8F%20-%20GB_T074055 -vmess://eyJhZGQiOiAiMTUxLjI0My4xMDEuNDAiLCAiYWlkIjogIjAiLCAiaG9zdCI6ICJnb29nbGUuY29tIiwgImlkIjogImEzZTc1OTM2LTBlNDQtNGJjOS1iOTdlLWExZmRiMjc2Y2NhNCIsICJuZXQiOiAidGNwIiwgInBhdGgiOiAiLyIsICJwb3J0IjogODA4MSwgInBzIjogIlx1MjZhMVx1MDQxMlx1MDQzNVx1MDQzYlx1MDQzOFx1MDQzYVx1MDQzZVx1MDQzMVx1MDQ0MFx1MDQzOFx1MDQ0Mlx1MDQzMFx1MDQzZFx1MDQzOFx1MDQ0ZiAtIEdCX1QwNzQwNTUiLCAic2N5IjogImF1dG8iLCAidGxzIjogIm5vbmUiLCAidHlwZSI6ICJodHRwIiwgInYiOiAiMiJ9 -vmess://eyJhZGQiOiAiMTUxLjI0My4xMDEuNDAiLCAiYWlkIjogIjAiLCAiaG9zdCI6ICJnb29nbGUuY29tIiwgImlkIjogImEzZTc1OTM2LTBlNDQtNGJjOS1iOTdlLWExZmRiMjc2Y2NhNCIsICJuZXQiOiAid3MiLCAicGF0aCI6ICIvIiwgInBvcnQiOiA4MDgwLCAicHMiOiAiXHUyNmExXHUwNDEyXHUwNDM1XHUwNDNiXHUwNDM4XHUwNDNhXHUwNDNlXHUwNDMxXHUwNDQwXHUwNDM4XHUwNDQyXHUwNDMwXHUwNDNkXHUwNDM4XHUwNDRmIC0gR0JfVDA3NDA1NSIsICJzY3kiOiAiYXV0byIsICJ0bHMiOiAibm9uZSIsICJ0eXBlIjogIiIsICJ2IjogIjIifQ== -vless://ca1a269d-6409-4bbf-a4e2-1e9cb04490e2@151.243.101.40:8443?security=reality&type=tcp&headerType=&path=&host=&sni=discordapp.com&fp=chrome&pbk=SbVKOEMjK0sIlbwg4akyBg5mL5KZwwB-ed4eEE7YnRc&sid=6ba85179e30d4fc2#%E2%9A%A1%D0%92%D0%B5%D0%BB%D0%B8%D0%BA%D0%BE%D0%B1%D1%80%D0%B8%D1%82%D0%B0%D0%BD%D0%B8%D1%8F%20-%20GB_T074055 -vless://ca1a269d-6409-4bbf-a4e2-1e9cb04490e2@151.243.101.40:2053?security=reality&type=grpc&headerType=&serviceName=xyz&authority=&mode=gun&sni=discordapp.com&fp=chrome&pbk=SbVKOEMjK0sIlbwg4akyBg5mL5KZwwB-ed4eEE7YnRc&sid=#%E2%9A%A1%D0%92%D0%B5%D0%BB%D0%B8%D0%BA%D0%BE%D0%B1%D1%80%D0%B8%D1%82%D0%B0%D0%BD%D0%B8%D1%8F%20-%20GB_T074055 -trojan://TEx16RQixr5cJ3rCBz1Ddw@151.243.101.40:2058?security=tls&type=ws&headerType=&path=%2F&host=&sni=uk.hydranet.space&fp=#%E2%9A%A1%D0%92%D0%B5%D0%BB%D0%B8%D0%BA%D0%BE%D0%B1%D1%80%D0%B8%D1%82%D0%B0%D0%BD%D0%B8%D1%8F%20-%20GB_T074055 -ss://Y2hhY2hhMjAtaWV0Zi1wb2x5MTMwNTp2aVluTUlnYW83TjlIbVlCWHV5ZnRB@109.235.48.181:2060#%E2%9A%A1%D0%9D%D0%B8%D0%B4%D0%B5%D1%80%D0%BB%D0%B0%D0%BD%D0%B4%D1%8B%20-%20NL_T078756 -vmess://eyJhZGQiOiAiMTA5LjIzNS40OC4xODEiLCAiYWlkIjogIjAiLCAiaG9zdCI6ICJnb29nbGUuY29tIiwgImlkIjogIjM1Y2EyMDY5LWFmYmYtNDkwMi04ZWIwLWViYjUxZTUwYjNiMyIsICJuZXQiOiAidGNwIiwgInBhdGgiOiAiLyIsICJwb3J0IjogODA4MSwgInBzIjogIlx1MjZhMVx1MDQxZFx1MDQzOFx1MDQzNFx1MDQzNVx1MDQ0MFx1MDQzYlx1MDQzMFx1MDQzZFx1MDQzNFx1MDQ0YiAtIE5MX1QwNzg3NTYiLCAic2N5IjogImF1dG8iLCAidGxzIjogIm5vbmUiLCAidHlwZSI6ICJodHRwIiwgInYiOiAiMiJ9 -vmess://eyJhZGQiOiAiMTA5LjIzNS40OC4xODEiLCAiYWlkIjogIjAiLCAiaG9zdCI6ICJnb29nbGUuY29tIiwgImlkIjogIjM1Y2EyMDY5LWFmYmYtNDkwMi04ZWIwLWViYjUxZTUwYjNiMyIsICJuZXQiOiAid3MiLCAicGF0aCI6ICIvIiwgInBvcnQiOiA4MDgwLCAicHMiOiAiXHUyNmExXHUwNDFkXHUwNDM4XHUwNDM0XHUwNDM1XHUwNDQwXHUwNDNiXHUwNDMwXHUwNDNkXHUwNDM0XHUwNDRiIC0gTkxfVDA3ODc1NiIsICJzY3kiOiAiYXV0byIsICJ0bHMiOiAibm9uZSIsICJ0eXBlIjogIiIsICJ2IjogIjIifQ== -vless://b9ae9a97-18da-4c5d-9ada-3b0a92d4813e@109.235.48.181:8443?security=reality&type=tcp&headerType=&path=&host=&sni=vkvideo.ru&fp=chrome&pbk=SbVKOEMjK0sIlbwg4akyBg5mL5KZwwB-ed4eEE7YnRc&sid=6ba85179e30d4fc2#%E2%9A%A1%D0%9D%D0%B8%D0%B4%D0%B5%D1%80%D0%BB%D0%B0%D0%BD%D0%B4%D1%8B%20-%20NL_T078756 -vless://b9ae9a97-18da-4c5d-9ada-3b0a92d4813e@109.235.48.181:2053?security=reality&type=grpc&headerType=&serviceName=xyz&authority=&mode=gun&sni=vkvideo.ru&fp=chrome&pbk=SbVKOEMjK0sIlbwg4akyBg5mL5KZwwB-ed4eEE7YnRc&sid=#%E2%9A%A1%D0%9D%D0%B8%D0%B4%D0%B5%D1%80%D0%BB%D0%B0%D0%BD%D0%B4%D1%8B%20-%20NL_T078756 -trojan://tbPsjmK8x6xSDW1vTO8V5g@109.235.48.181:2058?security=tls&type=ws&headerType=&path=%2F&host=&sni=nl2.hydranet.space&fp=#%E2%9A%A1%D0%9D%D0%B8%D0%B4%D0%B5%D1%80%D0%BB%D0%B0%D0%BD%D0%B4%D1%8B%20-%20NL_T078756 \ No newline at end of file