馃 distributed transcription service thistle.dunkirk.sh
1import { test, expect } from "bun:test"; 2import db from "../db/schema"; 3import { 4 createUser, 5 createEmailChangeToken, 6 verifyEmailChangeToken, 7 consumeEmailChangeToken, 8 updateUserEmail, 9 getUserByEmail, 10} from "./auth"; 11 12test("email change token lifecycle", async () => { 13 // Create a test user with unique email 14 const timestamp = Date.now(); 15 const user = await createUser(`test-email-change-${timestamp}@example.com`, "password123", "Test User"); 16 17 // Create an email change token 18 const newEmail = `new-email-${timestamp}@example.com`; 19 const token = createEmailChangeToken(user.id, newEmail); 20 21 expect(token).toBeTruthy(); 22 expect(token.length).toBeGreaterThan(0); 23 24 // Verify the token 25 const result = verifyEmailChangeToken(token); 26 expect(result).toBeTruthy(); 27 expect(result?.userId).toBe(user.id); 28 expect(result?.newEmail).toBe(newEmail); 29 30 // Update the email 31 updateUserEmail(result!.userId, result!.newEmail); 32 33 // Consume the token 34 consumeEmailChangeToken(token); 35 36 // Verify the email was updated 37 const updatedUser = getUserByEmail(newEmail); 38 expect(updatedUser).toBeTruthy(); 39 expect(updatedUser?.id).toBe(user.id); 40 expect(updatedUser?.email).toBe(newEmail); 41 42 // Verify the token can't be used again 43 const result2 = verifyEmailChangeToken(token); 44 expect(result2).toBeNull(); 45 46 // Clean up 47 db.run("DELETE FROM users WHERE id = ?", [user.id]); 48}); 49 50test("email change token expires", async () => { 51 // Create a test user with unique email 52 const timestamp = Date.now(); 53 const user = await createUser(`test-expire-${timestamp}@example.com`, "password123", "Test User"); 54 55 // Create an email change token 56 const newEmail = `new-expire-${timestamp}@example.com`; 57 const token = createEmailChangeToken(user.id, newEmail); 58 59 // Manually expire the token 60 db.run("UPDATE email_change_tokens SET expires_at = ? WHERE token = ?", [ 61 Math.floor(Date.now() / 1000) - 1, 62 token, 63 ]); 64 65 // Verify the token is expired 66 const result = verifyEmailChangeToken(token); 67 expect(result).toBeNull(); 68 69 // Clean up 70 db.run("DELETE FROM users WHERE id = ?", [user.id]); 71}); 72 73test("only one email change token per user", async () => { 74 // Create a test user with unique email 75 const timestamp = Date.now(); 76 const user = await createUser(`test-single-token-${timestamp}@example.com`, "password123", "Test User"); 77 78 // Create first token 79 const token1 = createEmailChangeToken(user.id, `email1-${timestamp}@example.com`); 80 81 // Create second token (should delete first) 82 const token2 = createEmailChangeToken(user.id, `email2-${timestamp}@example.com`); 83 84 // First token should be invalid 85 const result1 = verifyEmailChangeToken(token1); 86 expect(result1).toBeNull(); 87 88 // Second token should work 89 const result2 = verifyEmailChangeToken(token2); 90 expect(result2).toBeTruthy(); 91 expect(result2?.newEmail).toBe(`email2-${timestamp}@example.com`); 92 93 // Clean up 94 db.run("DELETE FROM users WHERE id = ?", [user.id]); 95 db.run("DELETE FROM email_change_tokens WHERE user_id = ?", [user.id]); 96});