1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
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');
});
});
|