Files

135 lines
3.9 KiB
TypeScript

import type QUnit from 'qunit'
import type * as jose from '../src/index.js'
type keyType = Uint8Array | jose.CryptoKey | jose.KeyObject | jose.GenerateKeyPairResult
function isKeyPair(input: keyType): input is jose.GenerateKeyPairResult {
return 'publicKey' in input && 'privateKey' in input
}
async function getKeys(
secretOrKeyPair: keyType,
jwk: false,
keys: Pick<typeof jose, 'exportJWK' | 'generateKeyPair' | 'generateSecret' | 'importJWK'>,
): Promise<Array<Uint8Array | jose.CryptoKey | jose.KeyObject>>
async function getKeys(
secretOrKeyPair: keyType,
jwk: true,
keys: Pick<typeof jose, 'exportJWK' | 'generateKeyPair' | 'generateSecret' | 'importJWK'>,
): Promise<Array<jose.JWK>>
async function getKeys(
secretOrKeyPair: keyType,
jwk: boolean,
keys: Pick<typeof jose, 'exportJWK' | 'generateKeyPair' | 'generateSecret' | 'importJWK'>,
) {
let sKey = isKeyPair(secretOrKeyPair) ? secretOrKeyPair.privateKey : secretOrKeyPair
let vKey = isKeyPair(secretOrKeyPair) ? secretOrKeyPair.publicKey : secretOrKeyPair
if (jwk) {
// @ts-ignore
return [await keys.exportJWK(sKey), await keys.exportJWK(vKey)]
}
return [sKey, vKey]
}
function jwkWithProps(jwk: jose.JWK, alg: string) {
jwk = structuredClone(jwk)
jwk.alg = alg
jwk.use = 'sig'
if (jwk.k) {
jwk.key_ops = ['sign', 'verify']
} else if (jwk.d || jwk.priv) {
jwk.key_ops = ['sign']
} else {
jwk.key_ops = ['verify']
}
return jwk
}
export async function jws(
t: typeof QUnit.assert,
lib: typeof jose,
keys: Pick<typeof jose, 'exportJWK' | 'generateKeyPair' | 'generateSecret' | 'importJWK'>,
alg: string,
secretOrKeyPair: keyType,
payload = crypto.getRandomValues(new Uint8Array(16)),
) {
// Test Uint8Array, CryptoKey, and KeyObject key inputs
{
const [sKey, vKey] = await getKeys(secretOrKeyPair, false, keys)
const jws = await new lib.FlattenedSign(payload).setProtectedHeader({ alg }).sign(sKey)
{
const verified = await lib.flattenedVerify(jws, vKey)
t.deepEqual([...verified.payload], [...payload])
}
{
const verified = await lib.flattenedVerify(jws, async () => vKey)
t.propContains(verified, {
key: vKey,
payload,
protectedHeader: { alg },
})
}
}
if (secretOrKeyPair instanceof Uint8Array) return
// Test JWK key input
{
const [sKey, vKey] = await getKeys(secretOrKeyPair, true, keys)
const jws = await new lib.FlattenedSign(payload).setProtectedHeader({ alg }).sign(sKey)
await new lib.FlattenedSign(payload).setProtectedHeader({ alg }).sign(jwkWithProps(sKey, alg))
for (const key of [
vKey,
async () => vKey,
jwkWithProps(vKey, alg),
async () => jwkWithProps(vKey, alg),
]) {
// @ts-ignore
const verified = await lib.flattenedVerify(jws, key)
t.deepEqual([...verified.payload], [...payload])
}
}
// Test JWK key input with all JWK properties
{
const [sKey, vKey] = await getKeys(secretOrKeyPair, true, keys)
const jws = await new lib.FlattenedSign(payload)
.setProtectedHeader({ alg })
.sign(jwkWithProps(sKey, alg))
const verified = await lib.flattenedVerify(jws, {
...vKey,
alg,
use: 'sig',
key_ops: ['verify'],
})
t.deepEqual([...verified.payload], [...payload])
}
}
export async function jwt(
t: typeof QUnit.assert,
lib: typeof jose,
keys: Pick<typeof jose, 'exportJWK' | 'generateKeyPair' | 'generateSecret' | 'importJWK'>,
alg: string,
secretOrKeyPair: keyType,
) {
const [sKey, vKey] = await getKeys(secretOrKeyPair, false, keys)
const jwt = await new lib.SignJWT({ foo: 'bar', '🤷‍♂️': '🤷‍♀️' })
.setProtectedHeader({ alg, '🤷‍♂️': '🤷‍♀️' })
.sign(sKey)
const verified = await lib.jwtVerify(jwt, vKey)
t.deepEqual(verified, {
payload: {
foo: 'bar',
'🤷‍♂️': '🤷‍♀️',
},
protectedHeader: {
alg,
'🤷‍♂️': '🤷‍♀️',
},
})
}