Files
suaveplan/packages/networking/drive/drive-template/tests/cdn-upload-token.test.ts
2026-05-27 23:47:53 +01:00

171 lines
5.3 KiB
TypeScript

/**
* DTP-19 — CdnUploadToken issuance and verification.
*/
import { describe, expect, it } from "@suaveplan/testing/runner";
import type { CdnUploadToken } from "../src/index.js";
import {
canonicalSerializeUploadToken,
type DriveTemplateError,
DTP_CODES,
signUploadToken,
UPLOAD_TOKEN_TTL_DEFAULT_MS,
UPLOAD_TOKEN_TTL_MAX_MS,
verifyUploadToken,
} from "../src/index.js";
import { makeKeys } from "./_helpers.js";
const NOW = 2_000_000_000;
function baseToken(): Omit<CdnUploadToken, "serverSignature" | "expiresAt"> {
return {
fileId: "f".repeat(64),
chunkId: 12,
chunkHash: "blake3:abcdef",
uploaderPubkey: "pubkey-hex",
};
}
describe("DTP-19 — CdnUploadToken", () => {
it("default TTL pinned at 60s; max at 5m", { timeout: 5000 }, () => {
expect(UPLOAD_TOKEN_TTL_DEFAULT_MS).toBe(60_000);
expect(UPLOAD_TOKEN_TTL_MAX_MS).toBe(300_000);
});
it("valid token accepted", { timeout: 5000 }, () => {
const keys = makeKeys();
const tok = signUploadToken(
{ ...baseToken(), expiresAt: NOW + 30_000 },
keys.secret,
{ clock: () => NOW }
);
expect(verifyUploadToken(tok, keys.publicHex, () => NOW + 1_000)).toBe(
true
);
});
it("expired token rejected", { timeout: 5000 }, () => {
const keys = makeKeys();
const tok = signUploadToken(
{ ...baseToken(), expiresAt: NOW + 30_000 },
keys.secret,
{ clock: () => NOW }
);
try {
verifyUploadToken(tok, keys.publicHex, () => NOW + 100_000);
throw new Error("expected expired");
} catch (err) {
expect((err as DriveTemplateError).code).toBe(
DTP_CODES.CDN_BAD_SIGNATURE
);
}
});
it("tampered token rejected", { timeout: 5000 }, () => {
const keys = makeKeys();
const tok = signUploadToken(
{ ...baseToken(), expiresAt: NOW + 30_000 },
keys.secret,
{ clock: () => NOW }
);
const tampered = { ...tok, chunkId: tok.chunkId + 1 };
try {
verifyUploadToken(tampered, keys.publicHex, () => NOW);
throw new Error("expected sig failure");
} catch (err) {
expect((err as DriveTemplateError).code).toBe(
DTP_CODES.CDN_BAD_SIGNATURE
);
}
});
it("token signed by wrong key rejected", { timeout: 5000 }, () => {
const k1 = makeKeys();
const k2 = makeKeys();
const tok = signUploadToken(
{ ...baseToken(), expiresAt: NOW + 30_000 },
k1.secret,
{ clock: () => NOW }
);
try {
verifyUploadToken(tok, k2.publicHex, () => NOW);
throw new Error("expected sig failure");
} catch (err) {
expect((err as DriveTemplateError).code).toBe(
DTP_CODES.CDN_BAD_SIGNATURE
);
}
});
it("invalid server pubkey hex rejected", { timeout: 5000 }, () => {
const keys = makeKeys();
const tok = signUploadToken(
{ ...baseToken(), expiresAt: NOW + 30_000 },
keys.secret,
{ clock: () => NOW }
);
try {
verifyUploadToken(tok, "not-hex", () => NOW);
throw new Error("expected pubkey rejection");
} catch (err) {
expect((err as DriveTemplateError).code).toBe(
DTP_CODES.CDN_BAD_SIGNATURE
);
}
});
it("ttlMs out of range rejected at sign", { timeout: 5000 }, () => {
const keys = makeKeys();
expect(() =>
signUploadToken({ ...baseToken(), expiresAt: 0 }, keys.secret, {
clock: () => NOW,
ttlMs: 0,
})
).toThrow();
expect(() =>
signUploadToken({ ...baseToken(), expiresAt: 0 }, keys.secret, {
clock: () => NOW,
ttlMs: UPLOAD_TOKEN_TTL_MAX_MS + 1,
})
).toThrow();
});
it("canonicalSerializeUploadToken is deterministic", {
timeout: 5000,
}, () => {
const tok = { ...baseToken(), expiresAt: NOW + 30_000 };
const a = canonicalSerializeUploadToken(tok);
const b = canonicalSerializeUploadToken(tok);
expect(a).toEqual(b);
});
it("default options use Date.now() as clock", { timeout: 5000 }, () => {
const keys = makeKeys();
const tok = signUploadToken(
{ ...baseToken(), expiresAt: 0 },
keys.secret
);
expect(tok.expiresAt).toBeGreaterThan(0);
});
it("malformed signature buffer triggers verify catch arm", {
timeout: 5000,
}, () => {
const keys = makeKeys();
const tok = signUploadToken(
{ ...baseToken(), expiresAt: NOW + 30_000 },
keys.secret,
{ clock: () => NOW }
);
const broken = { ...tok, serverSignature: new Uint8Array(8) };
try {
verifyUploadToken(broken, keys.publicHex, () => NOW);
throw new Error("expected rejection");
} catch (err) {
expect((err as DriveTemplateError).code).toBe(
DTP_CODES.CDN_BAD_SIGNATURE
);
}
});
});