74 lines
3.7 KiB
TypeScript
74 lines
3.7 KiB
TypeScript
import { afterEach, describe, expect, it } from "vitest";
|
|
|
|
import { requireExternalApiKey } from "@/lib/external-api-auth";
|
|
|
|
// N10 (PLAN-API.md D1) — auth ของ /api/external/*: fail closed เมื่อ env ว่าง +
|
|
// ข้อความ 401 อันเดียวกันทั้งไม่ใส่ key และ key ผิด (กัน enumerate) — ไฟล์นี้
|
|
// ตั้งใจไม่แตะ module ใดที่ลาก @/db มาด้วย (db/index.ts throw ตอน import เมื่อ
|
|
// ไม่มี DATABASE_URL — vitest ไม่โหลด .env)
|
|
|
|
const HAD_KEY = Object.prototype.hasOwnProperty.call(process.env, "EXTERNAL_API_KEY");
|
|
const ORIG_KEY = process.env.EXTERNAL_API_KEY;
|
|
|
|
function restoreKey() {
|
|
if (HAD_KEY) process.env.EXTERNAL_API_KEY = ORIG_KEY;
|
|
else delete process.env.EXTERNAL_API_KEY;
|
|
}
|
|
|
|
function reqWithKey(key?: string): Request {
|
|
const headers = new Headers();
|
|
if (key !== undefined) headers.set("x-api-key", key);
|
|
return new Request("http://localhost/docedit/note/api/external/documents", { headers });
|
|
}
|
|
|
|
async function bodyOf(res: Response): Promise<{ error: string }> {
|
|
expect(res.headers.get("content-type")).toBe("application/json; charset=utf-8");
|
|
return (await res.json()) as { error: string };
|
|
}
|
|
|
|
describe("requireExternalApiKey", () => {
|
|
afterEach(restoreKey);
|
|
|
|
it("env ไม่ตั้ง / ว่าง / whitespace ล้วน = 401 fail closed (แม้จะส่ง key มาถูก)", async () => {
|
|
for (const empty of [undefined, "", " "]) {
|
|
if (empty === undefined) delete process.env.EXTERNAL_API_KEY;
|
|
else process.env.EXTERNAL_API_KEY = empty;
|
|
const res = requireExternalApiKey(reqWithKey("correct-key"));
|
|
expect(res).not.toBeNull();
|
|
expect(res!.status).toBe(401);
|
|
expect(await bodyOf(res!)).toEqual({ error: "API ยังไม่ได้ตั้งค่าคีย์" });
|
|
}
|
|
});
|
|
|
|
it("ไม่ใส่ header กับ key ผิด = 401 ข้อความ/รูปร่างเดียวกัน (ไม่บอกว่าขาดอะไร)", async () => {
|
|
process.env.EXTERNAL_API_KEY = "correct-key";
|
|
const missing = requireExternalApiKey(reqWithKey());
|
|
const wrong = requireExternalApiKey(reqWithKey("wrong-key"));
|
|
expect(missing!.status).toBe(401);
|
|
expect(wrong!.status).toBe(401);
|
|
const missingBody = await bodyOf(missing!);
|
|
const wrongBody = await bodyOf(wrong!);
|
|
expect(missingBody).toEqual(wrongBody);
|
|
expect(Object.keys(missingBody)).toEqual(["error"]);
|
|
});
|
|
|
|
it("key ถูก = ผ่าน (คืน null)", () => {
|
|
process.env.EXTERNAL_API_KEY = "correct-key";
|
|
expect(requireExternalApiKey(reqWithKey("correct-key"))).toBeNull();
|
|
});
|
|
|
|
it("env มี whitespace ครอบ (trailing newline ของ K8s secret/env_file) = เทียบด้วยค่า trim แล้ว", () => {
|
|
process.env.EXTERNAL_API_KEY = " correct-key\n";
|
|
expect(requireExternalApiKey(reqWithKey("correct-key"))).toBeNull();
|
|
expect(requireExternalApiKey(reqWithKey("wrong-key"))!.status).toBe(401);
|
|
});
|
|
|
|
it("key ยาว (300+ ตัวอักษร) เทียบตรง ๆ ได้ — ต่างแม้ตัวเดียว = 401", () => {
|
|
// header เป็น ByteString จึงทดสอบด้วย latin1 เท่านั้น (ไทย/unicode ส่งผ่าน
|
|
// header ไม่ได้ตั้งแต่ใน Headers.set แล้ว)
|
|
const key = "k".repeat(300) + "-ok";
|
|
process.env.EXTERNAL_API_KEY = key;
|
|
expect(requireExternalApiKey(reqWithKey(key))).toBeNull();
|
|
expect(requireExternalApiKey(reqWithKey(key.slice(0, -1)))!.status).toBe(401);
|
|
});
|
|
});
|