import { describe, expect, it } from 'bun:test' import { tokenFromRequest, tokenMatches } from './auth.ts' const TOKEN = '208ac4512b9748b9b7408ebc16ec793d' describe('令牌比较', () => { it('一模一样才算通过', () => { expect(tokenMatches(TOKEN, TOKEN)).toBe(true) }) it('差一个字符就不通过', () => { expect(tokenMatches(TOKEN, `${TOKEN.slice(0, -1)}x`)).toBe(false) }) it('前缀正确也不算通过', () => { // 逐字节比较写错时最容易漏掉的一种:只比对了开头 expect(tokenMatches(TOKEN, TOKEN.slice(0, 8))).toBe(false) }) it('更长的字符串不算通过', () => { expect(tokenMatches(TOKEN, `${TOKEN}extra`)).toBe(false) }) it('没带令牌不算通过', () => { expect(tokenMatches(TOKEN, null)).toBe(false) expect(tokenMatches(TOKEN, '')).toBe(false) }) it('比较耗时不随匹配长度变化', () => { // 这是常数时间比较存在的理由:如果先匹配的字符越多越慢,就能靠计时逐字节猜出令牌。 // 这里只验证行为上的对称——两个都不匹配的输入走的是同样多的比较。 const almost = `${TOKEN.slice(0, -1)}x` const nothing = 'x'.repeat(TOKEN.length) expect(tokenMatches(TOKEN, almost)).toBe(false) expect(tokenMatches(TOKEN, nothing)).toBe(false) }) }) describe('从请求里取令牌', () => { const req = (init?: RequestInit, url = 'http://x/api/config') => new Request(url, init) it('认 Authorization 头', () => { expect(tokenFromRequest(req({ headers: { Authorization: `Bearer ${TOKEN}` } }))).toBe(TOKEN) }) it('认查询参数,WebSocket 用得上——它没法自定义请求头', () => { expect(tokenFromRequest(req(undefined, `http://x/api/logs?token=${TOKEN}`))).toBe(TOKEN) }) it('头的格式不对时当作没带', () => { expect(tokenFromRequest(req({ headers: { Authorization: TOKEN } }))).toBeNull() expect(tokenFromRequest(req({ headers: { Authorization: `Basic ${TOKEN}` } }))).toBeNull() }) it('什么都没带时返回空', () => { expect(tokenFromRequest(req())).toBeNull() }) })