75 lines
3.4 KiB
TypeScript
75 lines
3.4 KiB
TypeScript
import { describe, expect, test } from "vitest";
|
|
import { createWindowsAuthStorageBridge } from "../src/auth/windows-auth-storage.js";
|
|
|
|
const root = "C:\\ProgramData\\ThothII\\auth";
|
|
const filename = "a".repeat(64) + ".json";
|
|
|
|
describe("Windows auth-storage bridge", () => {
|
|
test("uses hidden tht argv and sends record bytes only over bounded stdin", async () => {
|
|
const calls: Array<{ executable: string; args: readonly string[]; input: Buffer; timeoutMs: number }> = [];
|
|
const bridge = createWindowsAuthStorageBridge({
|
|
thtExecutable: "C:\\Program Files\\ThothII\\tht.exe",
|
|
invoke: async (call) => {
|
|
calls.push(call);
|
|
return { code: 0, stdout: Buffer.from('{"version":1,"ok":true,"created":true}\n'), stderr: Buffer.alloc(0) };
|
|
},
|
|
});
|
|
|
|
await expect(bridge.create(root, "sessions", filename, Buffer.from('{"subject":"record-data"}'))).resolves.toBe(true);
|
|
expect(calls).toHaveLength(1);
|
|
expect(calls[0]).toMatchObject({
|
|
executable: "C:\\Program Files\\ThothII\\tht.exe",
|
|
args: ["_auth-storage"],
|
|
});
|
|
expect(JSON.stringify(calls[0].args)).not.toContain("record-data");
|
|
expect(JSON.parse(calls[0].input.toString("utf8"))).toMatchObject({
|
|
version: 1,
|
|
operation: "create",
|
|
root,
|
|
directory: "sessions",
|
|
filename,
|
|
contentBase64: Buffer.from('{"subject":"record-data"}').toString("base64"),
|
|
});
|
|
expect(calls[0].timeoutMs).toBeGreaterThan(0);
|
|
});
|
|
|
|
test.each([
|
|
{ label: "nonzero", result: { code: 1, stdout: Buffer.from('{"version":1,"ok":true}\n'), stderr: Buffer.from("secret") } },
|
|
{ label: "malformed stdout", result: { code: 0, stdout: Buffer.from("not-json"), stderr: Buffer.alloc(0) } },
|
|
{ label: "unexpected stdout", result: { code: 0, stdout: Buffer.from('{"version":1,"ok":true}\nextra'), stderr: Buffer.alloc(0) } },
|
|
{ label: "unexpected JSON field", result: { code: 0, stdout: Buffer.from('{"version":1,"ok":true,"created":true,"detail":"secret"}\n'), stderr: Buffer.alloc(0) } },
|
|
])("fails closed on $label bridge output", async ({ result }) => {
|
|
const bridge = createWindowsAuthStorageBridge({
|
|
thtExecutable: "C:\\tht.exe",
|
|
invoke: async () => result,
|
|
});
|
|
|
|
await expect(bridge.create(root, "sessions", filename, Buffer.from("record")))
|
|
.rejects.toThrow("auth_session_store_invalid");
|
|
});
|
|
|
|
test("fails closed on a bridge timeout without disclosing request content", async () => {
|
|
const bridge = createWindowsAuthStorageBridge({
|
|
thtExecutable: "C:\\tht.exe",
|
|
invoke: async () => { throw new Error("timeout secret-record"); },
|
|
});
|
|
|
|
await expect(bridge.create(root, "sessions", filename, Buffer.from("secret-record")))
|
|
.rejects.toThrow("auth_session_store_invalid");
|
|
});
|
|
|
|
test("rejects a claimed-read response without bounded record bytes", async () => {
|
|
const bridge = createWindowsAuthStorageBridge({
|
|
thtExecutable: "C:\\tht.exe",
|
|
invoke: async () => ({ code: 0, stdout: Buffer.from('{"version":1,"ok":true,"found":true}\n'), stderr: Buffer.alloc(0) }),
|
|
});
|
|
|
|
await expect(bridge.readClaim(root, filename)).rejects.toThrow("auth_session_store_invalid");
|
|
});
|
|
|
|
test("rejects an executable value that would require shell parsing", () => {
|
|
expect(() => createWindowsAuthStorageBridge({ thtExecutable: "tht.exe && unexpected" }))
|
|
.toThrow("auth_session_store_invalid");
|
|
});
|
|
});
|