import { describe, it, expect } from 'vitest' import { generateMobileSecret, generateDesktopToken, hashToken, verifyToken, isPairedSessionExpired, } from '@/lib/auth/pairing' describe('lib/auth/pairing', () => { describe('generateMobileSecret / generateDesktopToken', () => { it('produceert 43-karakter base64url (32 bytes)', () => { // 32 bytes → ceil(32/3) * 4 = 44 chars zonder padding → 43 chars in base64url (geen '=') expect(generateMobileSecret()).toMatch(/^[A-Za-z0-9_-]{43}$/) expect(generateDesktopToken()).toMatch(/^[A-Za-z0-9_-]{43}$/) }) it('twee opeenvolgende calls leveren verschillende waardes', () => { const a = generateMobileSecret() const b = generateMobileSecret() expect(a).not.toBe(b) }) it('mobile en desktop generators delen geen state — paren zijn onafhankelijk', () => { const m1 = generateMobileSecret() const d1 = generateDesktopToken() const m2 = generateMobileSecret() const d2 = generateDesktopToken() expect(new Set([m1, d1, m2, d2]).size).toBe(4) }) }) describe('hashToken', () => { it('is deterministisch — zelfde input → zelfde hash', () => { const t = 'voorbeeld-token' expect(hashToken(t)).toBe(hashToken(t)) }) it('produceert 64-karakter hex (sha256)', () => { expect(hashToken('x')).toMatch(/^[a-f0-9]{64}$/) }) it('verschillende inputs → verschillende hashes', () => { expect(hashToken('a')).not.toBe(hashToken('b')) }) }) describe('verifyToken', () => { it('true voor geldig (token, hashOf(token))', () => { const token = generateMobileSecret() expect(verifyToken(token, hashToken(token))).toBe(true) }) it('false voor onjuist token', () => { const realHash = hashToken('echt-token') expect(verifyToken('verkeerd-token', realHash)).toBe(false) }) it('false bij hash met afwijkende lengte', () => { expect(verifyToken('iets', 'abc')).toBe(false) }) it('false bij lege hash', () => { expect(verifyToken('iets', '')).toBe(false) }) }) describe('isPairedSessionExpired', () => { it('false als paired niet gezet is (reguliere wachtwoord-sessie)', () => { expect(isPairedSessionExpired({})).toBe(false) }) it('false als pairedExpiresAt ontbreekt', () => { expect(isPairedSessionExpired({ paired: true })).toBe(false) }) it('false als de paired-sessie nog niet vervallen is', () => { const future = Date.now() + 60_000 expect(isPairedSessionExpired({ paired: true, pairedExpiresAt: future })).toBe(false) }) it('true als paired én vervaltijd in het verleden ligt', () => { const past = Date.now() - 1_000 expect(isPairedSessionExpired({ paired: true, pairedExpiresAt: past })).toBe(true) }) }) })