118 lines
3.9 KiB
TypeScript
118 lines
3.9 KiB
TypeScript
/**
|
|
* Forward-defensive catch arms in `codec/verify`, `key/grant-validator`,
|
|
* and `cdn/upload-token` — exercised here by injecting a throwing
|
|
* `verifyFn` so the catch path runs in production code rather than
|
|
* being papered over with `istanbul ignore` annotations. Per AGENTS.md
|
|
* §7a, defensive guards must have a real test exercising them.
|
|
*/
|
|
|
|
import { sign } from "@suaveplan/crypto-curve/ed25519";
|
|
import { describe, expect, it } from "@suaveplan/testing/runner";
|
|
import type { KeyGrantPayload } from "../src/index.js";
|
|
import {
|
|
canonicalSerializeKeyGrant,
|
|
DriveTemplateError,
|
|
DTP_CODES,
|
|
signTemplate,
|
|
signUploadToken,
|
|
validateKeyGrant,
|
|
verifyTemplateSignature,
|
|
verifyUploadToken,
|
|
} from "../src/index.js";
|
|
import { buildTemplate, makeKeys } from "./_helpers.js";
|
|
|
|
const NOW = 2_000_000_000;
|
|
|
|
function throwingVerify(): never {
|
|
throw new Error("synthetic verify failure");
|
|
}
|
|
|
|
describe("AGENTS §7a — verify catch arms", () => {
|
|
it("verifyTemplateSignature surfaces a thrown verifier as TEMPLATE_SIG_INVALID", {
|
|
timeout: 5000,
|
|
}, () => {
|
|
const keys = makeKeys();
|
|
const tpl = signTemplate(
|
|
buildTemplate({ issuer: keys.publicHex }),
|
|
keys.secret
|
|
);
|
|
try {
|
|
verifyTemplateSignature(tpl, throwingVerify);
|
|
throw new Error("expected SIG_INVALID");
|
|
} catch (err) {
|
|
expect(err).toBeInstanceOf(DriveTemplateError);
|
|
expect((err as DriveTemplateError).code).toBe(
|
|
DTP_CODES.TEMPLATE_SIG_INVALID
|
|
);
|
|
expect((err as DriveTemplateError).message).toContain(
|
|
"synthetic verify failure"
|
|
);
|
|
}
|
|
});
|
|
|
|
it("validateKeyGrant surfaces a thrown verifier as KEY_GRANT_REJECTED", {
|
|
timeout: 5000,
|
|
}, () => {
|
|
const issuer = makeKeys();
|
|
const recipient = makeKeys();
|
|
const base: Omit<KeyGrantPayload, "issuerSignature"> = {
|
|
fileId: "f".repeat(64),
|
|
recipient: recipient.publicHex,
|
|
wrappedKey: new Uint8Array(48).fill(7),
|
|
issuer: issuer.publicHex,
|
|
expiresAt: NOW + 60_000,
|
|
};
|
|
const canonical = canonicalSerializeKeyGrant(base);
|
|
const grant: KeyGrantPayload = {
|
|
...base,
|
|
issuerSignature: sign(canonical, issuer.secret),
|
|
};
|
|
try {
|
|
validateKeyGrant(grant, {
|
|
expectedKeyAuthority: issuer.publicHex,
|
|
ourPubkey: recipient.publicHex,
|
|
clock: () => NOW,
|
|
verifyFn: throwingVerify,
|
|
});
|
|
throw new Error("expected KEY_GRANT_REJECTED");
|
|
} catch (err) {
|
|
expect(err).toBeInstanceOf(DriveTemplateError);
|
|
expect((err as DriveTemplateError).code).toBe(
|
|
DTP_CODES.KEY_GRANT_REJECTED
|
|
);
|
|
expect((err as DriveTemplateError).message).toContain(
|
|
"synthetic verify failure"
|
|
);
|
|
}
|
|
});
|
|
|
|
it("verifyUploadToken surfaces a thrown verifier as CDN_BAD_SIGNATURE", {
|
|
timeout: 5000,
|
|
}, () => {
|
|
const keys = makeKeys();
|
|
const tok = signUploadToken(
|
|
{
|
|
fileId: "f".repeat(64),
|
|
chunkId: 0,
|
|
chunkHash: "blake3:abc",
|
|
uploaderPubkey: "uploader",
|
|
expiresAt: NOW + 30_000,
|
|
},
|
|
keys.secret,
|
|
{ clock: () => NOW }
|
|
);
|
|
try {
|
|
verifyUploadToken(tok, keys.publicHex, () => NOW, throwingVerify);
|
|
throw new Error("expected CDN_BAD_SIGNATURE");
|
|
} catch (err) {
|
|
expect(err).toBeInstanceOf(DriveTemplateError);
|
|
expect((err as DriveTemplateError).code).toBe(
|
|
DTP_CODES.CDN_BAD_SIGNATURE
|
|
);
|
|
expect((err as DriveTemplateError).message).toContain(
|
|
"synthetic verify failure"
|
|
);
|
|
}
|
|
});
|
|
});
|