import { describe, expect, test } from "bun:test"; import { assertSafeObject, createTrustedHtml, isPrivateAddress, isTrustedHtml, secureJsonStringify, secureCookieOptions, setSecureCookie, unwrapTrustedHtml, validateUrl, } from "../src/index.ts"; describe("@wrnexus/security", () => { test("escapes HTML-significant JSON and redacts secrets", () => { const json = secureJsonStringify({ html: "", token: "secret", count: 1 }); expect(json).toContain("\\u003c/script\\u003e"); expect(json).toContain("[REDACTED]"); expect(json).not.toContain("secret"); }); test("rejects prototype-pollution keys and unsafe URL protocols", () => { const unsafe = JSON.parse('{"__proto__":{"admin":true}}'); expect(() => assertSafeObject(unsafe)).toThrow(); expect(() => validateUrl("javascript:alert(1)")).toThrow(); }); test("identifies private IP ranges", () => { expect(isPrivateAddress("127.0.0.1")).toBe(true); expect(isPrivateAddress("10.1.2.3")).toBe(true); expect(isPrivateAddress("8.8.8.8")).toBe(false); }); test("enforces __Host cookie rules", () => { const writes: unknown[] = []; const ctx = { url: new URL("https://example.com"), cookies: { set: (...args: unknown[]) => writes.push(args) }, } as any; setSecureCookie(ctx, "__Host-session", "value"); expect(writes).toHaveLength(1); expect(writes[0]).toEqual([ "__Host-session", "value", expect.objectContaining({ secure: true, httpOnly: true, path: "/", domain: undefined }), ]); }); test("defaults a cookie's Path to / when the caller omits one", () => { // setSecureCookie always forwards a `path` key, so an omitted path arrives // as `path: undefined`. If that lands after the default in the returned // object it wins, and the cookie ships with NO Path -- which the browser // then scopes to the request's directory, so a cookie set from // /api/oauth/google is never sent to /api/oauth/google/callback. const writes: unknown[][] = []; const ctx = { url: new URL("https://example.com"), cookies: { set: (...args: unknown[]) => writes.push(args) }, } as any; setSecureCookie(ctx, "oauth_state", "abc", { sameSite: "Lax", maxAge: 600 }); expect(writes).toHaveLength(1); expect((writes[0]![2] as { path?: string }).path).toBe("/"); }); test("keeps an explicitly requested cookie path", () => { const writes: unknown[][] = []; const ctx = { url: new URL("https://example.com"), cookies: { set: (...args: unknown[]) => writes.push(args) }, } as any; setSecureCookie(ctx, "scoped", "abc", { path: "/admin" }); expect((writes[0]![2] as { path?: string }).path).toBe("/admin"); }); test("secureCookieOptions defaults Path even when handed an explicit undefined", () => { const options = secureCookieOptions({ url: new URL("https://example.com") } as any, { path: undefined, }); expect(options.path).toBe("/"); }); test("accepts repeated references while still rejecting cycles", () => { const shared = { value: 1 }; expect(() => assertSafeObject({ first: shared, second: shared })).not.toThrow(); const cyclic: Record = {}; cyclic.self = cyclic; expect(() => assertSafeObject(cyclic)).toThrow(); }); test("trusted HTML requires an explicit sanitizer policy", () => { const value = createTrustedHtml('

Hello

', { name: "test-policy", sanitize: (input) => input.replace(/\s+onclick="[^"]*"/g, ""), }); expect(isTrustedHtml(value)).toBe(true); expect(unwrapTrustedHtml(value)).toBe("

Hello

"); expect(() => unwrapTrustedHtml({ value: "unsafe" } as any)).toThrow(); }); });