/** * test/origin.test.ts — TDD for src/http/origin.ts (T7) * * Covers ARCHITECTURE §3.3 and TECH_DOC §7 (CSWSH defence): * - whitelist hit → allow * - wrong hostname → deny * - wrong port → deny * - undefined Origin (non-browser client) → deny * - evil.com → deny */ import { describe, it, expect } from 'vitest' import { isOriginAllowed } from '../src/http/origin.js' const ALLOWED: readonly string[] = [ 'http://localhost:3000', 'http://192.168.1.42:3000', 'http://my-host.local:3000', ] describe('isOriginAllowed', () => { // ── whitelist hits ──────────────────────────────────────────────── it('allows an exact localhost origin', () => { expect(isOriginAllowed('http://localhost:3000', ALLOWED)).toBe(true) }) it('allows an exact LAN IP origin', () => { expect(isOriginAllowed('http://192.168.1.42:3000', ALLOWED)).toBe(true) }) it('allows an exact hostname.local origin', () => { expect(isOriginAllowed('http://my-host.local:3000', ALLOWED)).toBe(true) }) // ── hostname mismatch ───────────────────────────────────────────── it('rejects when the hostname does not match (evil.com)', () => { expect(isOriginAllowed('http://evil.com:3000', ALLOWED)).toBe(false) }) it('rejects a subdomain of an allowed hostname', () => { expect(isOriginAllowed('http://sub.localhost:3000', ALLOWED)).toBe(false) }) it('rejects a hostname that merely contains an allowed hostname', () => { // "evillocalhost:3000" should NOT match "localhost:3000" expect(isOriginAllowed('http://evillocalhost:3000', ALLOWED)).toBe(false) }) // ── port mismatch ───────────────────────────────────────────────── it('rejects when the port does not match (correct host, wrong port)', () => { expect(isOriginAllowed('http://localhost:9999', ALLOWED)).toBe(false) }) it('rejects when port is absent but allowed origin has a port', () => { // Browser sends Origin without port only when it is the default (80/443). // Our server runs on 3000, so no-port origins must not sneak in. expect(isOriginAllowed('http://localhost', ALLOWED)).toBe(false) }) // ── undefined Origin (non-browser clients: curl, scripts) ───────── it('rejects undefined Origin by default', () => { expect(isOriginAllowed(undefined, ALLOWED)).toBe(false) }) // ── empty / malformed origins ───────────────────────────────────── it('rejects an empty string origin', () => { expect(isOriginAllowed('', ALLOWED)).toBe(false) }) it('rejects a completely different scheme (https vs http in allowed)', () => { // Allowed list uses http://; https:// should not silently match. expect(isOriginAllowed('https://localhost:3000', ALLOWED)).toBe(false) }) it('rejects when allowed list is empty', () => { expect(isOriginAllowed('http://localhost:3000', [])).toBe(false) }) })