UNPKG

@gaonengwww/jose

Version:

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

241 lines (227 loc) 7.52 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/jwk/thumbprint.ts var thumbprint_exports = {}; __export(thumbprint_exports, { calculateJwkThumbprint: () => calculateJwkThumbprint, calculateJwkThumbprintUri: () => calculateJwkThumbprintUri }); module.exports = __toCommonJS(thumbprint_exports); // src/lib/digest.ts var digest_default = async (algorithm, data) => { const subtleDigest = `SHA-${algorithm.slice(-3)}`; return new Uint8Array(await crypto.subtle.digest(subtleDigest, data)); }; // src/lib/buffer_utils.ts var encoder = new TextEncoder(); var decoder = new TextDecoder(); var MAX_INT32 = 2 ** 32; // src/lib/base64.ts function encodeBase64(input) { if (Uint8Array.prototype.toBase64) { return input.toBase64(); } const CHUNK_SIZE = 32768; const arr = []; for (let i = 0; i < input.length; i += CHUNK_SIZE) { arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE))); } return btoa(arr.join("")); } // src/util/base64url.ts function encode(input) { let unencoded = input; if (typeof unencoded === "string") { unencoded = encoder.encode(unencoded); } if (Uint8Array.prototype.toBase64) { return unencoded.toBase64({ alphabet: "base64url", omitPadding: true }); } return encodeBase64(unencoded).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_"); } // src/util/errors.ts var JOSEError = class extends Error { /** * A unique error code for the particular error subclass. * * @ignore */ static code = "ERR_JOSE_GENERIC"; /** A unique error code for {@link JOSEError}. */ code = "ERR_JOSE_GENERIC"; /** @ignore */ constructor(message2, options) { super(message2, options); this.name = this.constructor.name; Error.captureStackTrace?.(this, this.constructor); } }; var JOSENotSupported = class extends JOSEError { /** @ignore */ static code = "ERR_JOSE_NOT_SUPPORTED"; /** A unique error code for {@link JOSENotSupported}. */ code = "ERR_JOSE_NOT_SUPPORTED"; }; var JWKInvalid = class extends JOSEError { /** @ignore */ static code = "ERR_JWK_INVALID"; /** A unique error code for {@link JWKInvalid}. */ code = "ERR_JWK_INVALID"; }; // src/lib/is_key_like.ts function isCryptoKey(key) { return key?.[Symbol.toStringTag] === "CryptoKey"; } function isKeyObject(key) { return key?.[Symbol.toStringTag] === "KeyObject"; } var is_key_like_default = (key) => { return isCryptoKey(key) || isKeyObject(key); }; // src/lib/is_object.ts function isObjectLike(value) { return typeof value === "object" && value !== null; } var is_object_default = (input) => { if (!isObjectLike(input) || Object.prototype.toString.call(input) !== "[object Object]") { return false; } if (Object.getPrototypeOf(input) === null) { return true; } let proto = input; while (Object.getPrototypeOf(proto) !== null) { proto = Object.getPrototypeOf(proto); } return Object.getPrototypeOf(input) === proto; }; // src/lib/is_jwk.ts function isJWK(key) { return is_object_default(key) && typeof key.kty === "string"; } // src/lib/invalid_key_input.ts function message(msg, actual, ...types) { types = types.filter(Boolean); if (types.length > 2) { const last = types.pop(); msg += `one of type ${types.join(", ")}, or ${last}.`; } else if (types.length === 2) { msg += `one of type ${types[0]} or ${types[1]}.`; } else { msg += `of type ${types[0]}.`; } if (actual == null) { msg += ` Received ${actual}`; } else if (typeof actual === "function" && actual.name) { msg += ` Received function ${actual.name}`; } else if (typeof actual === "object" && actual != null) { if (actual.constructor?.name) { msg += ` Received an instance of ${actual.constructor.name}`; } } return msg; } var invalid_key_input_default = (actual, ...types) => { return message("Key must be ", actual, ...types); }; // src/lib/key_to_jwk.ts async function keyToJWK(key) { if (isKeyObject(key)) { if (key.type === "secret") { key = key.export(); } else { return key.export({ format: "jwk" }); } } if (key instanceof Uint8Array) { return { kty: "oct", k: encode(key) }; } if (!isCryptoKey(key)) { throw new TypeError(invalid_key_input_default(key, "CryptoKey", "KeyObject", "Uint8Array")); } if (!key.extractable) { throw new TypeError("non-extractable CryptoKey cannot be exported as a JWK"); } const { ext, key_ops, alg, use, ...jwk } = await crypto.subtle.exportKey("jwk", key); return jwk; } // src/key/export.ts async function exportJWK(key) { return keyToJWK(key); } // src/jwk/thumbprint.ts var check = (value, description) => { if (typeof value !== "string" || !value) { throw new JWKInvalid(`${description} missing or invalid`); } }; async function calculateJwkThumbprint(key, digestAlgorithm) { let jwk; if (isJWK(key)) { jwk = key; } else if (is_key_like_default(key)) { jwk = await exportJWK(key); } else { throw new TypeError(invalid_key_input_default(key, "CryptoKey", "KeyObject", "JSON Web Key")); } digestAlgorithm ??= "sha256"; if (digestAlgorithm !== "sha256" && digestAlgorithm !== "sha384" && digestAlgorithm !== "sha512") { throw new TypeError('digestAlgorithm must one of "sha256", "sha384", or "sha512"'); } let components; switch (jwk.kty) { case "EC": check(jwk.crv, '"crv" (Curve) Parameter'); check(jwk.x, '"x" (X Coordinate) Parameter'); check(jwk.y, '"y" (Y Coordinate) Parameter'); components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y }; break; case "OKP": check(jwk.crv, '"crv" (Subtype of Key Pair) Parameter'); check(jwk.x, '"x" (Public Key) Parameter'); components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x }; break; case "RSA": check(jwk.e, '"e" (Exponent) Parameter'); check(jwk.n, '"n" (Modulus) Parameter'); components = { e: jwk.e, kty: jwk.kty, n: jwk.n }; break; case "oct": check(jwk.k, '"k" (Key Value) Parameter'); components = { k: jwk.k, kty: jwk.kty }; break; default: throw new JOSENotSupported('"kty" (Key Type) Parameter missing or unsupported'); } const data = encoder.encode(JSON.stringify(components)); return encode(await digest_default(digestAlgorithm, data)); } async function calculateJwkThumbprintUri(key, digestAlgorithm) { digestAlgorithm ??= "sha256"; const thumbprint = await calculateJwkThumbprint(key, digestAlgorithm); return `urn:ietf:params:oauth:jwk-thumbprint:sha-${digestAlgorithm.slice(-3)}:${thumbprint}`; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { calculateJwkThumbprint, calculateJwkThumbprintUri });