import { decode as base64url } from '../../runtime/base64url.js'; import verify from '../../runtime/verify.js'; import { JOSEAlgNotAllowed, JWSInvalid, JWSSignatureVerificationFailed } from '../../util/errors.js'; import { concat, encoder, decoder } from '../../lib/buffer_utils.js'; import isDisjoint from '../../lib/is_disjoint.js'; import isObject from '../../lib/is_object.js'; import checkKeyType from '../../lib/check_key_type.js'; import validateCrit from '../../lib/validate_crit.js'; import validateAlgorithms from '../../lib/validate_algorithms.js'; export async function flattenedVerify(jws, key, options) { var _a; if (!isObject(jws)) { throw new JWSInvalid('Flattened JWS must be an object'); } if (jws.protected === undefined && jws.header === undefined) { throw new JWSInvalid('Flattened JWS must have either of the "protected" or "header" members'); } if (jws.protected !== undefined && typeof jws.protected !== 'string') { throw new JWSInvalid('JWS Protected Header incorrect type'); } if (jws.payload === undefined) { throw new JWSInvalid('JWS Payload missing'); } if (typeof jws.signature !== 'string') { throw new JWSInvalid('JWS Signature missing or incorrect type'); } if (jws.header !== undefined && !isObject(jws.header)) { throw new JWSInvalid('JWS Unprotected Header incorrect type'); } let parsedProt = {}; if (jws.protected) { try { const protectedHeader = base64url(jws.protected); parsedProt = JSON.parse(decoder.decode(protectedHeader)); } catch (_b) { throw new JWSInvalid('JWS Protected Header is invalid'); } } if (!isDisjoint(parsedProt, jws.header)) { throw new JWSInvalid('JWS Protected and JWS Unprotected Header Parameter names must be disjoint'); } const joseHeader = { ...parsedProt, ...jws.header, }; const extensions = validateCrit(JWSInvalid, new Map([['b64', true]]), options === null || options === void 0 ? void 0 : options.crit, parsedProt, joseHeader); let b64 = true; if (extensions.has('b64')) { b64 = parsedProt.b64; if (typeof b64 !== 'boolean') { throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean'); } } const { alg } = joseHeader; if (typeof alg !== 'string' || !alg) { throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid'); } const algorithms = options && validateAlgorithms('algorithms', options.algorithms); if (algorithms && !algorithms.has(alg)) { throw new JOSEAlgNotAllowed('"alg" (Algorithm) Header Parameter not allowed'); } if (b64) { if (typeof jws.payload !== 'string') { throw new JWSInvalid('JWS Payload must be a string'); } } else if (typeof jws.payload !== 'string' && !(jws.payload instanceof Uint8Array)) { throw new JWSInvalid('JWS Payload must be a string or an Uint8Array instance'); } let resolvedKey = false; if (typeof key === 'function') { key = await key(parsedProt, jws); resolvedKey = true; } checkKeyType(alg, key, 'verify'); const data = concat(encoder.encode((_a = jws.protected) !== null && _a !== void 0 ? _a : ''), encoder.encode('.'), typeof jws.payload === 'string' ? encoder.encode(jws.payload) : jws.payload); let signature; try { signature = base64url(jws.signature); } catch (_c) { throw new JWSInvalid('Failed to base64url decode the signature'); } const verified = await verify(alg, key, signature, data); if (!verified) { throw new JWSSignatureVerificationFailed(); } let payload; if (b64) { try { payload = base64url(jws.payload); } catch (_d) { throw new JWSInvalid('Failed to base64url decode the payload'); } } else if (typeof jws.payload === 'string') { payload = encoder.encode(jws.payload); } else { payload = jws.payload; } const result = { payload }; if (jws.protected !== undefined) { result.protectedHeader = parsedProt; } if (jws.header !== undefined) { result.unprotectedHeader = jws.header; } if (resolvedKey) { return { ...result, key }; } return result; }