import { test } from "node:test" import assert from "node:assert" import lib from "../tailscalectl/lib.js" const { parsePeers, makeExitNodeCommand, findActiveExitNode, errorMessage, validateClipboardCmd, buildCopyCommand, parseClipboardDetection } = lib test("parsePeers extracts exitNode from ExitNodeOption", () => { const peerMap = { "peer-1": { HostName: "router", TailscaleIPs: ["100.64.0.1"], Online: true, ExitNodeOption: true }, "peer-2": { HostName: "laptop", TailscaleIPs: ["100.64.0.2"], Online: true, ExitNodeOption: false } } const peers = parsePeers(peerMap) assert.strictEqual(peers[0].exitNode, true) assert.strictEqual(peers[1].exitNode, false) }) test("makeExitNodeCommand returns tailscale set command for hostname", () => { const cmd = makeExitNodeCommand("router") assert.deepStrictEqual(cmd, ["tailscale", "set", "--exit-node=router"]) }) test("makeExitNodeCommand with empty string clears exit node", () => { const cmd = makeExitNodeCommand("") assert.deepStrictEqual(cmd, ["tailscale", "set", "--exit-node="]) }) test("findActiveExitNode returns hostname of peer with ExitNode=true", () => { const peerMap = { "peer-1": { HostName: "gluetun-sjc", ExitNode: true, ExitNodeOption: true }, "peer-2": { HostName: "gluetun-den", ExitNode: false, ExitNodeOption: true } } assert.strictEqual(findActiveExitNode(peerMap), "gluetun-sjc") }) test("findActiveExitNode returns empty string when no exit node", () => { const peerMap = { "peer-1": { HostName: "laptop", ExitNode: false, ExitNodeOption: false } } assert.strictEqual(findActiveExitNode(peerMap), "") }) test("errorMessage returns user-friendly message for tailscale up failure", () => { const msg = errorMessage("up", 1) assert.strictEqual(msg, "Failed to connect to Tailscale") }) test("errorMessage returns user-friendly message for tailscale down failure", () => { const msg = errorMessage("down", 1) assert.strictEqual(msg, "Failed to disconnect from Tailscale") }) test("errorMessage returns user-friendly message for tailscale set failure", () => { const msg = errorMessage("set", 1) assert.strictEqual(msg, "Failed to set exit node") }) test("errorMessage returns user-friendly message for tailscale status failure", () => { const msg = errorMessage("status", 1) assert.strictEqual(msg, "Failed to read Tailscale status") }) test("errorMessage returns generic message for unknown command", () => { const msg = errorMessage("unknown", 1) assert.strictEqual(msg, "Tailscale command failed") }) // --- validateClipboardCmd --- test("validateClipboardCmd accepts whitelisted values", () => { assert.strictEqual(validateClipboardCmd("dms cl copy"), true) assert.strictEqual(validateClipboardCmd("wl-copy"), true) assert.strictEqual(validateClipboardCmd("clipmanctl copy"), true) assert.strictEqual(validateClipboardCmd("none"), true) }) test("validateClipboardCmd rejects malicious inputs", () => { assert.strictEqual(validateClipboardCmd("rm -rf /"), false) assert.strictEqual(validateClipboardCmd("echo hi; malicious"), false) assert.strictEqual(validateClipboardCmd("$(whoami)"), false) assert.strictEqual(validateClipboardCmd("wl-copy || rm -rf /"), false) }) test("validateClipboardCmd rejects empty and falsy inputs", () => { assert.strictEqual(validateClipboardCmd(""), false) assert.strictEqual(validateClipboardCmd(null), false) assert.strictEqual(validateClipboardCmd(undefined), false) }) // --- buildCopyCommand --- test("buildCopyCommand returns safe command for whitelisted clipboard tool", () => { const cmd = buildCopyCommand("hello", "wl-copy") assert.ok(Array.isArray(cmd)) assert.strictEqual(cmd[0], "sh") assert.strictEqual(cmd[1], "-c") }) test("buildCopyCommand returns null for invalid clipboard command", () => { assert.strictEqual(buildCopyCommand("hello", "rm -rf /"), null) assert.strictEqual(buildCopyCommand("hello", ""), null) assert.strictEqual(buildCopyCommand("hello", null), null) }) test("buildCopyCommand safely handles text with special characters", () => { const cmd = buildCopyCommand("it's a 'test' with \"quotes\" and\nnewlines", "wl-copy") assert.ok(Array.isArray(cmd)) }) // --- parseClipboardDetection --- test("parseClipboardDetection passes through expected output strings", () => { assert.strictEqual(parseClipboardDetection("dms cl copy"), "dms cl copy") assert.strictEqual(parseClipboardDetection("wl-copy"), "wl-copy") assert.strictEqual(parseClipboardDetection("clipmanctl copy"), "clipmanctl copy") assert.strictEqual(parseClipboardDetection("none"), "none") }) test("parseClipboardDetection trims extra whitespace", () => { assert.strictEqual(parseClipboardDetection(" wl-copy \n"), "wl-copy") }) test("parseClipboardDetection falls back to none for multi-line output", () => { assert.strictEqual(parseClipboardDetection("wl-copy\nrm -rf /"), "none") }) test("parseClipboardDetection falls back to empty output", () => { assert.strictEqual(parseClipboardDetection(""), "none") assert.strictEqual(parseClipboardDetection(" "), "none") }) test("parseClipboardDetection falls back to none for unexpected strings", () => { assert.strictEqual(parseClipboardDetection("xclip -selection clipboard"), "none") assert.strictEqual(parseClipboardDetection("custom-tool"), "none") })