import { describe, expect, it } from 'vitest'; import type { CollabTokenClaims } from './collab-token'; import { signCollabToken, verifyCollabToken } from './token-crypto'; const secret = 'test-secret-at-least-16-chars-long'; const claims: CollabTokenClaims = { userId: 'user-1', pageId: 'page-1', mode: 'rw' }; describe('collab token', () => { it('round-trips valid claims', () => { const token = signCollabToken(claims, secret, 60); const result = verifyCollabToken(token, secret); expect(result).toEqual({ valid: true, claims }); }); it('rejects a token signed with a different secret', () => { const token = signCollabToken(claims, secret, 60); expect(verifyCollabToken(token, 'another-secret-16-chars')).toEqual({ valid: false, reason: 'bad_signature', }); }); it('rejects a tampered payload', () => { const token = signCollabToken(claims, secret, 60); const [header, , signature] = token.split('.'); const forgedPayload = Buffer.from( JSON.stringify({ ...claims, mode: 'rw', iat: 0, exp: 9999999999 }), 'utf8', ).toString('base64url'); const forged = `${header}.${forgedPayload}.${signature}`; expect(verifyCollabToken(forged, secret).valid).toBe(false); }); it('rejects an expired token', () => { const token = signCollabToken(claims, secret, 60); // 61 seconds later the 60 s token is past its expiry. const later = Date.now() + 61_000; expect(verifyCollabToken(token, secret, later)).toEqual({ valid: false, reason: 'expired' }); }); it('rejects a malformed token', () => { expect(verifyCollabToken('not-a-jwt', secret)).toEqual({ valid: false, reason: 'malformed' }); expect(verifyCollabToken('a.b', secret).valid).toBe(false); }); it('rejects an alg:none token even if the signature check is bypassed', () => { // Craft a header advertising `none` and an empty signature; the empty // signature cannot match a real HMAC, so this is caught as bad_signature, // but the algorithm guard is the intended second line of defense. const header = Buffer.from(JSON.stringify({ alg: 'none', typ: 'JWT' })).toString('base64url'); const payload = Buffer.from(JSON.stringify({ ...claims, iat: 0, exp: 9999999999 })).toString( 'base64url', ); const result = verifyCollabToken(`${header}.${payload}.`, secret); expect(result.valid).toBe(false); }); it('preserves the read-only mode claim', () => { const roToken = signCollabToken({ ...claims, mode: 'ro' }, secret, 60); const result = verifyCollabToken(roToken, secret); expect(result).toEqual({ valid: true, claims: { ...claims, mode: 'ro' } }); }); });