UNPKG

@microsoft/useragent-sdk

Version:

SDK for building decentralized identity wallets and enterprise agents.

200 lines (174 loc) 7.58 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { AuthenticationReference, ServiceReference, IdentifierDocumentPublicKey } from './types'; import UserAgentOptions from './UserAgentOptions'; import Identifier from './Identifier'; import UserAgentError from './UserAgentError'; import HostServiceEndpoint from './serviceEndpoints/HostServiceEndpoint'; import UserServiceEndpoint from './serviceEndpoints/UserServiceEndpoint'; import PublicKey from './crypto/keys/PublicKey'; const cloneDeep = require('lodash/fp/cloneDeep'); /** * Class for creating and managing identifiers, * retrieving identifier documents. */ export default class IdentifierDocument { /** * The identifier the document represents. */ public id: string; /** * The date the document was created. */ public created: Date | undefined; /** * Array of service entries added to the document. */ public publicKeys: IdentifierDocumentPublicKey[] = []; /** * Array of authentication entries added to the document. */ public authenticationReferences: AuthenticationReference[] = []; /** * Array of service entries added to the document. */ public serviceReferences: ServiceReference[] = []; /** * 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: any) { // 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: any) => { if (serviceRef.serviceEndpoint['@type'] === 'HostServiceEndpoint') { serviceRef.serviceEndpoint = HostServiceEndpoint.fromJSON(serviceRef.serviceEndpoint); } else { serviceRef.serviceEndpoint = UserServiceEndpoint.fromJSON(serviceRef.serviceEndpoint); } }); } } /** * Creates a new instance of an identifier document using the * provided public keys. * @param publicKeys to include in the document. */ public static create (id: string, publicKeys: IdentifierDocumentPublicKey[]): IdentifierDocument { 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 */ public static async createAndGenerateId (idBase: string, publicKeys: IdentifierDocumentPublicKey[], options: UserAgentOptions): Promise<IdentifierDocument> { const document = IdentifierDocument.create(idBase, publicKeys); const identifier: 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. */ public addAuthenticationReference (authenticationReference: AuthenticationReference) { this.authenticationReferences.push(authenticationReference); } /** * Adds a service reference to the document. * @param serviceReference to add to the document. */ public addServiceReference (serviceReference: ServiceReference) { this.serviceReferences.push(serviceReference); } /** * Get Hub Instances from Identity Service Reference. */ public getHubInstances () { const filteredServiceReferences = this.serviceReferences.filter(reference => reference.type === 'IdentityHub'); if (filteredServiceReferences.length === 0 || filteredServiceReferences[0].serviceEndpoint.type !== 'UserServiceEndpoint') { throw new UserAgentError(`No Hub Instances for ${this.id}`); } const serviceEndpoint = <UserServiceEndpoint> filteredServiceReferences[0].serviceEndpoint; return serviceEndpoint.instances; } /** * Get Hub Locations from Identity Service Reference. */ public getHubLocations () { const filteredServiceReferences = this.serviceReferences.filter(reference => reference.type === 'IdentityHub'); if (filteredServiceReferences.length === 0 || filteredServiceReferences[0].serviceEndpoint.type !== 'HostServiceEndpoint') { throw new UserAgentError(`No Hub Locations for ${this.id}`); } const serviceEndpoint = <HostServiceEndpoint> filteredServiceReferences[0].serviceEndpoint; return serviceEndpoint.locations; } public getPublicKeysFromDocument(): PublicKey[] { return this.publicKeys.map(key => key.publicKeyJwk); } /** * Used to control the the properties that are * output by JSON.parse. */ public static fromJSON (obj: any): IdentifierDocument { const document = Object.create(IdentifierDocument.prototype); const result = Object.assign(document, obj, { publicKeys: (<any> obj).publicKey }); delete result.publicKey; return new IdentifierDocument(document); } /** * Used to control the the properties that are * output by JSON.stringify. */ public toJSON (): any { // 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: ServiceReference) => { if (serviceRef.serviceEndpoint['type'] === 'HostServiceEndpoint') { serviceRef.serviceEndpoint = (<HostServiceEndpoint> serviceRef.serviceEndpoint).toJSON(); } else { serviceRef.serviceEndpoint = (<UserServiceEndpoint> 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; } }