Initial Commit
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
* DTP-06 — replay protection via per-client nonce LRU.
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "@suaveplan/testing/runner";
|
||||
import {
|
||||
type DriveTemplateError,
|
||||
DTP_CODES,
|
||||
TEMPLATE_NONCE_LRU_DEFAULT_CAPACITY,
|
||||
TemplateNonceLru,
|
||||
validateTemplate,
|
||||
} from "../src/index.js";
|
||||
import { makeKeys, makeNonce, signed } from "./_helpers.js";
|
||||
|
||||
describe("DTP-06 — replay protection", () => {
|
||||
it("hydrate with same (driveId, nonce) twice rejects on second call", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const keys = makeKeys();
|
||||
const lru = new TemplateNonceLru();
|
||||
const tpl = signed(
|
||||
{
|
||||
issuer: keys.publicHex,
|
||||
nonce: makeNonce(0x42),
|
||||
},
|
||||
keys
|
||||
);
|
||||
const ctx = { clock: () => Date.now(), nonceLru: lru };
|
||||
validateTemplate(tpl, ctx);
|
||||
try {
|
||||
validateTemplate(tpl, ctx);
|
||||
throw new Error("expected REPLAY rejection");
|
||||
} catch (err) {
|
||||
expect((err as DriveTemplateError).code).toBe(
|
||||
DTP_CODES.TEMPLATE_REPLAY
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
it("LRU capacity is the documented default", { timeout: 5000 }, () => {
|
||||
expect(TEMPLATE_NONCE_LRU_DEFAULT_CAPACITY).toBe(1024);
|
||||
});
|
||||
|
||||
it("LRU evicts oldest entry past capacity", { timeout: 5000 }, () => {
|
||||
const lru = new TemplateNonceLru(2);
|
||||
const a = makeNonce(1);
|
||||
const b = makeNonce(2);
|
||||
const c = makeNonce(3);
|
||||
lru.remember("d", a);
|
||||
lru.remember("d", b);
|
||||
lru.remember("d", c);
|
||||
expect(lru.has("d", a)).toBe(false);
|
||||
expect(lru.has("d", b)).toBe(true);
|
||||
expect(lru.has("d", c)).toBe(true);
|
||||
expect(lru.size).toBe(2);
|
||||
});
|
||||
|
||||
it("LRU reinserts on duplicate to refresh recency", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const lru = new TemplateNonceLru(2);
|
||||
const a = makeNonce(1);
|
||||
const b = makeNonce(2);
|
||||
lru.remember("d", a);
|
||||
lru.remember("d", b);
|
||||
lru.remember("d", a); // refresh
|
||||
const c = makeNonce(3);
|
||||
lru.remember("d", c); // evicts b, not a
|
||||
expect(lru.has("d", a)).toBe(true);
|
||||
expect(lru.has("d", b)).toBe(false);
|
||||
expect(lru.has("d", c)).toBe(true);
|
||||
});
|
||||
|
||||
it("LRU rejects non-positive capacity", { timeout: 5000 }, () => {
|
||||
expect(() => new TemplateNonceLru(0)).toThrow();
|
||||
expect(() => new TemplateNonceLru(-1)).toThrow();
|
||||
expect(() => new TemplateNonceLru(1.5)).toThrow();
|
||||
});
|
||||
|
||||
it("clear() empties the LRU", { timeout: 5000 }, () => {
|
||||
const lru = new TemplateNonceLru(8);
|
||||
lru.remember("d", makeNonce(1));
|
||||
expect(lru.size).toBe(1);
|
||||
lru.clear();
|
||||
expect(lru.size).toBe(0);
|
||||
});
|
||||
|
||||
it("capacity getter exposes the configured cap", {
|
||||
timeout: 5000,
|
||||
}, () => {
|
||||
const lru = new TemplateNonceLru(99);
|
||||
expect(lru.capacity).toBe(99);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user