Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol. wisp.place
at main 3.8 kB view raw
1import { describe, test, expect } from 'bun:test' 2import { verifyRequestOrigin } from './csrf' 3 4describe('verifyRequestOrigin', () => { 5 test('should accept matching origin and host', () => { 6 expect(verifyRequestOrigin('https://example.com', ['example.com'])).toBe(true) 7 expect(verifyRequestOrigin('http://localhost:8000', ['localhost:8000'])).toBe(true) 8 expect(verifyRequestOrigin('https://app.example.com', ['app.example.com'])).toBe(true) 9 }) 10 11 test('should accept origin matching one of multiple allowed hosts', () => { 12 const allowedHosts = ['example.com', 'app.example.com', 'localhost:8000'] 13 expect(verifyRequestOrigin('https://example.com', allowedHosts)).toBe(true) 14 expect(verifyRequestOrigin('https://app.example.com', allowedHosts)).toBe(true) 15 expect(verifyRequestOrigin('http://localhost:8000', allowedHosts)).toBe(true) 16 }) 17 18 test('should reject non-matching origin', () => { 19 expect(verifyRequestOrigin('https://evil.com', ['example.com'])).toBe(false) 20 expect(verifyRequestOrigin('https://fake-example.com', ['example.com'])).toBe(false) 21 expect(verifyRequestOrigin('https://example.com.evil.com', ['example.com'])).toBe(false) 22 }) 23 24 test('should reject empty origin', () => { 25 expect(verifyRequestOrigin('', ['example.com'])).toBe(false) 26 }) 27 28 test('should reject invalid URL format', () => { 29 expect(verifyRequestOrigin('not-a-url', ['example.com'])).toBe(false) 30 expect(verifyRequestOrigin('javascript:alert(1)', ['example.com'])).toBe(false) 31 expect(verifyRequestOrigin('file:///etc/passwd', ['example.com'])).toBe(false) 32 }) 33 34 test('should handle different protocols correctly', () => { 35 // Same host, different protocols should match (we only check host) 36 expect(verifyRequestOrigin('http://example.com', ['example.com'])).toBe(true) 37 expect(verifyRequestOrigin('https://example.com', ['example.com'])).toBe(true) 38 }) 39 40 test('should handle port numbers correctly', () => { 41 expect(verifyRequestOrigin('http://localhost:3000', ['localhost:3000'])).toBe(true) 42 expect(verifyRequestOrigin('http://localhost:3000', ['localhost:8000'])).toBe(false) 43 expect(verifyRequestOrigin('http://localhost', ['localhost'])).toBe(true) 44 }) 45 46 test('should handle subdomains correctly', () => { 47 expect(verifyRequestOrigin('https://sub.example.com', ['sub.example.com'])).toBe(true) 48 expect(verifyRequestOrigin('https://sub.example.com', ['example.com'])).toBe(false) 49 }) 50 51 test('should handle case sensitivity (exact match required)', () => { 52 // URL host is automatically lowercased by URL parser 53 expect(verifyRequestOrigin('https://EXAMPLE.COM', ['example.com'])).toBe(true) 54 expect(verifyRequestOrigin('https://example.com', ['example.com'])).toBe(true) 55 // But allowed hosts are case-sensitive 56 expect(verifyRequestOrigin('https://example.com', ['EXAMPLE.COM'])).toBe(false) 57 }) 58 59 test('should handle trailing slashes in origin', () => { 60 expect(verifyRequestOrigin('https://example.com/', ['example.com'])).toBe(true) 61 }) 62 63 test('should handle paths in origin (host extraction)', () => { 64 expect(verifyRequestOrigin('https://example.com/path/to/page', ['example.com'])).toBe(true) 65 expect(verifyRequestOrigin('https://evil.com/example.com', ['example.com'])).toBe(false) 66 }) 67 68 test('should reject when allowed hosts is empty', () => { 69 expect(verifyRequestOrigin('https://example.com', [])).toBe(false) 70 }) 71 72 test('should handle IPv4 addresses', () => { 73 expect(verifyRequestOrigin('http://127.0.0.1:8000', ['127.0.0.1:8000'])).toBe(true) 74 expect(verifyRequestOrigin('http://192.168.1.1', ['192.168.1.1'])).toBe(true) 75 }) 76 77 test('should handle IPv6 addresses', () => { 78 expect(verifyRequestOrigin('http://[::1]:8000', ['[::1]:8000'])).toBe(true) 79 expect(verifyRequestOrigin('http://[2001:db8::1]', ['[2001:db8::1]'])).toBe(true) 80 }) 81})