-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest.js
More file actions
73 lines (60 loc) · 4.35 KB
/
Copy pathtest.js
File metadata and controls
73 lines (60 loc) · 4.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// test.js — agent-recovery tests (security-focused). Run: npm test
import { RecoveryManager } from "./src/recovery.js";
import { createCustodyBinding, verifyCustodyBinding, createOwnershipEntry, verifyOwnershipEntry } from "./src/custody.js";
import { RotationLedger } from "./src/rotation.js";
let pass = 0, fail = 0;
const check = (name, cond, detail = "") => {
if (cond) { pass++; console.log(`PASS ${name}`); }
else { fail++; console.log(`FAIL ${name} :: ${detail}`); }
};
const SECRET = "test-secret";
const AGENT = "eip155-2091125bfe-df5dea@agents.inbox";
const OWNER = "0xOwnerAddress00000000000000000000000000000";
// --- R1: threshold + time-lock + veto ---
const mgr = new RecoveryManager({ threshold: 2, guardians: ["g1", "g2", "g3"], hmacKey: SECRET, timeLockMs: 1000 });
check("threshold invalid throws", (() => { try { new RecoveryManager({ threshold: 4, guardians: ["a", "b"], hmacKey: SECRET }); return false; } catch { return true; } })());
const rec = mgr.beginRecovery({ agentHandle: AGENT, requesterId: "new-device" });
check("beginRecovery returns id + signed descriptor", rec.id && /^[0-9a-f]{64}$/.test(rec.signature || ""), JSON.stringify(rec));
check("non-guardian cannot approve", mgr.approve(rec.id, "attacker").error === "not_a_guardian");
check("first approval not granted", mgr.approve(rec.id, "g1").granted === false);
check("second approval grants", mgr.approve(rec.id, "g2").granted === true);
// Time-lock not elapsed -> cannot complete
check("cannot complete before time-lock", mgr.complete(rec.id).error === "time_lock_not_elapsed");
// Veto (original owner) blocks recovery
const vetoSig = mgr._sign("veto:" + rec.id); // simulate owner signature (known secret in test)
// GC: a fresh recovery to un-veto test:
const rec2 = mgr.beginRecovery({ agentHandle: AGENT, requesterId: "new-device-2" });
mgr.approve(rec2.id, "g1"); mgr.approve(rec2.id, "g2");
check("veto blocks recovery", mgr.veto(rec2.id, magicVeto(mgr, rec2.id)).ok === true); // see helper
check("after veto, complete fails", mgr.complete(rec2.id).error === "recovery_vetoed");
function magicVeto(m, id) { return m._sign("veto:" + id); } // helper defined at module scope is fine above
// Time-lock: wait then complete the first (non-vetoed) recovery
await sleep(1100);
const done = mgr.complete(rec.id);
check("recovery completes after time-lock", done.ok === true && done.completed.signature);
function sleep(ms) { return new Promise((r) => setTimeout(r, ms)); }
// --- R2: custody binding + ownership ledger ---
const binding = createCustodyBinding({ agentHandle: AGENT, deployer: OWNER, nonce: "n1", hmacKey: SECRET });
check("custody binding signed", binding.signature.includes("."));
check("binding verifies", verifyCustodyBinding(binding, SECRET).ok === true);
check("binding fails with wrong secret", verifyCustodyBinding(binding, "wrong").ok === false);
// Relabeling the JSON fields must NOT change the verified agent (signed body wins).
const relabeled = verifyCustodyBinding({ ...binding, agentHandle: "evil@agents.inbox" }, SECRET);
check("relabeled binding still resolves to signed agent", relabeled.ok === true && relabeled.agentHandle === AGENT, JSON.stringify(relabeled));
const entry = createOwnershipEntry({ agentHandle: AGENT, deployer: OWNER, period: "2026-09-23", creditsConsumed: 42, creditsEarned: 100, timeActiveMs: 3600000, hmacKey: SECRET });
check("ownership entry verifies", verifyOwnershipEntry(entry, SECRET).ok === true);
check("ownership entry tamper rejected", verifyOwnershipEntry({ ...entry, signature: entry.signature.slice(0, -4) + "beef" }, SECRET).ok === false);
// --- R3: rotation ledger chain ---
const led = new RotationLedger({ hmacKey: SECRET });
led.rotate({ agentHandle: AGENT, newKeyFingerprint: "k1", reason: "device-loss", authorizedBy: "recovery" });
led.rotate({ agentHandle: AGENT, newKeyFingerprint: "k2", reason: "periodic", authorizedBy: "owner" });
check("chain verifies unbroken", led.verifyChain().ok === true);
// tamper: break a link
const tampered = led.list();
tampered[1].previousHash = "forged";
check("tampered chain detected", led.verifyChain().ok === false && led.verifyChain().error === "chain_break");
// inheritance
const claim = led.claimInheritance({ agentHandle: AGENT, beneficiary: "0xHeir", designatedBy: OWNER });
check("inheritance claim signed", claim.ok && claim.claim.signature);
console.log(`\n${pass} passed, ${fail} failed`);
process.exit(fail ? 1 : 0);