65 行
2.8 KiB
TypeScript
65 行
2.8 KiB
TypeScript
|
|
import assert from 'node:assert/strict'
|
||
|
|
import test from 'node:test'
|
||
|
|
import { decodeBase64, encodeBase64 } from '../security/base64.js'
|
||
|
|
import { canonicalJson } from '../security/canonical-json.js'
|
||
|
|
|
||
|
|
test('strict Base64 decoder supports padded, unpadded and URL-safe inputs without atob', () => {
|
||
|
|
assert.deepEqual([...decodeBase64('TQ==')], [77])
|
||
|
|
assert.deepEqual([...decodeBase64('TWE=')], [77, 97])
|
||
|
|
assert.deepEqual([...decodeBase64('TWFu')], [77, 97, 110])
|
||
|
|
assert.deepEqual([...decodeBase64('AQIDBA==')], [1, 2, 3, 4])
|
||
|
|
assert.deepEqual([...decodeBase64('AQIDBA')], [1, 2, 3, 4])
|
||
|
|
assert.deepEqual([...decodeBase64('-_8=')], [251, 255])
|
||
|
|
})
|
||
|
|
|
||
|
|
test('strict Base64 decoder rejects invalid alphabets, lengths, padding and trailing bits', () => {
|
||
|
|
for (const value of [
|
||
|
|
'A',
|
||
|
|
'A+_-',
|
||
|
|
'AA=A',
|
||
|
|
'AA===',
|
||
|
|
'AAA==',
|
||
|
|
'TQ=',
|
||
|
|
'TWE==',
|
||
|
|
'TQ===',
|
||
|
|
'TQ==AA',
|
||
|
|
'TR==',
|
||
|
|
'TWF=',
|
||
|
|
'AA!A',
|
||
|
|
]) {
|
||
|
|
assert.throws(() => decodeBase64(value), /Base64/)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
test('pure JS Base64 encoder emits canonical standard and URL-safe forms', () => {
|
||
|
|
assert.equal(encodeBase64(new Uint8Array()), '')
|
||
|
|
assert.equal(encodeBase64(Uint8Array.of(77)), 'TQ==')
|
||
|
|
assert.equal(encodeBase64(Uint8Array.of(77, 97)), 'TWE=')
|
||
|
|
assert.equal(encodeBase64(Uint8Array.of(77, 97, 110)), 'TWFu')
|
||
|
|
assert.equal(encodeBase64(Uint8Array.of(251, 255), { urlSafe: true }), '-_8=')
|
||
|
|
assert.equal(encodeBase64(Uint8Array.of(251, 255), { urlSafe: true, padding: false }), '-_8')
|
||
|
|
assert.throws(() => encodeBase64([1, 2, 3] as unknown as Uint8Array), /Uint8Array/)
|
||
|
|
})
|
||
|
|
|
||
|
|
test('Base64 codec round-trips chunk boundaries and matches the Node reference', () => {
|
||
|
|
for (const length of [0, 1, 2, 3, 4, 31, 32, 33, 255, 256, 257]) {
|
||
|
|
const input = Uint8Array.from({ length }, (_, index) => (index * 197 + 31) & 0xff)
|
||
|
|
const standard = encodeBase64(input)
|
||
|
|
const urlSafe = encodeBase64(input, { urlSafe: true, padding: false })
|
||
|
|
assert.equal(standard, Buffer.from(input).toString('base64'))
|
||
|
|
assert.equal(urlSafe, Buffer.from(input).toString('base64url'))
|
||
|
|
assert.deepEqual(decodeBase64(standard), input)
|
||
|
|
assert.deepEqual(decodeBase64(urlSafe), input)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
test('canonical JSON rejects values that have no cross-runtime protocol representation', () => {
|
||
|
|
assert.throws(() => canonicalJson(Number.NaN), /finite numbers/)
|
||
|
|
assert.throws(() => canonicalJson(Number.POSITIVE_INFINITY), /finite numbers/)
|
||
|
|
assert.throws(() => canonicalJson(() => undefined), /does not support function/)
|
||
|
|
assert.throws(() => canonicalJson(Symbol('value')), /does not support symbol/)
|
||
|
|
assert.throws(() => canonicalJson([undefined]), /cannot contain holes or undefined/)
|
||
|
|
assert.throws(() => canonicalJson(new Array(1)), /cannot contain holes or undefined/)
|
||
|
|
assert.throws(() => canonicalJson(new Date(0)), /only supports plain objects/)
|
||
|
|
})
|