import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { TokenSigner } from '../src/token/index.js'; describe('TokenSigner', () => { beforeEach(() => { vi.useFakeTimers(); vi.setSystemTime(new Date('2020-01-01T00:00:00.000Z')); }); afterEach(() => { vi.useRealTimers(); }); it('generates and validates a token for the expected route', () => { const signer = new TokenSigner('test-secret', 30); const now = Date.now(); const token = signer.generate('route1'); const result = signer.validate(token, 'route1'); expect(result.left().present()).toBe(false); expect(result.right().get()).toEqual({ routeName: 'route1', timestamp: now }); }); it('rejects token when route does not match', () => { const signer = new TokenSigner('test-secret', 30); const token = signer.generate('route1'); const result = signer.validate(token, 'route2'); expect(result.left().present()).toBe(true); expect(result.left().get().message).toBe('Token route mismatch'); }); it('rejects expired tokens', () => { const signer = new TokenSigner('test-secret', 1); const token = signer.generate('route1'); vi.advanceTimersByTime(2000); const result = signer.validate(token, 'route1'); expect(result.left().present()).toBe(true); expect(result.left().get().message).toBe('Token expired'); }); it('rejects tokens with a bad signature', () => { const signer = new TokenSigner('test-secret', 30); const token = signer.generate('route1'); const decoded = Buffer.from(token, 'base64url').toString('utf-8'); const dotIndex = decoded.lastIndexOf('.'); const payload = decoded.substring(0, dotIndex); const signature = decoded.substring(dotIndex + 1); const parsed = JSON.parse(payload) as { routeName: string; timestamp: number }; const tamperedPayload = JSON.stringify({ ...parsed, routeName: 'route2' }); const tamperedToken = Buffer.from(`${tamperedPayload}.${signature}`).toString('base64url'); const result = signer.validate(tamperedToken, 'route2'); expect(result.left().present()).toBe(true); expect(result.left().get().message).toBe('Invalid token signature'); }); it('rejects invalid token format', () => { const signer = new TokenSigner('test-secret', 30); const invalidToken = Buffer.from('missing-dot').toString('base64url'); const result = signer.validate(invalidToken, 'route1'); expect(result.left().present()).toBe(true); expect(result.left().get().message).toBe('Invalid token format'); }); });