馃 distributed transcription service thistle.dunkirk.sh
1import { expect, test } from "bun:test"; 2import db from "../db/schema"; 3import { 4 createSession, 5 deleteSession, 6 getSession, 7 getSessionFromRequest, 8} from "./auth"; 9 10test("createSession generates UUID and stores in database", () => { 11 const userId = 1; 12 const ipAddress = "192.168.1.1"; 13 const userAgent = "Mozilla/5.0"; 14 15 const sessionId = createSession(userId, ipAddress, userAgent); 16 17 // UUID format 18 expect(sessionId).toMatch( 19 /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/, 20 ); 21 22 // Verify stored in database 23 const session = getSession(sessionId); 24 expect(session).not.toBeNull(); 25 expect(session?.user_id).toBe(userId); 26 expect(session?.ip_address).toBe(ipAddress); 27 expect(session?.user_agent).toBe(userAgent); 28 29 // Cleanup 30 deleteSession(sessionId); 31}); 32 33test("getSession returns null for expired session", () => { 34 const userId = 1; 35 const sessionId = createSession(userId); 36 37 // Manually set expiration to past 38 db.run("UPDATE sessions SET expires_at = ? WHERE id = ?", [ 39 Math.floor(Date.now() / 1000) - 1000, 40 sessionId, 41 ]); 42 43 const session = getSession(sessionId); 44 expect(session).toBeNull(); 45 46 // Cleanup 47 deleteSession(sessionId); 48}); 49 50test("getSession returns null for non-existent session", () => { 51 const session = getSession("non-existent-session-id"); 52 expect(session).toBeNull(); 53}); 54 55test("deleteSession removes session from database", () => { 56 const userId = 1; 57 const sessionId = createSession(userId); 58 59 const sessionBefore = getSession(sessionId); 60 expect(sessionBefore).not.toBeNull(); 61 62 deleteSession(sessionId); 63 64 const sessionAfter = getSession(sessionId); 65 expect(sessionAfter).toBeNull(); 66}); 67 68test("getSessionFromRequest extracts session from cookie", () => { 69 const sessionId = "test-session-id"; 70 const req = new Request("http://localhost", { 71 headers: { 72 cookie: `session=${sessionId}; other=value`, 73 }, 74 }); 75 76 const extracted = getSessionFromRequest(req); 77 expect(extracted).toBe(sessionId); 78}); 79 80test("getSessionFromRequest returns null when no cookie", () => { 81 const req = new Request("http://localhost"); 82 83 const extracted = getSessionFromRequest(req); 84 expect(extracted).toBeNull(); 85}); 86 87test("getSessionFromRequest returns null when session cookie missing", () => { 88 const req = new Request("http://localhost", { 89 headers: { 90 cookie: "other=value; foo=bar", 91 }, 92 }); 93 94 const extracted = getSessionFromRequest(req); 95 expect(extracted).toBeNull(); 96}); 97 98test("prevents directory traversal in session IDs", () => { 99 const maliciousIds = [ 100 "../../../etc/passwd", 101 "..\\..\\..\\windows\\system32", 102 "test/../../../secret", 103 "/etc/passwd", 104 "C:\\Windows\\System32", 105 ]; 106 107 for (const id of maliciousIds) { 108 const session = getSession(id); 109 expect(session).toBeNull(); 110 } 111}); 112 113test("prevents SQL injection in session lookup", () => { 114 const maliciousIds = [ 115 "' OR '1'='1", 116 "'; DROP TABLE sessions; --", 117 "1' UNION SELECT * FROM users --", 118 "test' OR 1=1 --", 119 ]; 120 121 for (const id of maliciousIds) { 122 // Should not throw or return unexpected data 123 const session = getSession(id); 124 expect(session).toBeNull(); 125 } 126 127 // Verify sessions table still exists 128 const result = db.query("SELECT COUNT(*) as count FROM sessions").get() as { 129 count: number; 130 }; 131 expect(typeof result.count).toBe("number"); 132});