import { describe, it, expect, vi, afterEach } from 'vitest' import { createJwt, verifyJwt, blacklistJwt } from './jwt.js' describe('JWT', () => { afterEach(() => { vi.useRealTimers() }) it('creates a valid JWT that can be verified', () => { const token = createJwt('abc123pubkey', 'bot-1') const payload = verifyJwt(token) expect(payload).not.toBeNull() expect(payload!.sub).toBe('abc123pubkey') expect(payload!.botId).toBe('bot-1') expect(payload!.iat).toBeDefined() expect(payload!.exp).toBeGreaterThan(payload!.iat) }) it('creates JWT without botId', () => { const token = createJwt('pubkey-only') const payload = verifyJwt(token) expect(payload).not.toBeNull() expect(payload!.sub).toBe('pubkey-only') expect(payload!.botId).toBeUndefined() }) it('rejects expired JWT', () => { vi.useFakeTimers() const token = createJwt('pubkey-expire') // Advance time past 24h expiry vi.advanceTimersByTime(25 * 60 * 60 * 1000) const payload = verifyJwt(token) expect(payload).toBeNull() }) it('rejects tampered payload', () => { const token = createJwt('original-pubkey') const parts = token.split('.') // Tamper with payload — change the pubkey const tampered = Buffer.from(JSON.stringify({ sub: 'hacker-pubkey', iat: Math.floor(Date.now() / 1000), exp: Math.floor(Date.now() / 1000) + 86400, })).toString('base64url') const tamperedToken = `${parts[0]}.${tampered}.${parts[2]}` const payload = verifyJwt(tamperedToken) expect(payload).toBeNull() }) it('rejects tampered signature', () => { const token = createJwt('pubkey-sig-test') const parts = token.split('.') const badSig = parts[2].split('').reverse().join('') const tamperedToken = `${parts[0]}.${parts[1]}.${badSig}` const payload = verifyJwt(tamperedToken) expect(payload).toBeNull() }) it('rejects malformed tokens', () => { expect(verifyJwt('')).toBeNull() expect(verifyJwt('not-a-jwt')).toBeNull() expect(verifyJwt('a.b')).toBeNull() expect(verifyJwt('a.b.c.d')).toBeNull() }) it('rejects blacklisted JWT (logout)', () => { const token = createJwt('pubkey-logout', 'bot-logout') // Token works before blacklisting expect(verifyJwt(token)).not.toBeNull() // Blacklist the token blacklistJwt(token) // Token is now rejected expect(verifyJwt(token)).toBeNull() }) })