@gaonengwww/jose
Version:
JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes
127 lines (124 loc) • 3.82 kB
JavaScript
// src/lib/crypto_key.ts
function unusable(name, prop = "algorithm.name") {
return new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name}`);
}
function isAlgorithm(algorithm, name) {
return algorithm.name === name;
}
function getHashLength(hash) {
return parseInt(hash.name.slice(4), 10);
}
function getNamedCurve(alg) {
switch (alg) {
case "ES256":
return "P-256";
case "ES384":
return "P-384";
case "ES512":
return "P-521";
default:
throw new Error("unreachable");
}
}
function checkUsage(key, usage) {
if (usage && !key.usages.includes(usage)) {
throw new TypeError(
`CryptoKey does not support this operation, its usages must include ${usage}.`
);
}
}
function checkSigCryptoKey(key, alg, usage) {
switch (alg) {
case "HS256":
case "HS384":
case "HS512": {
if (!isAlgorithm(key.algorithm, "HMAC")) throw unusable("HMAC");
const expected = parseInt(alg.slice(2), 10);
const actual = getHashLength(key.algorithm.hash);
if (actual !== expected) throw unusable(`SHA-${expected}`, "algorithm.hash");
break;
}
case "RS256":
case "RS384":
case "RS512": {
if (!isAlgorithm(key.algorithm, "RSASSA-PKCS1-v1_5"))
throw unusable("RSASSA-PKCS1-v1_5");
const expected = parseInt(alg.slice(2), 10);
const actual = getHashLength(key.algorithm.hash);
if (actual !== expected) throw unusable(`SHA-${expected}`, "algorithm.hash");
break;
}
case "PS256":
case "PS384":
case "PS512": {
if (!isAlgorithm(key.algorithm, "RSA-PSS")) throw unusable("RSA-PSS");
const expected = parseInt(alg.slice(2), 10);
const actual = getHashLength(key.algorithm.hash);
if (actual !== expected) throw unusable(`SHA-${expected}`, "algorithm.hash");
break;
}
case "Ed25519":
// Fall through
case "EdDSA": {
if (!isAlgorithm(key.algorithm, "Ed25519")) throw unusable("Ed25519");
break;
}
case "ES256":
case "ES384":
case "ES512": {
if (!isAlgorithm(key.algorithm, "ECDSA")) throw unusable("ECDSA");
const expected = getNamedCurve(alg);
const actual = key.algorithm.namedCurve;
if (actual !== expected) throw unusable(expected, "algorithm.namedCurve");
break;
}
default:
throw new TypeError("CryptoKey does not support this operation");
}
checkUsage(key, usage);
}
// 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/get_sign_verify_key.ts
var get_sign_verify_key_default = async (alg, key, usage) => {
if (key instanceof Uint8Array) {
if (!alg.startsWith("HS")) {
throw new TypeError(invalid_key_input_default(key, "CryptoKey", "KeyObject", "JSON Web Key"));
}
return crypto.subtle.importKey(
"raw",
key,
{ hash: `SHA-${alg.slice(-3)}`, name: "HMAC" },
false,
[usage]
);
}
checkSigCryptoKey(key, alg, usage);
return key;
};
export {
get_sign_verify_key_default as default
};