Files
spoon/apps/next/tests/unit/box-terminal-token.test.ts

50 lines
1.7 KiB
TypeScript

import { createHmac } from 'node:crypto';
import { describe, expect, it } from 'vitest';
import { buildBoxToken } from '../../src/lib/box-terminal-token';
describe('buildBoxToken', () => {
const secret = 'test-secret';
const wsBase = 'wss://worker.example.com';
const username = 'alice';
const now = 1_700_000_000_000;
it('returns null when the secret is unset', () => {
expect(buildBoxToken(username, undefined, wsBase, now)).toBeNull();
});
it('returns null when the WS base is unset', () => {
expect(buildBoxToken(username, secret, undefined, now)).toBeNull();
});
it('mints a 4-part box token matching the worker format', () => {
const result = buildBoxToken(username, secret, wsBase, now);
expect(result).not.toBeNull();
const { url, expiresAt } = result!;
expect(expiresAt).toBe(now + 2 * 60 * 1000);
const expectedHmac = createHmac('sha256', secret)
.update(`${expiresAt}.box.${username}`)
.digest('hex');
const expectedToken = `${expiresAt}.box.${username}.${expectedHmac}`;
expect(url).toContain('/box/terminal?token=');
expect(url).toBe(
`${wsBase}/box/terminal?token=${encodeURIComponent(expectedToken)}`,
);
const token = decodeURIComponent(new URL(url).searchParams.get('token')!);
expect(token).toBe(expectedToken);
const parts = token.split('.');
expect(parts).toHaveLength(4);
expect(parts[1]).toBe('box');
expect(parts[2]).toBe(username);
});
it('strips a trailing slash from the WS base', () => {
const result = buildBoxToken(username, secret, `${wsBase}/`, now);
expect(result!.url.startsWith(`${wsBase}/box/terminal?token=`)).toBe(true);
});
});