Files
Clintchiz 2c960fc1dc
Quality / quality (ubuntu-latest) (push) Failing after 9m49s
Quality / quality (windows-latest) (push) Canceled after 0s
refactor: migrate legacy wire namespace to wrn
2026-08-12 18:51:15 +05:30

120 lines
4.1 KiB
TypeScript

import { expect, test } from "bun:test";
import type { Context } from "@wrnexus/core";
import { createAuthEngine } from "../src/engine.ts";
import { setDefaultAuthEngine } from "../src/runtime.ts";
import { MemoryAuthStore } from "../src/stores/memory.ts";
import { POST as requestPasswordReset } from "../src/routes/api/password-request.ts";
import { GET as listSessions } from "../src/routes/api/sessions.ts";
import { POST as passkeyLoginOptions } from "../src/routes/api/passkeys-login-options.ts";
function context(request: Request): Context {
const values = new Map<string, unknown>();
return {
req: request,
// Deliberately use unrelated values. A route-specific package entry must
// not infer its endpoint from ctx.url, ctx.req.url, params, or locals.
url: new URL("https://example.test/__wrnexus/rewritten"),
params: {},
locals: {},
lang: "en",
t: (key: string) => key,
ip: "127.0.0.1",
user: null,
cookies: {
get: (name: string) => (name === "wrn-csrf" ? "route-csrf-token" : undefined),
} as Context["cookies"],
localStorage: {} as Context["localStorage"],
session: {
id: () => "route-test-session",
get: <T>(key: string) => values.get(key) as T | undefined,
getAll: () => Object.fromEntries(values),
set: (key: string, value: unknown) => {
values.set(key, value);
},
delete: (key: string) => {
values.delete(key);
},
regenerate: () => {},
clear: () => {
values.clear();
},
},
} as Context;
}
test("route-specific password recovery entry cannot fall through to Not Found", async () => {
setDefaultAuthEngine(
createAuthEngine({
store: new MemoryAuthStore(),
secret: "route-specific-entry-secret-longer-than-thirty-two-characters",
}),
);
const request = new Request("https://example.test/completely/unrelated", {
method: "POST",
headers: {
"content-type": "application/json",
"x-csrf-token": "route-csrf-token",
},
body: JSON.stringify({ identifier: "missing@example.test" }),
});
const response = await requestPasswordReset(context(request));
expect(response.status).toBe(200);
expect(await response.json()).toEqual({ ok: true });
});
test("package auth routes reject unsafe requests without CSRF verification", async () => {
const request = new Request("https://example.test/api/auth/password/request", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ identifier: "missing@example.test" }),
});
const response = await requestPasswordReset(context(request));
expect(response.status).toBe(403);
expect(await response.json()).toMatchObject({ ok: false, error: "Invalid CSRF token" });
});
test("safe package auth routes do not require a CSRF token", async () => {
const engine = createAuthEngine({
store: new MemoryAuthStore(),
secret: "safe-route-secret-that-is-longer-than-thirty-two-characters",
});
const registered = await engine.register({
email: "sessions@example.test",
password: "StrongPassword123",
});
setDefaultAuthEngine(engine);
const ctx = context(new Request("https://example.test/api/auth/sessions", { method: "GET" }));
ctx.user = registered.user!;
ctx.locals.authUser = registered.user!;
const response = await listSessions(ctx);
expect(response.status).toBe(200);
expect(await response.json()).toMatchObject({ ok: true, sessions: [] });
});
test("passkey routes return a controlled response when no provider is configured", async () => {
setDefaultAuthEngine(
createAuthEngine({
store: new MemoryAuthStore(),
secret: "missing-passkey-provider-secret-longer-than-thirty-two-characters",
}),
);
const request = new Request("https://example.test/api/auth/passkeys/login/options", {
method: "POST",
headers: {
"content-type": "application/json",
"x-csrf-token": "route-csrf-token",
},
body: JSON.stringify({}),
});
const response = await passkeyLoginOptions(context(request));
expect(response.status).toBe(503);
expect(await response.json()).toMatchObject({
ok: false,
code: "passkey-provider-not-configured",
});
});