import assert from "node:assert/strict" import { fileURLToPath } from "node:url" import { wireguardInterfaceDependencyPaths, wireguardInterfaceDeleteProof, type WireguardInterfaceDeleteState } from "./wireguard-interface-delete.js" import { wireguardPublicKey } from "./wireguard-interface-create.js" import { planWireguardInterfaceUpdate, projectWireguardInterfaceUpdate, wireguardInterfaceUpdateSchema, wireguardInterfaceUpdateProof } from "./wireguard-interface-update.js" import { wireguardInterfaceUpdatePlanSchema } from "../modules/mcp/wireguard-interface-update-actions.js" import { sameWireguardEndpoint } from "./wireguard-source.js" import type { ServerRow } from "../modules/servers/repository/servers-repository.js" export async function acceptWireguardInterfaceUpdateModel() { const endpoint = { id: 136, enabled: true, host: "127.0.0.1", port: 443, username: "admin", password: "NEVER_ENDPOINT_PASSWORD", useSsl: true, verifySsl: true, routingEndpointEpoch: "35adfb60-9da1-44fa-b699-9ce1a32371bf", name: "before", updatedAt: new Date(0) } as ServerRow assert.equal(sameWireguardEndpoint({ ...endpoint, name: "after", comment: "metadata", updatedAt: new Date() }, endpoint), true) assert.equal(sameWireguardEndpoint({ ...endpoint, routingEndpointEpoch: "ae5e2528-fe50-483b-a128-dc8ad90de36f" }, endpoint), false) assert.equal(sameWireguardEndpoint({ ...endpoint, password: "changed" }, endpoint), false) const privateKey = Buffer.alloc(32, 61).toString("base64"), nextKey = Buffer.alloc(32, 62).toString("base64") const state: WireguardInterfaceDeleteState = { base: { interfaces: [{ ".id": "*a", name: "wg-owned", disabled: "false", mtu: "1420", "listen-port": "13231", "private-key": privateKey, "public-key": wireguardPublicKey(privateKey), opaque: "NEVER_OPAQUE" }], peers: [{ ".id": "*b", interface: "wg-owned", "public-key": wireguardPublicKey(nextKey), disabled: "false", "allowed-address": "192.0.2.2/32" }], bindings: [], flow: { hostPublicKey: "", registered: false }, serverProof: "source", proof: "base" }, ipv4: [{ ".id": "*c", interface: "wg-owned", address: "192.0.2.1/24", disabled: "false", dynamic: "false" }, { ".id": "*d", interface: "wg-owned", address: "198.51.100.1/24", disabled: "false", dynamic: "false", comment: "secondary" }], ipv6: [], dependencies: Object.fromEntries(wireguardInterfaceDependencyPaths.map(path => [path, []])), filters: [], proof: "" } state.dependencies["/interface"].push({ ".id": "*a", name: "wg-owned", type: "wg" }) state.proof = await wireguardInterfaceDeleteProof(state) const beforeProofNormalization = structuredClone(state), scalarProof = await wireguardInterfaceUpdateProof(state) const originalBytes = Buffer.from(privateKey, "base64"), equivalentKeys: string[] = [] for (let ignored = 0; ignored < 32; ignored++) { const bytes = Buffer.from(originalBytes) bytes[0] = (bytes[0] & 248) | (ignored & 7) bytes[31] = (bytes[31] & 63) | ((ignored >> 3) << 6) const equivalent = bytes.toString("base64"); equivalentKeys.push(equivalent) assert.equal(wireguardPublicKey(equivalent), state.base.interfaces[0]["public-key"]) const changed = structuredClone(state); changed.base.interfaces[0]["private-key"] = equivalent assert.equal(await wireguardInterfaceUpdateProof(changed), scalarProof, "All 32 RFC 7748 ignored-bit combinations prove one observed identity") changed.dependencies["/interface"][0]["private-key"] = privateKey assert.equal(await wireguardInterfaceUpdateProof(changed), scalarProof, "Corroborated generic key mirrors may differ only in ignored scalar bits") changed.dependencies["/interface"][0]["private-key"] = equivalent changed.base.interfaces[0]["private-key"] = privateKey assert.equal(await wireguardInterfaceUpdateProof(changed), scalarProof) } assert.deepEqual(state, beforeProofNormalization, "Proof normalization must not rewrite captured or native secret material") const meaningfulBytes = Buffer.from(originalBytes); meaningfulBytes[1] ^= 1 const meaningfulKey = meaningfulBytes.toString("base64"), inconsistent = structuredClone(state) inconsistent.base.interfaces[0]["private-key"] = meaningfulKey assert.notEqual(await wireguardInterfaceUpdateProof(inconsistent), scalarProof) const rotated = structuredClone(inconsistent); rotated.base.interfaces[0]["public-key"] = wireguardPublicKey(meaningfulKey) assert.notEqual(await wireguardInterfaceUpdateProof(rotated), scalarProof, "An actual key rotation remains visible") for (const publicKey of [undefined, "invalid", wireguardPublicKey(nextKey)]) { const first = structuredClone(state), second = structuredClone(state) if (publicKey === undefined) { delete first.base.interfaces[0]["public-key"]; delete second.base.interfaces[0]["public-key"] } else { first.base.interfaces[0]["public-key"] = publicKey; second.base.interfaces[0]["public-key"] = publicKey } first.base.interfaces[0]["private-key"] = equivalentKeys[0]; second.base.interfaces[0]["private-key"] = equivalentKeys[1] assert.notEqual(await wireguardInterfaceUpdateProof(first), await wireguardInterfaceUpdateProof(second), "A missing or inconsistent public identity cannot authorize key normalization") second.dependencies["/interface"][0]["private-key"] = equivalentKeys[0] await assert.rejects(wireguardInterfaceUpdateProof(second), "An inconsistent generic private mirror cannot be normalized") } const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", noncanonical = privateKey.slice(0, -2) + alphabet[alphabet.indexOf(privateKey.at(-2)!) ^ 1] + "=" assert.deepEqual(Buffer.from(noncanonical, "base64"), originalBytes) const opaqueKeys: Array = [undefined, "", "********", "(hidden)", "invalid-key", noncanonical, Buffer.alloc(32).toString("base64")] const opaqueProofs: string[] = [] for (const opaque of opaqueKeys) { const changed = structuredClone(state) if (opaque === undefined) delete changed.base.interfaces[0]["private-key"]; else changed.base.interfaces[0]["private-key"] = opaque const unchanged = structuredClone(changed), proof = await wireguardInterfaceUpdateProof(changed) assert.equal(await wireguardInterfaceUpdateProof(changed), proof); assert.deepEqual(changed, unchanged) opaqueProofs.push(proof) } assert.equal(new Set(opaqueProofs).size, opaqueKeys.length, "Missing, invalid and unknown key representations remain exact opaque state") assert.ok(opaqueProofs.every(proof => proof !== scalarProof)) const wrongGeneric = structuredClone(state); wrongGeneric.dependencies["/interface"][0]["private-key"] = meaningfulKey await assert.rejects(wireguardInterfaceUpdateProof(wrongGeneric)) const opaqueGeneric = structuredClone(state); opaqueGeneric.base.interfaces[0]["private-key"] = "(hidden)"; opaqueGeneric.dependencies["/interface"][0]["private-key"] = "(hidden)" await wireguardInterfaceUpdateProof(opaqueGeneric) opaqueGeneric.dependencies["/interface"][0]["private-key"] = "********" await assert.rejects(wireguardInterfaceUpdateProof(opaqueGeneric)) const changedOpaque = structuredClone(state); changedOpaque.base.interfaces[0].opaque = equivalentKeys[0] assert.notEqual(await wireguardInterfaceUpdateProof(changedOpaque), scalarProof) const all = { name: "renamed", mtu: 1380, listenPort: 23456, comment: "updated", disabled: true, privateKey: nextKey } const commands = planWireguardInterfaceUpdate(state, "*a", all) assert.equal(commands.length, 1) const next = projectWireguardInterfaceUpdate(state, commands[0]) const beforeProjectedProof = structuredClone(next) await wireguardInterfaceUpdateProof(next) assert.deepEqual(next, beforeProjectedProof); assert.equal(commands[0].body?.["private-key"], nextKey); assert.equal(next.base.interfaces[0]["private-key"], nextKey) assert.equal(next.base.interfaces[0]["public-key"], wireguardPublicKey(nextKey)) assert.equal(next.base.interfaces[0].opaque, "NEVER_OPAQUE") assert.equal(next.base.peers[0].interface, "renamed") assert.equal(next.ipv4[0].interface, "renamed") assert.equal(next.dependencies["/interface"][0].name, "renamed") assert.notEqual(await wireguardInterfaceDeleteProof(next), state.proof) const generic = structuredClone(state) generic.base.interfaces.push({ ".id": "*f", name: "wg-foreign", disabled: "true", mtu: "1420" }) generic.dependencies["/interface"].push({ ".id": "*f", name: "wg-foreign", type: "wg", mtu: "1420", disabled: "yes", opaque: "NEVER_FOREIGN_GENERIC" }) const genericProof = await wireguardInterfaceUpdateProof(generic) const foreignKey = structuredClone(generic) foreignKey.base.interfaces[1]["private-key"] = privateKey; foreignKey.base.interfaces[1]["public-key"] = wireguardPublicKey(privateKey) const foreignProof = await wireguardInterfaceUpdateProof(foreignKey) foreignKey.base.interfaces[1]["private-key"] = meaningfulKey assert.notEqual(await wireguardInterfaceUpdateProof(foreignKey), foreignProof, "Foreign private material cannot drift under an unchanged public identity") foreignKey.base.interfaces[1]["public-key"] = wireguardPublicKey(meaningfulKey) assert.notEqual(await wireguardInterfaceUpdateProof(foreignKey), foreignProof, "Foreign public identity and real key rotation remain sealed") generic.dependencies["/interface"][1]["rx-byte"] = "1234"; generic.dependencies["/interface"][1]["fp-rx-byte"] = "5678" assert.equal(await wireguardInterfaceUpdateProof(generic), genericProof) generic.dependencies["/interface"][1].opaque = "NEVER_CHANGED_FOREIGN" assert.notEqual(await wireguardInterfaceUpdateProof(generic), genericProof) generic.dependencies["/interface"][1].mtu = "1380" await assert.rejects(wireguardInterfaceUpdateProof(generic)) const mirrors = structuredClone(state); Object.assign(mirrors.dependencies["/interface"][0], { mtu: "1420", disabled: "no" }) const projectedMirrors = projectWireguardInterfaceUpdate(mirrors, commands[0]) assert.equal(projectedMirrors.dependencies["/interface"][0].mtu, "1380"); assert.equal(projectedMirrors.dependencies["/interface"][0].disabled, "true") await wireguardInterfaceUpdateProof(projectedMirrors) const address = planWireguardInterfaceUpdate(state, "*a", { address: "2001:db8::1/64" }) assert.deepEqual(address.map(command => command.method), ["DELETE", "PUT"]) assert.equal(address[0].id, "*c"); assert.equal(address[1].body?.advertise, "false") const removed = projectWireguardInterfaceUpdate(state, address[0]), added = projectWireguardInterfaceUpdate(removed, address[1], "*e") assert.equal(added.ipv4.length, 1); assert.equal(added.ipv4[0].comment, "secondary"); assert.equal(added.ipv6[0].address, "2001:db8::1/64") assert.deepEqual(planWireguardInterfaceUpdate(state, "*a", { address: "" }).map(command => command.id), ["*c"]) assert.deepEqual(planWireguardInterfaceUpdate(state, "*a", { address: "198.51.100.1/24" }).map(command => command.id), ["*c"]) assert.equal(planWireguardInterfaceUpdate(state, "*a", { address: "192.0.2.1/24" }).length, 0) for (const bad of [{}, { name: "\u0000bad" }, { listenPort: 65536 }, { mtu: 0 }, { privateKey: "bad" }, { unknown: true }]) assert.equal(wireguardInterfaceUpdateSchema.safeParse(bad).success, false) assert.equal(wireguardInterfaceUpdatePlanSchema.safeParse({ serverId: 136, interfaceId: "*a", patch: { privateKey: nextKey } }).success, false) assert.equal(wireguardInterfaceUpdatePlanSchema.safeParse({ serverId: 136, interfaceId: "*a", patch: { privateKeyRef: "b9ae94ed-5d23-4edb-b71b-60207a110c47" } }).success, true) assert.throws(() => planWireguardInterfaceUpdate(state, "*a", { name: "renamed", address: "192.0.2.3/24" })) for (const mutate of [ (value: typeof state) => { value.dependencies["/interface/vlan"].push({ ".id": "*f", interface: "wg-owned" }) }, (value: typeof state) => { value.base.interfaces[0].comment = "MikrotikManager traffic-flow overlay" }, (value: typeof state) => { value.dependencies["/interface"][0][".id"] = "*f" }, (value: typeof state) => { value.ipv4[0].dynamic = "true" }, ]) { const changed = structuredClone(state); mutate(changed); assert.throws(() => planWireguardInterfaceUpdate(changed, "*a", { disabled: true })) } console.log("WireGuard interface update model: all 32 corroborated RFC7748 scalar encodings, exact opaque/invalid keys, generic mirrors, real/foreign rotation, immutable native material; full fields, rename children, addresses and dependency protections checked") } if (process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1]) await acceptWireguardInterfaceUpdateModel()