50 lines
1.7 KiB
TypeScript
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);
|
|
});
|
|
});
|