const test = require("node:test"); const assert = require("node:assert/strict"); const fs = require("node:fs"); const path = require("node:path"); const vm = require("node:vm"); function loadInternals() { const scriptPath = path.join(__dirname, "nordvpn-client.js"); const source = fs.readFileSync(scriptPath, "utf8").replace(/\nmain\(\);\s*$/, "\n"); const wrapped = `${source} module.exports = { buildMacTailscaleState: typeof buildMacTailscaleState === "function" ? buildMacTailscaleState : undefined, buildMacDnsState: typeof buildMacDnsState === "function" ? buildMacDnsState : undefined, buildWireguardConfig: typeof buildWireguardConfig === "function" ? buildWireguardConfig : undefined, buildLookupResult: typeof buildLookupResult === "function" ? buildLookupResult : undefined, cleanupMacWireguardState: typeof cleanupMacWireguardState === "function" ? cleanupMacWireguardState : undefined, cleanupMacWireguardAndDnsState: typeof cleanupMacWireguardAndDnsState === "function" ? cleanupMacWireguardAndDnsState : undefined, collectMacWireguardDiagnostics: typeof collectMacWireguardDiagnostics === "function" ? collectMacWireguardDiagnostics : undefined, inspectMacWireguardHelperSecurity: typeof inspectMacWireguardHelperSecurity === "function" ? inspectMacWireguardHelperSecurity : undefined, getMacTailscalePath: typeof getMacTailscalePath === "function" ? getMacTailscalePath : undefined, isBenignMacWireguardAbsentError: typeof isBenignMacWireguardAbsentError === "function" ? isBenignMacWireguardAbsentError : undefined, isMacTailscaleActive: typeof isMacTailscaleActive === "function" ? isMacTailscaleActive : undefined, normalizeSuccessfulConnectState: typeof normalizeSuccessfulConnectState === "function" ? normalizeSuccessfulConnectState : undefined, normalizeStatusState: typeof normalizeStatusState === "function" ? normalizeStatusState : undefined, shouldManageMacDnsService: typeof shouldManageMacDnsService === "function" ? shouldManageMacDnsService : undefined, sanitizeOutputPayload: typeof sanitizeOutputPayload === "function" ? sanitizeOutputPayload : undefined, shouldFinalizeMacWireguardConnect: typeof shouldFinalizeMacWireguardConnect === "function" ? shouldFinalizeMacWireguardConnect : undefined, shouldResumeMacTailscale: typeof shouldResumeMacTailscale === "function" ? shouldResumeMacTailscale : undefined, shouldAttemptMacWireguardDisconnect: typeof shouldAttemptMacWireguardDisconnect === "function" ? shouldAttemptMacWireguardDisconnect : undefined, detectMacWireguardActiveFromIfconfig: typeof detectMacWireguardActiveFromIfconfig === "function" ? detectMacWireguardActiveFromIfconfig : undefined, resolveHostnameWithFallback: typeof resolveHostnameWithFallback === "function" ? resolveHostnameWithFallback : undefined, verifyConnectionWithRetry: typeof verifyConnectionWithRetry === "function" ? verifyConnectionWithRetry : undefined, };`; const sandbox = { require, module: { exports: {} }, exports: {}, __dirname, __filename: scriptPath, process: { ...process, exit() {} }, console, setTimeout, clearTimeout, Buffer, }; vm.runInNewContext(wrapped, sandbox, { filename: scriptPath }); return sandbox.module.exports; } test("detectMacWireguardActiveFromIfconfig detects nordvpn utun client address", () => { const { detectMacWireguardActiveFromIfconfig } = loadInternals(); assert.equal(typeof detectMacWireguardActiveFromIfconfig, "function"); const ifconfig = ` utun8: flags=8051 mtu 1380 utun9: flags=8051 mtu 1420 \tinet 10.5.0.2 --> 10.5.0.2 netmask 0xff000000 `; assert.equal(detectMacWireguardActiveFromIfconfig(ifconfig), true); assert.equal(detectMacWireguardActiveFromIfconfig("utun7: flags=8051\n\tinet 100.64.0.4"), false); }); test("buildLookupResult supports lookup all=true mode", () => { const { buildLookupResult } = loadInternals(); assert.equal(typeof buildLookupResult, "function"); assert.equal( JSON.stringify(buildLookupResult("104.26.9.44", { all: true })), JSON.stringify([{ address: "104.26.9.44", family: 4 }]) ); assert.equal(JSON.stringify(buildLookupResult("104.26.9.44", { all: false })), JSON.stringify(["104.26.9.44", 4])); }); test("buildWireguardConfig omits DNS and relies on post-connect networksetup on macOS", () => { const { buildWireguardConfig } = loadInternals(); assert.equal(typeof buildWireguardConfig, "function"); const config = buildWireguardConfig( { hostname: "tr73.nordvpn.com", ips: [{ ip: { version: 4, ip: "45.89.52.1" } }], technologies: [{ identifier: "wireguard_udp", metadata: [{ name: "public_key", value: "PUBKEY" }] }], }, "PRIVATEKEY" ); assert.equal(config.includes("DNS = 103.86.96.100, 103.86.99.100"), false); assert.equal(config.includes("AllowedIPs = 0.0.0.0/0"), true); }); test("shouldManageMacDnsService keeps active physical services and excludes virtual ones", () => { const { shouldManageMacDnsService } = loadInternals(); assert.equal(typeof shouldManageMacDnsService, "function"); assert.equal(shouldManageMacDnsService("Wi-Fi"), true); assert.equal(shouldManageMacDnsService("USB 10/100/1000 LAN"), true); assert.equal(shouldManageMacDnsService("Tailscale"), false); assert.equal(shouldManageMacDnsService("Thunderbolt Bridge"), false); assert.equal(shouldManageMacDnsService("Acme VPN"), false); }); test("buildMacDnsState records DNS and search domains per service", () => { const { buildMacDnsState } = loadInternals(); assert.equal(typeof buildMacDnsState, "function"); assert.equal( JSON.stringify( buildMacDnsState([ { name: "Wi-Fi", dnsServers: ["1.1.1.1"], searchDomains: [] }, { name: "USB 10/100/1000 LAN", dnsServers: [], searchDomains: ["lan"] }, ]) ), JSON.stringify({ services: [ { name: "Wi-Fi", dnsServers: ["1.1.1.1"], searchDomains: [] }, { name: "USB 10/100/1000 LAN", dnsServers: [], searchDomains: ["lan"] }, ], }) ); }); test("getMacTailscalePath falls back to /opt/homebrew/bin/tailscale when PATH lookup is missing", () => { const { getMacTailscalePath } = loadInternals(); assert.equal(typeof getMacTailscalePath, "function"); assert.equal( getMacTailscalePath({ commandExists: () => "", fileExists: (target) => target === "/opt/homebrew/bin/tailscale", }), "/opt/homebrew/bin/tailscale" ); }); test("buildMacTailscaleState records whether tailscale was active", () => { const { buildMacTailscaleState } = loadInternals(); assert.equal(typeof buildMacTailscaleState, "function"); assert.equal( JSON.stringify(buildMacTailscaleState(true)), JSON.stringify({ tailscaleWasActive: true, }) ); }); test("shouldResumeMacTailscale only resumes when previously active and not already running", () => { const { shouldResumeMacTailscale } = loadInternals(); assert.equal(typeof shouldResumeMacTailscale, "function"); assert.equal(shouldResumeMacTailscale({ tailscaleWasActive: true }, false), true); assert.equal(shouldResumeMacTailscale({ tailscaleWasActive: true }, true), false); assert.equal(shouldResumeMacTailscale({ tailscaleWasActive: false }, false), false); assert.equal(shouldResumeMacTailscale(null, false), false); }); test("cleanupMacWireguardState removes stale config and last-connection files", () => { const { cleanupMacWireguardState } = loadInternals(); assert.equal(typeof cleanupMacWireguardState, "function"); const tmpDir = fs.mkdtempSync(path.join(fs.mkdtempSync("/tmp/nordvpn-client-test-"), "state-")); const configPath = path.join(tmpDir, "nordvpnctl.conf"); const lastConnectionPath = path.join(tmpDir, "last-connection.json"); fs.writeFileSync(configPath, "wireguard-config"); fs.writeFileSync(lastConnectionPath, "{\"country\":\"Germany\"}"); const result = cleanupMacWireguardState({ configPath, lastConnectionPath, }); assert.equal(result.cleaned, true); assert.equal(fs.existsSync(configPath), false); assert.equal(fs.existsSync(lastConnectionPath), false); }); test("cleanupMacWireguardAndDnsState removes stale config, DNS snapshot, and last-connection files", () => { const { cleanupMacWireguardAndDnsState } = loadInternals(); assert.equal(typeof cleanupMacWireguardAndDnsState, "function"); const tmpDir = fs.mkdtempSync(path.join(fs.mkdtempSync("/tmp/nordvpn-client-test-"), "state-")); const configPath = path.join(tmpDir, "nordvpnctl.conf"); const lastConnectionPath = path.join(tmpDir, "last-connection.json"); const dnsStatePath = path.join(tmpDir, "dns.json"); fs.writeFileSync(configPath, "wireguard-config"); fs.writeFileSync(lastConnectionPath, "{\"country\":\"Germany\"}"); fs.writeFileSync(dnsStatePath, "{\"services\":[]}"); const result = cleanupMacWireguardAndDnsState({ configPath, lastConnectionPath, dnsStatePath, }); assert.equal(result.cleaned, true); assert.equal(fs.existsSync(configPath), false); assert.equal(fs.existsSync(lastConnectionPath), false); assert.equal(fs.existsSync(dnsStatePath), false); }); test("inspectMacWireguardHelperSecurity rejects a user-owned helper path", () => { const { inspectMacWireguardHelperSecurity } = loadInternals(); assert.equal(typeof inspectMacWireguardHelperSecurity, "function"); const result = inspectMacWireguardHelperSecurity("/tmp/nordvpn-wireguard-helper.sh", { fileExists: () => true, statSync: () => ({ uid: 501, gid: 20, mode: 0o100755, }), }); assert.equal(result.exists, true); assert.equal(result.hardened, false); assert.match(result.reason, /root-owned/i); }); test("inspectMacWireguardHelperSecurity accepts a root-owned non-writable helper path", () => { const { inspectMacWireguardHelperSecurity } = loadInternals(); assert.equal(typeof inspectMacWireguardHelperSecurity, "function"); const result = inspectMacWireguardHelperSecurity("/tmp/nordvpn-wireguard-helper.sh", { fileExists: () => true, statSync: () => ({ uid: 0, gid: 0, mode: 0o100755, }), }); assert.equal(result.exists, true); assert.equal(result.hardened, true); assert.equal(result.reason, ""); }); test("collectMacWireguardDiagnostics captures bounded wg/ifconfig/route/process output", async () => { const { collectMacWireguardDiagnostics } = loadInternals(); assert.equal(typeof collectMacWireguardDiagnostics, "function"); const seen = []; const result = await collectMacWireguardDiagnostics({ interfaceName: "nordvpnctl", runExec: async (command, args) => { seen.push(`${command} ${args.join(" ")}`); if (command === "/opt/homebrew/bin/wg") { return { ok: true, stdout: "interface: nordvpnctl\npeer: abc123", stderr: "", error: "" }; } if (command === "ifconfig") { return { ok: true, stdout: "utun8: flags=8051\n\tinet 10.5.0.2 --> 10.5.0.2", stderr: "", error: "" }; } if (command === "route") { return { ok: true, stdout: "default 10.5.0.2 UGSc", stderr: "", error: "" }; } if (command === "pgrep") { return { ok: true, stdout: "1234 wireguard-go utun\n5678 wg-quick up nordvpnctl", stderr: "", error: "" }; } throw new Error(`unexpected command: ${command}`); }, }); assert.deepEqual(seen, [ "/opt/homebrew/bin/wg show nordvpnctl", "ifconfig nordvpnctl", "route -n get default", "pgrep -fl wireguard-go|wg-quick|nordvpnctl", ]); assert.equal(result.interfaceName, "nordvpnctl"); assert.equal(result.wgShow.includes("peer: abc123"), true); assert.equal(result.ifconfig.includes("10.5.0.2"), true); assert.equal(result.routes.includes("default 10.5.0.2"), true); assert.equal(result.processes.includes("wireguard-go"), true); }); test("shouldAttemptMacWireguardDisconnect does not trust active=false when residual state exists", () => { const { shouldAttemptMacWireguardDisconnect } = loadInternals(); assert.equal(typeof shouldAttemptMacWireguardDisconnect, "function"); assert.equal( shouldAttemptMacWireguardDisconnect({ active: false, configPath: "/Users/stefano/.nordvpn-client/wireguard/nordvpnctl.conf", endpoint: null, lastConnection: null, }), true ); assert.equal( shouldAttemptMacWireguardDisconnect({ active: false, configPath: null, endpoint: null, lastConnection: { country: "Italy" }, }), true ); assert.equal( shouldAttemptMacWireguardDisconnect({ active: false, configPath: null, endpoint: null, lastConnection: null, }), false ); }); test("isBenignMacWireguardAbsentError recognizes stale-interface teardown errors", () => { const { isBenignMacWireguardAbsentError } = loadInternals(); assert.equal(typeof isBenignMacWireguardAbsentError, "function"); assert.equal(isBenignMacWireguardAbsentError("wg-quick: `nordvpnctl' is not a WireGuard interface"), true); assert.equal(isBenignMacWireguardAbsentError("Unable to access interface: No such file or directory"), true); assert.equal(isBenignMacWireguardAbsentError("permission denied"), false); }); test("normalizeSuccessfulConnectState marks the connect snapshot active after verified macOS wireguard connect", () => { const { normalizeSuccessfulConnectState } = loadInternals(); assert.equal(typeof normalizeSuccessfulConnectState, "function"); const state = normalizeSuccessfulConnectState( { platform: "darwin", controlMode: "wireguard", connected: false, wireguard: { active: false, endpoint: null, }, }, { backend: "wireguard", server: { hostname: "de1227.nordvpn.com", }, }, { ok: true, ipInfo: { country: "Germany", }, } ); assert.equal(state.connected, true); assert.equal(state.wireguard.active, true); assert.equal(state.wireguard.endpoint, "de1227.nordvpn.com:51820"); }); test("shouldFinalizeMacWireguardConnect requires a verified wireguard connect", () => { const { shouldFinalizeMacWireguardConnect } = loadInternals(); assert.equal(typeof shouldFinalizeMacWireguardConnect, "function"); assert.equal(shouldFinalizeMacWireguardConnect({ backend: "wireguard" }, { ok: true }), true); assert.equal(shouldFinalizeMacWireguardConnect({ backend: "wireguard" }, { ok: false }), false); assert.equal(shouldFinalizeMacWireguardConnect({ backend: "cli" }, { ok: true }), false); assert.equal(shouldFinalizeMacWireguardConnect(null, { ok: true }), false); }); test("normalizeStatusState marks macOS wireguard connected when public IP matches the last successful target", () => { const { normalizeStatusState } = loadInternals(); assert.equal(typeof normalizeStatusState, "function"); const state = normalizeStatusState({ platform: "darwin", controlMode: "wireguard", connected: false, wireguard: { active: false, endpoint: "tr73.nordvpn.com:51820", lastConnection: { requestedTarget: { country: "Turkey", city: "" }, resolvedTarget: { country: "Turkey", city: "Istanbul" }, }, }, publicIp: { ok: true, country: "Turkey", city: "Istanbul", }, }); assert.equal(state.connected, true); assert.equal(state.wireguard.active, true); }); test("sanitizeOutputPayload redacts local path metadata from normal JSON output", () => { const { sanitizeOutputPayload } = loadInternals(); assert.equal(typeof sanitizeOutputPayload, "function"); const sanitized = sanitizeOutputPayload({ cliPath: "/opt/homebrew/bin/nordvpn", appPath: "/Applications/NordVPN.app", wireguard: { configPath: "/Users/stefano/.nordvpn-client/wireguard/nordvpnctl.conf", helperPath: "/Users/stefano/.openclaw/workspace/skills/nordvpn-client/scripts/nordvpn-wireguard-helper.sh", authCache: { tokenSource: "default:/Users/stefano/.openclaw/workspace/.clawdbot/credentials/nordvpn/token.txt", }, endpoint: "jp454.nordvpn.com:51820", }, }); assert.equal(sanitized.cliPath, null); assert.equal(sanitized.appPath, null); assert.equal(sanitized.wireguard.configPath, null); assert.equal(sanitized.wireguard.helperPath, null); assert.equal(sanitized.wireguard.authCache.tokenSource, null); assert.equal(sanitized.wireguard.endpoint, "jp454.nordvpn.com:51820"); }); test("isMacTailscaleActive treats Running backend as active", () => { const { isMacTailscaleActive } = loadInternals(); assert.equal(typeof isMacTailscaleActive, "function"); assert.equal(isMacTailscaleActive({ BackendState: "Running" }), true); assert.equal(isMacTailscaleActive({ BackendState: "Stopped" }), false); }); test("verifyConnectionWithRetry retries transient reachability failures", async () => { const { verifyConnectionWithRetry } = loadInternals(); assert.equal(typeof verifyConnectionWithRetry, "function"); let attempts = 0; const result = await verifyConnectionWithRetry( { country: "Italy", city: "Milan" }, { attempts: 3, delayMs: 1, getPublicIpInfo: async () => { attempts += 1; if (attempts === 1) { return { ok: false, error: "read EHOSTUNREACH" }; } return { ok: true, country: "Italy", city: "Milan" }; }, } ); assert.equal(result.ok, true); assert.equal(result.ipInfo.country, "Italy"); assert.equal(attempts, 2); }); test("resolveHostnameWithFallback uses fallback resolvers when system lookup fails", async () => { const { resolveHostnameWithFallback } = loadInternals(); assert.equal(typeof resolveHostnameWithFallback, "function"); const calls = []; const address = await resolveHostnameWithFallback("ipapi.co", { resolvers: ["1.1.1.1", "8.8.8.8"], resolveWithResolver: async (hostname, resolver) => { calls.push(`${resolver}:${hostname}`); if (resolver === "1.1.1.1") return []; return ["104.26.9.44"]; }, }); assert.equal(address, "104.26.9.44"); assert.deepEqual(calls, ["1.1.1.1:ipapi.co", "8.8.8.8:ipapi.co"]); });