UNPKG

jose

Version:

JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes

75 lines (74 loc) 3.14 kB
import { JOSENotSupported, JWEInvalid, JWSInvalid } from '../util/errors.js'; import { isObject } from './type_checks.js'; export const JWS_RECOGNIZED = { __proto__: null, b64: true }; export const JWE_RECOGNIZED = { __proto__: null }; export function validateAlgorithms(option, algorithms) { if (algorithms !== undefined && (!Array.isArray(algorithms) || algorithms.some((s) => typeof s !== 'string'))) { throw new TypeError(`"${option}" option must be an array of strings`); } if (!algorithms) { return undefined; } return new Set(algorithms); } export function validateCritDuplicates(Err, protectedHeader) { const { crit } = protectedHeader ?? {}; if (Array.isArray(crit) && new Set(crit).size !== crit.length) { throw new Err('"crit" (Critical) Header Parameter MUST NOT contain duplicate values'); } } export function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) { if (joseHeader.crit !== undefined && protectedHeader?.crit === undefined) { throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected'); } if (!protectedHeader || protectedHeader.crit === undefined) { return []; } if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input !== 'string' || input.length === 0)) { throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present'); } const recognized = recognizedOption === undefined ? recognizedDefault : { __proto__: null, ...recognizedOption, ...recognizedDefault }; for (const parameter of protectedHeader.crit) { if (!(parameter in recognized)) { throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`); } if (!Object.hasOwn(joseHeader, parameter) || joseHeader[parameter] === undefined) { throw new Err(`Extension Header Parameter "${parameter}" is missing`); } if (recognized[parameter] && (!Object.hasOwn(protectedHeader, parameter) || protectedHeader[parameter] === undefined)) { throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`); } } return protectedHeader.crit; } export function validateB64(protectedHeader, extensions) { if (extensions.includes('b64')) { const b64 = protectedHeader.b64; if (typeof b64 !== 'boolean') { throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean'); } return b64; } return true; } export function serializeJoseHeader(Err, header) { let serialized; let parsed; try { serialized = JSON.stringify(header); parsed = JSON.parse(serialized); } catch (cause) { throw new Err('JOSE Header is not valid JSON', { cause }); } if (!isObject(parsed)) { throw new Err('JOSE Header is not a JSON object'); } return [parsed, serialized]; }