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();
});
});