mirror of
https://github.com/willchen96/mike.git
synced 2026-07-24 23:41:04 +02:00
Merge pull request #228 from amal66/olp-pr/test-harness
[Testing 05] test: minimal vitest harness for backend and frontend
This commit is contained in:
commit
8a34a6457f
7 changed files with 2683 additions and 31 deletions
1230
backend/package-lock.json
generated
1230
backend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -5,7 +5,8 @@
|
|||
"scripts": {
|
||||
"dev": "tsx watch src/index.ts",
|
||||
"build": "tsc",
|
||||
"start": "node dist/index.js"
|
||||
"start": "node dist/index.js",
|
||||
"test": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.90.0",
|
||||
|
|
@ -38,7 +39,8 @@
|
|||
"@types/node": "^22.14.1",
|
||||
"prettier": "^3.8.1",
|
||||
"tsx": "^4.19.3",
|
||||
"typescript": "^5.8.3"
|
||||
"typescript": "^5.8.3",
|
||||
"vitest": "^4.1.9"
|
||||
},
|
||||
"license": "AGPL-3.0-only"
|
||||
}
|
||||
|
|
|
|||
109
backend/src/lib/__tests__/downloadTokens.test.ts
Normal file
109
backend/src/lib/__tests__/downloadTokens.test.ts
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
import { describe, it, expect, beforeAll, afterAll } from "vitest";
|
||||
import { signDownload, verifyDownload, buildDownloadUrl } from "../downloadTokens";
|
||||
|
||||
const SECRET = "test-secret-32-bytes-long-enough!!";
|
||||
|
||||
beforeAll(() => {
|
||||
process.env.DOWNLOAD_SIGNING_SECRET = SECRET;
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
delete process.env.DOWNLOAD_SIGNING_SECRET;
|
||||
});
|
||||
|
||||
describe("signDownload", () => {
|
||||
it("returns a two-part dot-separated token", () => {
|
||||
const token = signDownload("documents/user/doc.pdf", "contract.pdf");
|
||||
const parts = token.split(".");
|
||||
expect(parts).toHaveLength(2);
|
||||
expect(parts[0].length).toBeGreaterThan(0);
|
||||
expect(parts[1].length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("produces different tokens for different paths", () => {
|
||||
const t1 = signDownload("documents/a/file.pdf", "a.pdf");
|
||||
const t2 = signDownload("documents/b/file.pdf", "b.pdf");
|
||||
expect(t1).not.toBe(t2);
|
||||
});
|
||||
|
||||
it("uses base64url characters only (no +, /, =)", () => {
|
||||
const token = signDownload("documents/user/file.pdf", "file.pdf");
|
||||
expect(token).not.toMatch(/[+/=]/);
|
||||
});
|
||||
});
|
||||
|
||||
describe("verifyDownload", () => {
|
||||
it("round-trips a valid token", () => {
|
||||
const path = "documents/user123/doc456/source.pdf";
|
||||
const filename = "Contract Final v2.pdf";
|
||||
const token = signDownload(path, filename);
|
||||
const result = verifyDownload(token);
|
||||
expect(result).not.toBeNull();
|
||||
expect(result!.path).toBe(path);
|
||||
expect(result!.filename).toBe(filename);
|
||||
});
|
||||
|
||||
it("returns null for a tampered payload", () => {
|
||||
const token = signDownload("documents/user/file.pdf", "file.pdf");
|
||||
const [, sig] = token.split(".");
|
||||
const fakePayload = Buffer.from(
|
||||
JSON.stringify({ p: "documents/attacker/file.pdf", f: "file.pdf" }),
|
||||
)
|
||||
.toString("base64")
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=+$/g, "");
|
||||
expect(verifyDownload(`${fakePayload}.${sig}`)).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null for a tampered signature", () => {
|
||||
const token = signDownload("documents/user/file.pdf", "file.pdf");
|
||||
const [enc] = token.split(".");
|
||||
const fakeSig = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
|
||||
expect(verifyDownload(`${enc}.${fakeSig}`)).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null for a token with too many parts", () => {
|
||||
expect(verifyDownload("a.b.c")).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null for a token with too few parts", () => {
|
||||
expect(verifyDownload("onlyonepart")).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null when payload JSON is missing required fields", () => {
|
||||
const bad = Buffer.from(JSON.stringify({ x: 1 }))
|
||||
.toString("base64")
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=+$/g, "");
|
||||
const sig = Buffer.alloc(32).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
||||
expect(verifyDownload(`${bad}.${sig}`)).toBeNull();
|
||||
});
|
||||
|
||||
it("returns null when signed with a different secret", () => {
|
||||
const token = signDownload("documents/user/file.pdf", "file.pdf");
|
||||
process.env.DOWNLOAD_SIGNING_SECRET = "different-secret-value-!!";
|
||||
const result = verifyDownload(token);
|
||||
process.env.DOWNLOAD_SIGNING_SECRET = SECRET;
|
||||
expect(result).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("buildDownloadUrl", () => {
|
||||
it("returns a path starting with /download/", () => {
|
||||
const url = buildDownloadUrl("documents/user/file.pdf", "file.pdf");
|
||||
expect(url).toMatch(/^\/download\//);
|
||||
});
|
||||
|
||||
it("embeds a verifiable token in the URL", () => {
|
||||
const path = "documents/user/file.pdf";
|
||||
const filename = "file.pdf";
|
||||
const url = buildDownloadUrl(path, filename);
|
||||
const token = url.replace("/download/", "");
|
||||
const result = verifyDownload(token);
|
||||
expect(result).not.toBeNull();
|
||||
expect(result!.path).toBe(path);
|
||||
expect(result!.filename).toBe(filename);
|
||||
});
|
||||
});
|
||||
|
|
@ -16,5 +16,5 @@
|
|||
}
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
"exclude": ["node_modules", "dist", "src/**/*.test.ts", "src/**/__tests__/**"]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue