@microsoft/useragent-sdk
Version:
SDK for building decentralized identity wallets and enterprise agents.
1,172 lines (1,157 loc) • 3.29 MB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.useragentSdk = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const CryptoFactory_1 = require("./crypto/plugin/CryptoFactory");
const SubtleCryptoBrowserOperations_1 = require("./crypto/plugin/SubtleCryptoBrowser");
const KeyStoreInMemory_1 = require("./crypto/keyStore/KeyStoreInMemory");
const JoseProtocol_1 = require("./crypto/protocols/jose/JoseProtocol");
/**
* Class used to model crypto options
*/
class CryptoOptions {
constructor() {
/**
* Get or set the crypto api to be used. Initialize the default crypto plugin.
*/
this.cryptoFactory = new CryptoFactory_1.default(new KeyStoreInMemory_1.default(), new SubtleCryptoBrowserOperations_1.default());
/**
* Get or set the payload protection protocol.
*/
this.payloadProtection = new JoseProtocol_1.default();
/**
* Get or set the signing algorithm.
*/
this.signingAlgorithm = 'ES256K';
/**
* Get or set the encryption algorithm.
*/
this.encryptionAlgorithm = 'RSA-OAEP';
}
}
exports.default = CryptoOptions;
},{"./crypto/keyStore/KeyStoreInMemory":11,"./crypto/plugin/CryptoFactory":26,"./crypto/plugin/SubtleCryptoBrowser":28,"./crypto/protocols/jose/JoseProtocol":35}],2:[function(require,module,exports){
(function (Buffer){
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
const KeyStoreConstants_1 = require("./keystores/KeyStoreConstants");
const IdentifierDocument_1 = require("./IdentifierDocument");
const UserAgentError_1 = require("./UserAgentError");
const ProtectionFormat_1 = require("./crypto/keyStore/ProtectionFormat");
const SubtleCryptoExtension_1 = require("./crypto/plugin/SubtleCryptoExtension");
const JwsToken_1 = require("./crypto/protocols/jose/jws/JwsToken");
const CryptoHelpers_1 = require("./crypto/utilities/CryptoHelpers");
const KeyUseFactory_1 = require("./crypto/keys/KeyUseFactory");
const JweToken_1 = require("./crypto/protocols/jose/jwe/JweToken");
const JoseConstants_1 = require("./crypto/protocols/jose/JoseConstants");
const UserAgentConstants_1 = require("./UserAgentConstants");
/**
* Class for creating and managing identifiers,
* retrieving identifier documents.
*/
class Identifier {
/**
* Constructs an instance of the Identifier
* class using the provided identifier or identifier document.
* @param identifier either the string representation of an identifier or a identifier document.
* @param [options] for configuring how to register and resolve identifiers.
*/
constructor(identifier, options) {
this.identifier = identifier;
// Check whether passed an identifier document
// or an identifier string
if (typeof identifier === 'object') {
this.document = identifier;
this.id = identifier.id;
}
else {
this.id = identifier;
}
this.options = options;
}
/**
* Creates a new decentralized identifier.
* @param [options] for configuring how to register and resolve identifiers.
*/
static async create(options) {
const id = options.didPrefix;
return new Identifier(id, options).createLinkedIdentifier(id, true);
}
/**
* Creates a new decentralized identifier, using the current identifier
* and the specified target. If the registar flag is true, the newly created
* identifier will be registered using the
* @param target entity for which to create the linked identifier
* @param register flag indicating whether the new identifier should be registered
* with a ledger.
*/
async createLinkedIdentifier(target, register = false) {
if (this.options && this.options.keyStore) {
// Create DID key
const cryptoFactory = this.options.cryptoFactory;
const signingKeyStorageId = Identifier.keyStorageIdentifier(this.id, target, this.options.cryptoOptions.signingAlgorithm, KeyUseFactory_1.default.createViaJwa(this.options.cryptoOptions.signingAlgorithm));
const signingPublicKey = await this.generateAndSaveKey(new SubtleCryptoExtension_1.default(cryptoFactory), this.options.cryptoOptions.signingAlgorithm, target, `#${UserAgentConstants_1.default.keyTagSigning}1`, signingKeyStorageId || this.options.cryptoOptions.signingKeyReference);
const encryptionKeyStorageId = Identifier.keyStorageIdentifier(this.id, target, this.options.cryptoOptions.encryptionAlgorithm, KeyUseFactory_1.default.createViaJwa(this.options.cryptoOptions.encryptionAlgorithm));
const encryptionPublicKey = await this.generateAndSaveKey(new SubtleCryptoExtension_1.default(cryptoFactory), this.options.cryptoOptions.encryptionAlgorithm, target, `#${UserAgentConstants_1.default.keyTagEncryption}1`, encryptionKeyStorageId || this.options.cryptoOptions.encryptionKeyReference);
// Set key format
// todo switch by leveraging pairwiseKey
const signingDocumentKey = {
id: signingPublicKey.kid,
type: this.getDidDocumentKeyType(),
publicKeyJwk: signingPublicKey
};
const encryptionDocumentKey = {
id: encryptionPublicKey.kid,
// we need to add RsaEncryptionKey 2018 as type - todo
type: 'RsaVerificationKey2018',
publicKeyJwk: encryptionPublicKey
};
let identifier;
if (this.options.registrar) {
// add encryptionDocumentKey to register the encryption key
const document = await this.createIdentifierDocument(this.id, [signingDocumentKey, encryptionDocumentKey]);
if (register) {
// register did document
identifier = await this.options.registrar.register(document, signingKeyStorageId);
document.id = identifier.id;
}
identifier = new Identifier(document, this.options);
// If we create a new identifier save the signing key
if (target === this.id) {
this.options.cryptoOptions.signingKeyReference = signingKeyStorageId;
this.options.cryptoOptions.encryptionKeyReference = encryptionKeyStorageId;
}
return identifier;
}
else {
throw new UserAgentError_1.default(`No registrar in options to register DID document`);
}
}
throw new UserAgentError_1.default('No keyStore in options');
}
/**
* Generate a key and save it into the store
* @param generator interface
* @param algorithm for the key
* @param target id of peer
*/
async generateAndSaveKey(generator, algorithm, target, kid, keyReference) {
const alg = CryptoHelpers_1.default.jwaToWebCrypto(algorithm);
const jwk = await generator.generatePairwiseKey(alg, KeyStoreConstants_1.default.masterSeed, this.id, target);
jwk.kid = kid;
jwk.use = KeyUseFactory_1.default.createViaJwa(algorithm);
const pubJwk = jwk.getPublicKey();
pubJwk.kid = jwk.kid;
const pairwiseKeyStorageId = keyReference || Identifier.keyStorageIdentifier(this.id, target, algorithm, KeyUseFactory_1.default.createViaJwa(algorithm));
await this.options.keyStore.save(pairwiseKeyStorageId, jwk);
return pubJwk;
}
/**
* Gets the IdentifierDocument for the identifier
* instance, throwing if no identifier has been
* created.
*/
async getDocument() {
// If we already have not already
// retrieved the document use the
// resolver to get the document
if (!this.document) {
if (!this.options || !this.options.resolver) {
throw new UserAgentError_1.default('Resolver not specified in user agent options.');
}
// We need to resolve the document
this.document = await this.options.resolver.resolve(this);
}
return this.document;
}
/**
* Performs a public key lookup using the
* specified key identifier, returning the
* key defined in document.
* @param keyIdentifier the identifier of the public key.
*/
async getPublicKey(keyIdentifier) {
if (!this.document) {
await this.getDocument();
}
// If we have been provided a key identifier use
// the identifier to look up a key in the document
if (this.document && this.document.publicKeys && keyIdentifier) {
const index = this.document.publicKeys.findIndex((key) => key.id === keyIdentifier);
// trim down the key Identifier to the unique keyID
const keyIdentifierComponents = keyIdentifier.split('#');
const keyId = keyIdentifierComponents[keyIdentifierComponents.length - 1];
const matchingPublicKeys = this.document.publicKeys.filter((PublicKey) => PublicKey.id.endsWith(keyId));
if (matchingPublicKeys.length === 0) {
throw new UserAgentError_1.default(`No matching public key found for ${keyIdentifier}`);
}
return matchingPublicKeys[0];
}
else if (this.document && this.document.publicKeys && this.document.publicKeys.length > 0) {
// If only one key has been specified in the document
// return that
return this.document.publicKeys[0];
}
throw new UserAgentError_1.default('Document does not contain any public keys');
}
/**
* Generate a storage identifier to store a key
* @param personaId The identifier for the persona
* @param target The identifier for the peer. Will be persona for non-pairwise keys
* @param algorithm Key algorithm
* @param keyType Key type
*/
static keyStorageIdentifier(personaId, target, algorithm, keyType) {
console.log(`${personaId}-${target}-${algorithm}-${keyType}`);
return `${personaId}-${target}-${algorithm}-${keyType}`;
}
// Create an identifier document. Included the public key.
async createIdentifierDocument(id, publicKeys) {
return IdentifierDocument_1.default.createAndGenerateId(id, publicKeys, this.options);
}
// Get the did document public key type
getDidDocumentKeyType() {
// Support other key types
return 'Secp256k1VerificationKey2018';
}
/**
* Sign payload with key specified by keyStorageIdentifier in options.keyStore
* @param payload object to be signed
* @param keyReference the identifier for the key used to sign payload.
*/
async sign(payload, keyReference) {
let body;
if (this.options && this.options.cryptoOptions) {
if (this.options.keyStore) {
if (typeof (payload) !== 'string') {
body = JSON.stringify(payload);
}
else {
body = payload;
}
const signingOptions = {
cryptoFactory: this.options.cryptoFactory
};
const jws = new JwsToken_1.default(signingOptions);
const signature = await jws.sign(keyReference, Buffer.from(body), ProtectionFormat_1.ProtectionFormat.JwsFlatJson);
return signature.serialize();
;
}
else {
throw new UserAgentError_1.default('No KeyStore in Options');
}
}
else {
throw new UserAgentError_1.default('No Crypto Options in User Agent Options');
}
}
/**
* Verify the payload with public key from the Identifier Document.
* @param jws the signed token to be verified.
*/
async verify(jws) {
if (!this.document) {
this.document = await this.getDocument();
}
const signingOptions = {
cryptoFactory: this.options.cryptoFactory
};
const token = JwsToken_1.default.deserialize(jws, signingOptions);
if (await token.verify(this.document.getPublicKeysFromDocument(), signingOptions)) {
return token.getPayload();
}
throw new UserAgentError_1.default(`The signature validation for '${this.id}' failed.`);
}
/**
* Encrypt payload using Public Key registered on Identifier Document.
* @param payload object that will be encrypted.
* @param encryptionKeys used for the encryption.
*/
async encrypt(payload) {
if (!this.options) {
throw new UserAgentError_1.default('Options Undefined');
}
// get document if undefined
if (!this.document) {
this.document = await this.getDocument();
}
const keyStore = this.options.keyStore;
const cryptoFactory = this.options.cryptoFactory;
const options = {
cryptoFactory: cryptoFactory,
contentEncryptionAlgorithm: JoseConstants_1.default.AesGcm256
};
// create a jweToken with temp cryptoFactory and algorithm.
const jweToken = new JweToken_1.default(options);
// get any JWK key marked use as 'enc'
const publicKey = this.document.getPublicKeysFromDocument().reduce((keyFound, currentKey) => {
if (keyFound) {
return keyFound;
}
if (currentKey.use === KeyUseFactory_1.KeyUse.Encryption) {
return currentKey;
}
return undefined;
}, undefined);
if (!publicKey) {
throw new UserAgentError_1.default(`No Public Key found with use equal to 'enc' for ${this.id}`);
}
// keyIDs retrieved from the DID Document may not be fully quantified
if (publicKey.kid && publicKey.kid.indexOf('#') <= 0) {
publicKey.kid = `${this.id}${publicKey.kid.indexOf('#') === -1 ? '#' : ''}${publicKey.kid}`;
}
// encrypt payload using public keys.
const encryptedToken = await jweToken.encrypt([publicKey], payload, ProtectionFormat_1.ProtectionFormat.JweCompactJson);
// return serialized token.
return encryptedToken.serialize(ProtectionFormat_1.ProtectionFormat.JweCompactJson);
}
/**
* Decrypt cipher using key referenced in keystore.
* @param cipher cipher to be decrypted.
* @param keyReference string that references what key to use from keystore.
*/
async decrypt(cipher, keyReference) {
if (!this.options) {
throw new UserAgentError_1.default('Options Undefined');
}
const options = {
cryptoFactory: this.options.cryptoFactory
};
const jweToken = JweToken_1.default.deserialize(cipher.toString(), options);
// create jweToken, feed in ciphertext, and decrypt.
const payload = await jweToken.decrypt(keyReference);
return payload.toString();
}
}
exports.default = Identifier;
}).call(this,require("buffer").Buffer)
},{"./IdentifierDocument":3,"./UserAgentConstants":4,"./UserAgentError":5,"./crypto/keyStore/ProtectionFormat":12,"./crypto/keys/KeyUseFactory":15,"./crypto/plugin/SubtleCryptoExtension":29,"./crypto/protocols/jose/JoseConstants":33,"./crypto/protocols/jose/jwe/JweToken":38,"./crypto/protocols/jose/jws/JwsToken":40,"./crypto/utilities/CryptoHelpers":44,"./keystores/KeyStoreConstants":68,"buffer":517}],3:[function(require,module,exports){
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
const UserAgentError_1 = require("./UserAgentError");
const HostServiceEndpoint_1 = require("./serviceEndpoints/HostServiceEndpoint");
const UserServiceEndpoint_1 = require("./serviceEndpoints/UserServiceEndpoint");
const cloneDeep = require('lodash/fp/cloneDeep');
/**
* Class for creating and managing identifiers,
* retrieving identifier documents.
*/
class IdentifierDocument {
/**
* Constructs an instance of the identifier
* document.
* @param document from which to create the identifier document.
* @param options for configuring how to register and resolve identifiers.
*/
constructor(document) {
/**
* Array of service entries added to the document.
*/
this.publicKeys = [];
/**
* Array of authentication entries added to the document.
*/
this.authenticationReferences = [];
/**
* Array of service entries added to the document.
*/
this.serviceReferences = [];
// Populate the base properties
this.id = document.id;
this.publicKeys = document.publicKeys;
if (document.created) {
this.created = new Date(document.created);
}
this.authenticationReferences = document.authentication || [];
this.serviceReferences = document.service || [];
if (document.service && document.service.length > 0) {
document.service.forEach((serviceRef) => {
if (serviceRef.serviceEndpoint['@type'] === 'HostServiceEndpoint') {
serviceRef.serviceEndpoint = HostServiceEndpoint_1.default.fromJSON(serviceRef.serviceEndpoint);
}
else {
serviceRef.serviceEndpoint = UserServiceEndpoint_1.default.fromJSON(serviceRef.serviceEndpoint);
}
});
}
}
/**
* Creates a new instance of an identifier document using the
* provided public keys.
* @param publicKeys to include in the document.
*/
static create(id, publicKeys) {
const createdDate = new Date(Date.now()).toISOString();
return new IdentifierDocument({ id: id, created: createdDate, publicKeys: publicKeys });
}
/**
* Creates a new instance of an identifier document using the
* provided public keys.
* The id is generated.
* @param idBase The base id in format did:{method}:{id}. {id} will be filled in by this method
* @param publicKeys to include in the document.
* @param options User agent options containing the crypto Api
*/
static async createAndGenerateId(idBase, publicKeys, options) {
const document = IdentifierDocument.create(idBase, publicKeys);
const identifier = await options.registrar.generateIdentifier(document);
document.id = identifier.id;
return document;
}
/**
* Adds an authentication reference to the document.
* @param authenticationReference to add to the document.
*/
addAuthenticationReference(authenticationReference) {
this.authenticationReferences.push(authenticationReference);
}
/**
* Adds a service reference to the document.
* @param serviceReference to add to the document.
*/
addServiceReference(serviceReference) {
this.serviceReferences.push(serviceReference);
}
/**
* Get Hub Instances from Identity Service Reference.
*/
getHubInstances() {
const filteredServiceReferences = this.serviceReferences.filter(reference => reference.type === 'IdentityHub');
if (filteredServiceReferences.length === 0 || filteredServiceReferences[0].serviceEndpoint.type !== 'UserServiceEndpoint') {
throw new UserAgentError_1.default(`No Hub Instances for ${this.id}`);
}
const serviceEndpoint = filteredServiceReferences[0].serviceEndpoint;
return serviceEndpoint.instances;
}
/**
* Get Hub Locations from Identity Service Reference.
*/
getHubLocations() {
const filteredServiceReferences = this.serviceReferences.filter(reference => reference.type === 'IdentityHub');
if (filteredServiceReferences.length === 0 || filteredServiceReferences[0].serviceEndpoint.type !== 'HostServiceEndpoint') {
throw new UserAgentError_1.default(`No Hub Locations for ${this.id}`);
}
const serviceEndpoint = filteredServiceReferences[0].serviceEndpoint;
return serviceEndpoint.locations;
}
getPublicKeysFromDocument() {
return this.publicKeys.map(key => key.publicKeyJwk);
}
/**
* Used to control the the properties that are
* output by JSON.parse.
*/
static fromJSON(obj) {
const document = Object.create(IdentifierDocument.prototype);
const result = Object.assign(document, obj, {
publicKeys: obj.publicKey
});
delete result.publicKey;
return new IdentifierDocument(document);
}
/**
* Used to control the the properties that are
* output by JSON.stringify.
*/
toJSON() {
// Clone the current instance. Note the use of
// a deep clone to ensure immutability of
// the instance being cloned for serialization
const clonedDocument = cloneDeep(this);
// Add the JSON-LD context
clonedDocument['@context'] = 'https://w3id.org/did/v1';
// switch authentication references to authentication.
if (this.authenticationReferences && this.authenticationReferences.length > 0) {
clonedDocument.authentication = this.authenticationReferences;
}
clonedDocument.authenticationReferences = undefined;
// switch service references to service.
if (this.serviceReferences && this.serviceReferences.length > 0) {
clonedDocument.service = this.serviceReferences;
clonedDocument.service.forEach((serviceRef) => {
if (serviceRef.serviceEndpoint['type'] === 'HostServiceEndpoint') {
serviceRef.serviceEndpoint = serviceRef.serviceEndpoint.toJSON();
}
else {
serviceRef.serviceEndpoint = serviceRef.serviceEndpoint.toJSON();
}
});
}
clonedDocument.serviceReferences = undefined;
if (!this.publicKeys || this.publicKeys.length === 0) {
clonedDocument.publicKeys = undefined;
}
else {
clonedDocument.publicKey = this.publicKeys;
delete clonedDocument.publicKeys;
}
// Now return the cloned document for serialization
return clonedDocument;
}
}
exports.default = IdentifierDocument;
},{"./UserAgentError":5,"./serviceEndpoints/HostServiceEndpoint":73,"./serviceEndpoints/UserServiceEndpoint":75,"lodash/fp/cloneDeep":319}],4:[function(require,module,exports){
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
/**
* General constants used by user agent
*/
class UserAgentConstants {
}
/**
* Define default key tag for signature key
*/
UserAgentConstants.keyTagSigning = 'sigKey';
/**
* Define default key tag for encyption key
*/
UserAgentConstants.keyTagEncryption = 'encKey';
exports.default = UserAgentConstants;
},{}],5:[function(require,module,exports){
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Base error class for the UserAgent.
*/
class UserAgentError extends Error {
constructor(message) {
super(message);
// NOTE: Extending 'Error' breaks prototype chain since TypeScript 2.1.
// The following line restores prototype chain.
Object.setPrototypeOf(this, new.target.prototype);
}
}
exports.default = UserAgentError;
},{}],6:[function(require,module,exports){
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
const CryptoOptions_1 = require("./CryptoOptions");
/**
* Interface defining options for the
* User Agent, such as resolver and register.
*/
class UserAgentOptions {
constructor() {
/**
* The timeout when making requests to
* external services.
*/
this.timeoutInSeconds = 30;
/**
* The locale to be used by the
* user agent.
*/
this.locale = 'en';
/**
* The lifetime of any self-issued credentials.
* Used to determine the expiry time of the
* credential.
*/
this.selfIssuedCredentialLifetimeInSeconds = 300; // 5 mins
/**
* Crypto Options
* contains algorithm and other data about crypto
*/
this.cryptoOptions = new CryptoOptions_1.default();
/**
* Prefix for the generated did.
*/
this.didPrefix = 'did:ion';
}
/**
* Get the key store
*/
get keyStore() {
return this.cryptoOptions.cryptoFactory.keyStore;
}
/**
* Set the key store
*/
set keyStore(keyStore) {
this.cryptoOptions.cryptoFactory.keyStore = keyStore;
}
/**
* Get the crypto operations
*/
get cryptoFactory() {
return this.cryptoOptions.cryptoFactory;
}
/**
* Set the key store
*/
set cryptoFactory(cryptoFactory) {
this.cryptoOptions.cryptoFactory = cryptoFactory;
}
}
exports.default = UserAgentOptions;
},{"./CryptoOptions":1}],7:[function(require,module,exports){
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
const UserAgentError_1 = require("../UserAgentError");
const CredentialManifest_1 = require("./CredentialManifest");
require("isomorphic-fetch");
/**
* Class for obtaining
* credentials from an issuer.
*/
class CredentialIssuer {
/**
* Constructs an instance of the credential issuer
* based on the specified credential manifest.
* @param identifier for the issuer.
* @param manifest credential manifest for specific credential.
*/
constructor(identifier, manifest) {
this.identifier = identifier;
this.manifest = new CredentialManifest_1.default(manifest);
}
/**
* Constructs an instance of the credential issuer
* based on the specified credential manifest.
* @param identifier for the issuer.
* @param manifest credential manifest object or endpoint string of manifest.
*/
static async create(identifier, manifest) {
let manifestJson;
if (typeof (manifest) === 'string') {
const response = await fetch(manifest);
if (!response.ok) {
let error;
switch (response.status) {
case 404:
error = new UserAgentError_1.default(`Failed to request a credential manifest from the issuer \'${identifier.id}.\'`);
break;
default:
error = new UserAgentError_1.default(`'${manifest}' returned an error with \'${response.statusText}\'`);
}
throw error;
}
manifestJson = await response.json();
}
else {
manifestJson = manifest;
}
return new CredentialIssuer(identifier, manifestJson);
}
/**
* Gets the array of languages supported
* by the manifest.
*/
// public get language (): Array<string> {
// console.log(this.identifier);
// return this.manifest.language || [];
// }
/**
* Requests a new credential from the issuer,
* providing a self-issued credential with the inputs
* specified in the credential manifest.
* @param inputCredential containing the inputs as specified
* in the credential manifest.
*/
async requestCredential(inputCredential) {
const serializedCredential = JSON.stringify(inputCredential);
return new Promise(async (resolve, reject) => {
const timer = setTimeout(() => reject(new UserAgentError_1.default(`Requesting a credential from '${this.manifest.endpoint}' timed out`)), 30000 // 30s
);
const fetchOptions = {
method: 'POST',
body: serializedCredential,
headers: {
'Content-Type': 'application/json',
'Content-Length': serializedCredential.length
}
};
// Now call the actual fetch with the updated options
const response = await fetch(this.manifest.endpoint, fetchOptions);
// Got a response so clear the timer
clearTimeout(timer);
if (!response.ok) {
const error = new UserAgentError_1.default(`Failed to request a credential from the issuer '${this.identifier.id}.'`);
reject(error);
return;
}
const credential = await response.json();
resolve(credential);
});
}
/**
* Validate inputCredential with manifest and process and exchange inputCredential wuth Data Handler
* @param inputCredential The Self-Issued Credential that with required claims.
* @param _dataHandler Data handler for process and exchanging credentials.
*/
async handleCredentialRequest(inputCredential, dataHandler) {
// Validate that credential matched credential manifest.
if (!this.validateCredential(inputCredential)) {
throw new UserAgentError_1.default(`Credential issued by '${inputCredential.issuedBy.id}' does not match credential manifest '${this.manifest.credential}'`);
}
return dataHandler.process(inputCredential);
}
/**
* Validate whether a credential is valid for the manifest.
* @param _inputCredential the Credential to validate against the credential manifest
*/
validateCredential(_inputCredential) {
return true;
}
}
exports.default = CredentialIssuer;
},{"../UserAgentError":5,"./CredentialManifest":8,"isomorphic-fetch":133}],8:[function(require,module,exports){
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
/**
* context for credentialManifest
*/
const context = 'https://identity.foundation/schemas/credentials';
/**
* type for credentialManifest
*/
const type = 'CredentialManifest';
/**
* Class defining methods and properties for a ClaimManifest object.
* based off of the CredentialManifest spec: {@link https://github.com/decentralized-identity/credential-manifest/blob/master/explainer.md}
*/
class CredentialManifest {
/**
* Constructs an instance of the CredentialManifest class from a well-formed credential manifest JSON object.
*/
constructor(credentialManifest) {
this.endpoint = credentialManifest.endpoint;
this.credential = credentialManifest.credential;
this.language = credentialManifest.language;
this.keeper = credentialManifest.keeper;
this.version = credentialManifest.version;
this.preconditions = credentialManifest.preconditions;
this.inputs = credentialManifest.inputs;
this.issuerOptions = credentialManifest.issuer_options;
}
/**
* Creates a new instance of the CredentialManifest class.
*/
static create(credential, endpoint, language, keeper, version, preconditions, inputs, issuerOptions) {
const manifest = {
'@context': context,
'@type': type,
'endpoint': endpoint,
'language': language,
'credential': credential,
'keeper': keeper,
'version': version,
'preconditions': preconditions,
'inputs': inputs,
'issuer_options': issuerOptions
};
return new CredentialManifest(manifest);
}
/**
* serializes the CredentialManifest to JSON.
*/
toJSON() {
return {
'@context': context,
'@type': type,
'endpoint': this.endpoint,
'credential': this.credential,
'preconditions': this.preconditions,
'inputs': this.inputs,
'issuer_options': this.issuerOptions
};
}
/**
* Get the keeper did of the CredentialManifest
*/
getKeeperDid() {
return this.keeper;
}
/**
* Get the input properties of the manifest
*/
getInputProperties() {
return this.inputs;
}
}
exports.default = CredentialManifest;
},{}],9:[function(require,module,exports){
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Implementation of an OpenID Connect
* self-issued id token.
* @implements ICredential
*/
class SelfIssuedCredential {
/**
* Constructs a new instance of a self-issued
* credential for the specified identifier.
* @param issuer of the credential.
* @param recipient either a string or identifier identifying the
* intended recipient of the credential.
*/
constructor(issuer, recipient) {
/**
* Array to hold claims to be included in the credential
*/
this.claims = [];
this.issuedBy = issuer;
this.issuedTo = recipient;
this.issuedAt = new Date(Date.now());
// Add the identifier as the did claim
this.addClaim({ name: 'did', value: issuer.id });
}
/**
* Adds the specified claim to the credential.
* @param claim claim to add to credential.
*/
addClaim(claim) {
// Add the claim to the credential
this.claims.push(claim);
}
}
exports.default = SelfIssuedCredential;
},{}],10:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* Base error class for the crypto.
*/
class CryptoError extends Error {
/**
* Create instance of @class CryptoProtocolError
* @param protocol name
* @param message for the error
*/
constructor(algorithm, message) {
super(message);
// NOTE: Extending 'Error' breaks prototype chain since TypeScript 2.1.
// The following line restores prototype chain.
Object.setPrototypeOf(this, new.target.prototype);
this.algorithm = algorithm;
}
}
exports.default = CryptoError;
},{}],11:[function(require,module,exports){
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
const SecretKey_1 = require("../keys/SecretKey");
/**
* Class defining methods and properties for a light KeyStore
*/
class KeyStoreInMemory {
constructor() {
this.store = new Map();
}
/**
* Returns the key associated with the specified
* key identifier.
* @param keyReference for which to return the key.
* @param [publicKeyOnly] True if only the public key is needed.
*/
get(keyReference, publicKeyOnly = true) {
return new Promise((resolve, reject) => {
if (this.store.has(keyReference)) {
const key = this.store.get(keyReference);
if (key instanceof SecretKey_1.default) {
return resolve(key);
}
if (publicKeyOnly) {
switch (key.kty.toLowerCase()) {
case 'ec':
case 'rsa':
return resolve(key.getPublicKey());
default:
throw new Error(`A secret does not has a public key`);
}
}
else {
resolve(key);
}
}
else {
reject(`${keyReference} not found`);
}
});
}
/**
* Lists all keys with their corresponding key ids
*/
list() {
const dictionary = new Map();
for (let [key, value] of this.store) {
if (value.kid) {
dictionary.set(key, value.kid);
}
}
return new Promise((resolve) => {
resolve(dictionary);
});
}
/**
* Saves the specified key to the key store using
* the key identifier.
* @param keyIdentifier for the key being saved.
* @param key being saved to the key store.
*/
save(keyIdentifier, key) {
console.log(this.store.toString() + keyIdentifier + key.toString());
this.store.set(keyIdentifier, key);
return new Promise((resolve) => {
resolve();
});
}
}
exports.default = KeyStoreInMemory;
},{"../keys/SecretKey":19}],12:[function(require,module,exports){
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Enum to define different protection formats
*/
var ProtectionFormat;
(function (ProtectionFormat) {
/**
* Format for a flat JSON signature
*/
ProtectionFormat["JwsFlatJson"] = "JwsFlatJson";
/**
* Format for a compact JSON signature
*/
ProtectionFormat["JwsCompactJson"] = "JwsCompactJson";
/**
* Format for a general JSON signature
*/
ProtectionFormat["JwsGeneralJson"] = "JwsGeneralJson";
/**
* Format for a flat JSON encryption
*/
ProtectionFormat["JweFlatJson"] = "JweFlatJson";
/**
* Format for a compact JSON encryption
*/
ProtectionFormat["JweCompactJson"] = "JweCompactJson";
/**
* Format for a general JSON encryption
*/
ProtectionFormat["JweGeneralJson"] = "JweGeneralJson";
})(ProtectionFormat = exports.ProtectionFormat || (exports.ProtectionFormat = {}));
},{}],13:[function(require,module,exports){
"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
const jose = require('node-jose');
/**
* JWK key operations
*/
var KeyOperation;
(function (KeyOperation) {
KeyOperation["Sign"] = "sign";
KeyOperation["Verify"] = "verify";
KeyOperation["Encrypt"] = "encrypt";
KeyOperation["Decrypt"] = "decrypt";
KeyOperation["WrapKey"] = "wrapKey";
KeyOperation["UnwrapKey"] = "unwrapKey";
KeyOperation["DeriveKey"] = "deriveKey";
KeyOperation["DeriveBits"] = "deriveBits";
})(KeyOperation = exports.KeyOperation || (exports.KeyOperation = {}));
/**
* Represents a Public Key in JWK format.
* @class
* @abstract
* @hideconstructor
*/
class JsonWebKey {
/**
* Create instance of @class JsonWebKey
*/
constructor(key) {
/**
* Key ID
*/
this.kid = '';
this.kty = key.kty;
this.kid = key.kid;
this.use = key.use;
this.key_ops = key.key_ops;
this.alg = key.alg;
}
}
exports.default = JsonWebKey;
},{"node-jose":420}],14:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const CryptoHelpers_1 = require("../utilities/CryptoHelpers");
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* Enumeration to model key types.
*/
var KeyType;
(function (KeyType) {
KeyType["Oct"] = "oct";
KeyType["EC"] = "EC";
KeyType["RSA"] = "RSA";
})(KeyType = exports.KeyType || (exports.KeyType = {}));
/**
* Factory class to create @enum KeyType objects
*/
class KeyTypeFactory {
/**
* Create the key type according to the selected algorithm.
* @param algorithm Web crypto compliant algorithm object
*/
static createViaWebCrypto(algorithm) {
switch (algorithm.name.toLowerCase()) {
case 'hmac':
return KeyType.Oct;
case 'ecdsa':
return KeyType.EC;
case 'ecdh':
return KeyType.EC;
case 'rsassa-pkcs1-v1_5':
return KeyType.RSA;
case 'rsa-oaep':
case 'rsa-oaep-256':
return KeyType.RSA;
default:
throw new Error(`The algorithm '${algorithm.name}' is not supported`);
}
}
/**
* Create the key use according to the selected algorithm.
* @param algorithm JWA algorithm constant
*/
static createViaJwa(algorithm) {
const alg = CryptoHelpers_1.default.jwaToWebCrypto(algorithm);
return KeyTypeFactory.createViaWebCrypto(alg);
}
}
exports.default = KeyTypeFactory;
},{"../utilities/CryptoHelpers":44}],15:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const CryptoHelpers_1 = require("../utilities/CryptoHelpers");
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/**
* Enumeration to model key use.
*/
var KeyUse;
(function (KeyUse) {
KeyUse["Encryption"] = "enc";
KeyUse["Signature"] = "sig";
})(KeyUse = exports.KeyUse || (exports.KeyUse = {}));
/**
* Factory class to create @enum KeyUse objects.
*/
class KeyUseFactory {
/**
* Create the key use according to the selected algorithm.
* @param algorithm Web crypto compliant algorithm object
*/
static createViaWebCrypto(algorithm) {
switch (algorithm.name.toLowerCase()) {
case 'hmac':
return KeyUse.Signature;
case 'ecdsa':
return KeyUse.Signature;
case 'ecdh':
return KeyUse.Encryption;
case 'rsassa-pkcs1-v1_5':
return KeyUse.Signature;
case 'rsa-oaep':
case 'rsa-oaep-256':
return KeyUse.Encryption;
default:
throw new Error(`The algorithm '${algorithm.name}' is not supported`);
}
}
/**
* Create the key use according to the selected algorithm.
* @param algorithm JWA algorithm constant
*/
static createViaJwa(algorithm) {
const alg = CryptoHelpers_1.default.jwaToWebCrypto(algorithm);
return KeyUseFactory.createViaWebCrypto(alg);
}
}
exports.default = KeyUseFactory;
},{"../utilities/CryptoHelpers":44}],16:[function(require,module,exports){
(function (Buffer){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const KeyTypeFactory_1 = require("./KeyTypeFactory");
const W3cCryptoApiConstants_1 = require("../utilities/W3cCryptoApiConstants");
const EcPairwiseKey_1 = require("./ec/EcPairwiseKey");
const CryptoError_1 = require("../CryptoError");
const RsaPairwiseKey_1 = require("./rsa/RsaPairwiseKey");
const JoseConstants_1 = require("../protocols/jose/JoseConstants");
/**
* Class to model pairwise keys
*/
class PairwiseKey {
/**
* Create an instance of @class PairwiseKey.
* @param cryptoFactory The crypto factory object.
*/
constructor(cryptoFactory) {
// Set of master keys for the different persona's
this.masterKeys = new Map();
this.cryptoFactory = cryptoFactory;
}
/**
* Generate a pairwise key for the specified algorithms
* @param algorithm for the key
* @param seedReference Reference to the seed
* @param personaId Id for th