UNPKG

ts-jose

Version:

Wrap functions of JOSE in steady interface

103 lines 3.27 kB
import { calculateJwkThumbprint, exportJWK, generateKeyPair, generateSecret, importJWK, } from 'jose'; import { JoseError } from './error.js'; const RSAPrivateProperties = ['d', 'p', 'q', 'dp', 'dq', 'qi', 'oth']; export class JWK { constructor(key, metadata) { this.key = key; this.metadata = deleteUndefined(metadata); } get kid() { return this.metadata.kid; } get alg() { return this.metadata.alg; } get use() { return this.metadata.use; } get kty() { return this.metadata.kty; } get isPrivate() { switch (this.kty) { case 'oct': return true; case 'EC': case 'OKP': return this.metadata.d !== undefined; case 'RSA': return Object.entries(this.metadata) .filter((entry) => RSAPrivateProperties.includes(entry[0])) .some((entry) => entry[1] !== undefined); } } getThumbprint(config) { return calculateJwkThumbprint(this.metadata, config?.digestAlgorithm); } getKey(options) { if (options.kid !== undefined && options.kid !== this.kid) { throw new JoseError('Key', 'kid', options.kid, this.kid); } if (options.use !== undefined && this.use !== undefined) { if (options.use !== this.use) { throw new JoseError('Key', 'use', options.use, this.use); } } if (options.alg !== undefined && this.alg !== undefined) { if (options.alg !== this.alg) { throw new JoseError('Key', 'alg', options.alg, this.alg); } } return this; } async toPublic() { if (!this.isPrivate) return this; return JWK.fromObject(this.toObject()); } toObject(asPrivate = false) { if (this.isPrivate && !asPrivate) { const { kid, alg, use, kty, crv, x, y, e, n } = this.metadata; return deleteUndefined({ kid, alg, use, kty, crv, x, y, e, n }); } const { ...key } = this.metadata; return key; } static async fromObject(keyObject) { const key = await importJWK(keyObject, keyObject.alg, { extractable: true, }); return new JWK(key, keyObject); } static async generate(algorithm, options) { const key = await generateKey(algorithm, options); const metadata = (await exportJWK(key)); return new JWK(key, { kid: options?.kid, use: options?.use, alg: algorithm, ...metadata, }); } } function deleteUndefined(data) { Object.entries(data).forEach((entry) => { if (entry[1] === undefined) { delete data[entry[0]]; } }); return data; } async function generateKey(algorithm, options) { if (algorithm.startsWith('HS') || algorithm.startsWith('A')) { return generateSecret(algorithm, { extractable: false, }); } const keyPair = await generateKeyPair(algorithm, { ...options, extractable: true, }); return keyPair.privateKey; } //# sourceMappingURL=jwk.js.map