@enbox/dids
Version:
TBD DIDs library
201 lines • 11.6 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { LocalKeyManager, CryptoUtils } from '@enbox/crypto';
import { DidError, DidErrorCode } from './did-error.js';
import { extractDidFragment, getVerificationMethods } from './utils.js';
/**
* Represents a Decentralized Identifier (DID) along with its DID document, key manager, metadata,
* and convenience functions.
*/
export class BearerDid {
constructor({ uri, document, metadata, keyManager }) {
this.uri = uri;
this.document = document;
this.metadata = metadata;
this.keyManager = keyManager;
}
/**
* Converts a `BearerDid` object to a portable format containing the URI and verification methods
* associated with the DID.
*
* This method is useful when you need to represent the key material and metadata associated with
* a DID in format that can be used independently of the specific DID method implementation. It
* extracts both public and private keys from the DID's key manager and organizes them into a
* `PortableDid` structure.
*
* @remarks
* If the DID's key manager does not allow private keys to be exported, the `PortableDid` returned
* will not contain a `privateKeys` property. This enables the importing and exporting DIDs that
* use the same underlying KMS even if the KMS does not support exporting private keys. Examples
* include hardware security modules (HSMs) and cloud-based KMS services like AWS KMS.
*
* If the DID's key manager does support exporting private keys, the resulting `PortableDid` will
* include a `privateKeys` property which contains the same number of entries as there are
* verification methods as the DID document, each with its associated private key and the
* purpose(s) for which the key can be used (e.g., `authentication`, `assertionMethod`, etc.).
*
* @example
* ```ts
* // Assuming `did` is an instance of BearerDid
* const portableDid = await did.export();
* // portableDid now contains the DID URI, document, metadata, and optionally, private keys.
* ```
*
* @returns A `PortableDid` containing the URI, DID document, metadata, and optionally private
* keys associated with the `BearerDid`.
* @throws An error if the DID document does not contain any verification methods or the keys for
* any verification method are missing in the key manager.
*/
export() {
return __awaiter(this, void 0, void 0, function* () {
// Verify the DID document contains at least one verification method.
if (!(Array.isArray(this.document.verificationMethod) && this.document.verificationMethod.length > 0)) {
throw new Error(`DID document for '${this.uri}' is missing verification methods`);
}
// Create a new `PortableDid` copy object to store the exported data.
let portableDid = JSON.parse(JSON.stringify({
uri: this.uri,
document: this.document,
metadata: this.metadata
}));
// If the BearerDid's key manager supports exporting private keys, add them to the portable DID.
if ('exportKey' in this.keyManager && typeof this.keyManager.exportKey === 'function') {
const privateKeys = [];
for (let vm of this.document.verificationMethod) {
if (!vm.publicKeyJwk) {
throw new Error(`Verification method '${vm.id}' does not contain a public key in JWK format`);
}
// Compute the key URI of the verification method's public key.
const keyUri = yield this.keyManager.getKeyUri({ key: vm.publicKeyJwk });
// Retrieve the private key from the key manager.
const privateKey = yield this.keyManager.exportKey({ keyUri });
// Add the verification method to the key set.
privateKeys.push(Object.assign({}, privateKey));
}
portableDid.privateKeys = privateKeys;
}
return portableDid;
});
}
/**
* Return a {@link Signer} that can be used to sign messages, credentials, or arbitrary data.
*
* If given, the `methodId` parameter is used to select a key from the verification methods
* present in the DID Document.
*
* If `methodID` is not given, the first verification method intended for signing claims is used.
*
* @param params - The parameters for the `getSigner` operation.
* @param params.methodId - ID of the verification method key that will be used for sign and
* verify operations. Optional.
* @returns An instantiated {@link Signer} that can be used to sign and verify data.
*/
getSigner(params) {
return __awaiter(this, void 0, void 0, function* () {
var _a;
// Attempt to find a verification method that matches the given method ID, or if not given,
// find the first verification method intended for signing claims.
const verificationMethod = (_a = this.document.verificationMethod) === null || _a === void 0 ? void 0 : _a.find(vm => { var _a, _b; return extractDidFragment(vm.id) === ((_a = extractDidFragment(params === null || params === void 0 ? void 0 : params.methodId)) !== null && _a !== void 0 ? _a : extractDidFragment((_b = this.document.assertionMethod) === null || _b === void 0 ? void 0 : _b[0])); });
if (!(verificationMethod && verificationMethod.publicKeyJwk)) {
throw new DidError(DidErrorCode.InternalError, 'A verification method intended for signing could not be determined from the DID Document');
}
// Compute the expected key URI of the signing key.
const keyUri = yield this.keyManager.getKeyUri({ key: verificationMethod.publicKeyJwk });
// Get the public key to be used for verify operations, which also verifies that the key is
// present in the key manager's store.
const publicKey = yield this.keyManager.getPublicKey({ keyUri });
// Bind the DID's key manager to the signer.
const keyManager = this.keyManager;
// Determine the signing algorithm.
const algorithm = CryptoUtils.getJoseSignatureAlgorithmFromPublicKey(publicKey);
return {
algorithm: algorithm,
keyId: verificationMethod.id,
sign(_a) {
return __awaiter(this, arguments, void 0, function* ({ data }) {
const signature = yield keyManager.sign({ data, keyUri: keyUri }); // `keyUri` is guaranteed to be defined at this point.
return signature;
});
},
verify(_a) {
return __awaiter(this, arguments, void 0, function* ({ data, signature }) {
const isValid = yield keyManager.verify({ data, key: publicKey, signature }); // `publicKey` is guaranteed to be defined at this point.
return isValid;
});
}
};
});
}
/**
* Instantiates a {@link BearerDid} object from a given {@link PortableDid}.
*
* This method allows for the creation of a `BearerDid` object using a previously created DID's
* key material, DID document, and metadata.
*
* @example
* ```ts
* // Export an existing BearerDid to PortableDid format.
* const portableDid = await did.export();
* // Reconstruct a BearerDid object from the PortableDid.
* const did = await BearerDid.import({ portableDid });
* ```
*
* @param params - The parameters for the import operation.
* @param params.portableDid - The PortableDid object to import.
* @param params.keyManager - Optionally specify an external Key Management System (KMS) used to
* generate keys and sign data. If not given, a new
* {@link LocalKeyManager} instance will be created and
* used.
* @returns A Promise resolving to a `BearerDid` object representing the DID formed from the
* provided PortableDid.
* @throws An error if the PortableDid document does not contain any verification methods or the
* keys for any verification method are missing in the key manager.
*/
static import(_a) {
return __awaiter(this, arguments, void 0, function* ({ portableDid, keyManager = new LocalKeyManager() }) {
var _b;
// Get all verification methods from the given DID document, including embedded methods.
const verificationMethods = getVerificationMethods({ didDocument: portableDid.document });
// Validate that the DID document contains at least one verification method.
if (verificationMethods.length === 0) {
throw new DidError(DidErrorCode.InvalidDidDocument, `At least one verification method is required but 0 were given`);
}
// If given, import the private key material into the key manager.
for (let key of (_b = portableDid.privateKeys) !== null && _b !== void 0 ? _b : []) {
// confirm th key does not already exist before importing it to avoid failures from the key manager
const keyUri = yield keyManager.getKeyUri({ key });
const keyExists = yield keyManager.getPublicKey({ keyUri }).then(() => true).catch(() => false);
if (!keyExists) {
yield keyManager.importKey({ key });
}
}
// Validate that the key material for every verification method in the DID document is present
// in the key manager.
for (let vm of verificationMethods) {
if (!vm.publicKeyJwk) {
throw new Error(`Verification method '${vm.id}' does not contain a public key in JWK format`);
}
// Compute the key URI of the verification method's public key.
const keyUri = yield keyManager.getKeyUri({ key: vm.publicKeyJwk });
// Verify that the key is present in the key manager. If not, an error is thrown.
yield keyManager.getPublicKey({ keyUri });
}
// Use the given PortableDid to construct the BearerDid object.
const did = new BearerDid({
uri: portableDid.uri,
document: portableDid.document,
metadata: portableDid.metadata,
keyManager
});
return did;
});
}
}
//# sourceMappingURL=bearer-did.js.map