UNPKG

crypto-ld

Version:

A Javascript library for generating and performing common operations on Linked Data cryptographic key pairs.

178 lines (162 loc) 5.55 kB
/*! * Copyright (c) 2020-2022 Digital Bazaar, Inc. All rights reserved. */ /** * General purpose key generation driver for Linked Data cryptographic key * pairs. * * @param {Map} [suites] - Optional map of supported suites, by suite id. */ export class CryptoLD { constructor({suites} = {}) { this.suites = suites || new Map(); } /** * Installs support for a key type (suite). * * @param {LDKeyPair} keyPairLib - Conforming key pair library for a suite. */ use(keyPairLib) { this.suites.set(keyPairLib.suite, keyPairLib); } /** * Generates a public/private LDKeyPair. * * @param {object} options - Suite-specific key options. * @param {string} options.type - Key suite id (for example, * 'Ed25519VerificationKey2020'). * @param {string} [options.controller] - Controller DID or URL for the * generated key pair. If present, used to auto-initialize the key.id. * * @returns {Promise<LDKeyPair>} Generated key pair. */ async generate(options = {}) { const Suite = this._suiteForType(options); return Suite.generate(options); } /** * Imports a public/private key pair from serialized data. * * @param {object} serialized - Serialized key object. * * @throws {Error} - On missing or invalid serialized key data. * * @returns {Promise<LDKeyPair>} Imported key pair. */ async from(serialized = {}) { const Suite = this._suiteForType(serialized); if(serialized['@context']) { // presume this may be an untrusted (fetched, etc) key document return Suite.fromKeyDocument({document: serialized}); } return Suite.from(serialized); } /** * Imports a key pair instance from a provided externally fetched key * document (fetched via a secure JSON-LD `documentLoader` or via * `cryptoLd.fromKeyId()`), optionally checking it for revocation and required * context. * * @param {object} options - Options hashmap. * @param {string} options.document - Externally fetched key document. * @param {boolean} [options.checkContext=true] - Whether to check that the * fetched key document contains the context required by the key's crypto * suite. * @param {boolean} [options.checkRevoked=true] - Whether to check the key * object for the presence of the `revoked` timestamp. * * @returns {Promise<LDKeyPair>} Resolves with the resulting key pair * instance. */ async fromKeyDocument({ document, checkContext = true, checkRevoked = true } = {}) { if(!document) { throw new TypeError('The "document" parameter is required.'); } const Suite = this._suiteForType(document); return Suite.fromKeyDocument({document, checkContext, checkRevoked}); } /** * Imports a key pair instance via the provided `documentLoader` function, * optionally checking it for revocation and required context. * * @param {object} options - Options hashmap. * @param {string} options.id - Key ID or URI. * @param {Function} options.documentLoader - JSON-LD Document Loader. * @param {boolean} [options.checkContext=true] - Whether to check that the * fetched key document contains the context required by the key's crypto * suite. * @param {boolean} [options.checkRevoked=true] - Whether to check the key * object for the presence of the `revoked` timestamp. * * @returns {Promise<LDKeyPair>} Resolves with the appropriate key pair * instance. */ async fromKeyId({ id, documentLoader, checkContext = true, checkRevoked = true } = {}) { if(!id) { throw new TypeError('The "id" parameter is required.'); } if(!documentLoader) { throw new TypeError('The "documentLoader" parameter is required.'); } let keyDocument; try { ({document: keyDocument} = await documentLoader(id)); // the supplied documentLoader may not be properly implemented if(!keyDocument) { throw new Error( 'The "documentLoader" function must return a "document" object.'); } } catch(e) { const error = new Error('Error fetching document: ' + e.message); error.cause = e; throw error; } const fetchedType = keyDocument.type; if(!fetchedType) { throw new Error('Key suite type not found in fetched document.'); } const keySuite = this.suites.get(fetchedType); if(!keySuite) { throw new Error(`Support for suite "${fetchedType}" is not installed.`); } return keySuite.fromKeyDocument({document: keyDocument, checkContext, checkRevoked}); } /** * Tests if a given key type is currently installed. * * @param {string} [type] - Key suite id ('Ed25519VerificationKey2020'). * @private * * @returns {boolean} True if key type installed. */ _installed({type}) { return this.suites.has(type); } /** * Returns the installed crypto suite class for a given document's type. * * @param {object} document - A serialized key document (or options document). * @param {string} document.type - Key suite id (for example, * 'Ed25519VerificationKey2020'). * * @returns {object} LDKeyPair (crypto suite) class. */ _suiteForType(document) { const type = document && document.type; if(!type) { throw new TypeError('Missing key type.'); } if(!this._installed({type})) { throw new Error(`Support for key type "${type}" is not installed.`); } return this.suites.get(type); } } /** * @typedef LDKeyPair */