UNPKG

@dwn-protocol/id-sdk

Version:

SDK for accessing the features and capabilities

277 lines (242 loc) 8.33 kB
import type { IDRpc, DidRequest, VcResponse, DidResponse, DwnResponse, SyncManager, AppDataStore, SendVcRequest, SendDwnRequest, ProcessVcRequest, IDManagedAgent, ProcessDwnRequest, } from '../agent/index.js'; // import { DateSort, DataStream } from '@dwn-protocol/id'; // import { DwnApi } from '../dwn-api.js'; import { LevelStore } from '../common/index.js'; import { EdDsaAlgorithm } from '../crypto/index.js'; import { DidIonMethod, DidKeyMethod, DidResolverCacheLevel, DidResolver } from '../dids/index.js'; import { LocalKms, DidManager, DwnManager, KeyManager, DidStoreDwn, KeyStoreDwn, AppDataVault, IDRpcClient, IdentityManager, IdentityStoreDwn, SyncManagerLevel, PrivateKeyStoreDwn, cryptoToPortableKeyPair, DidMessage, } from '../agent/index.js'; export type IDUserAgentOptions = { agentDid: string; appData: AppDataStore; didManager: DidManager; didResolver: DidResolver; dwnManager: DwnManager; identityManager: IdentityManager; keyManager: KeyManager; rpcClient: IDRpc; syncManager: SyncManager; } let connected: boolean = false; export class IDUserAgent implements IDManagedAgent { agentDid: string; appData: AppDataStore; didManager: DidManager; didResolver: DidResolver; dwnManager: DwnManager; identityManager: IdentityManager; keyManager: KeyManager; rpcClient: IDRpc; syncManager: SyncManager; constructor(options: IDUserAgentOptions) { this.agentDid = options.agentDid; this.appData = options.appData; this.keyManager = options.keyManager; this.didManager = options.didManager; this.didResolver = options.didResolver; this.dwnManager = options.dwnManager; this.identityManager = options.identityManager; this.rpcClient = options.rpcClient; this.syncManager = options.syncManager; // Set this agent to be the default agent. this.didManager.agent = this; this.dwnManager.agent = this; this.identityManager.agent = this; this.keyManager.agent = this; this.syncManager.agent = this; } static async create(options: Partial<IDUserAgentOptions> = {}): Promise<IDUserAgent> { let { agentDid, appData, didManager, didResolver, dwnManager, identityManager, keyManager, rpcClient, syncManager } = options; if (agentDid === undefined) { // An Agent DID was not specified, so set to empty string. agentDid = ''; } if (appData === undefined) { /** A custom AppDataStore implementation was not specified, so * instantiate a LevelDB backed secure AppDataVault. */ appData = new AppDataVault({ store: new LevelStore('data/AGENT/APPDATA') }); } if (didManager === undefined) { /** A custom DidManager implementation was not specified, so * instantiate a default that uses a DWN-backed store. */ didManager = new DidManager({ didMethods : [DidIonMethod, DidKeyMethod], store : new DidStoreDwn() }); } if (didResolver === undefined) { /** A custom DidManager implementation was not specified, so * instantiate a default that uses a DWN-backed store and * LevelDB-backed resolution cache. */ didResolver = new DidResolver({ cache : new DidResolverCacheLevel(), didResolvers : [DidIonMethod, DidKeyMethod] }); } if (dwnManager === undefined) { /** A custom DwnManager implementation was not specified, so * instantiate a default. */ dwnManager = await DwnManager.create({ didResolver }); } if (identityManager === undefined) { /** A custom IdentityManager implementation was not specified, so * instantiate a default that uses a DWN-backed store. */ identityManager = new IdentityManager({ store: new IdentityStoreDwn() }); } if (keyManager === undefined) { /** A custom KeyManager implementation was not specified, so * instantiate a default with KMSs that use a DWN-backed store. */ const localKmsDwn = new LocalKms({ kmsName : 'local', keyStore : new KeyStoreDwn({ schema: 'https://identity.foundation/schemas/dwn/kms-key' }), privateKeyStore : new PrivateKeyStoreDwn() }); const localKmsMemory = new LocalKms({ kmsName: 'memory' }); keyManager = new KeyManager({ kms: { local : localKmsDwn, memory : localKmsMemory }, store: new KeyStoreDwn({ schema: 'https://identity.foundation/schemas/dwn/managed-key' }) }); } if (rpcClient === undefined) { // A custom RPC Client implementation was not specified, so // instantiate a default. rpcClient = new IDRpcClient(); } if (syncManager === undefined) { // A custom SyncManager implementation was not specified, so // instantiate a LevelDB-backed default. syncManager = new SyncManagerLevel(); } // Instantiate the Agent. const agent = new IDUserAgent({ agentDid, appData, didManager, didResolver, dwnManager, keyManager, identityManager, rpcClient, syncManager }); // connected = false; return agent; } static isConnected(): boolean { return connected; } async firstLaunch(): Promise<boolean> { // Check whether data vault is already initialized. const { initialized } = await this.appData.getStatus(); return initialized === false; } /** Executed once the first time the Agent is launched. * The passphrase should be input by the end-user. */ async initialize(options: { passphrase: string }) { const { passphrase } = options; // Generate an Ed25519 key pair for the Agent. const agentKeyPair = await new EdDsaAlgorithm().generateKey({ algorithm : { name: 'EdDSA', namedCurve: 'Ed25519' }, extractable : true, keyUsages : ['sign', 'verify'] }); /** Initialize the AppDataStore with the Agent's * private key and passphrase, which also unlocks the data vault. */ await this.appData.initialize({ passphrase : passphrase, keyPair : agentKeyPair, }); } async processDidRequest(request: DidRequest): Promise<DidResponse> { switch (request.messageType) { case DidMessage.Resolve: { const { didUrl, resolutionOptions } = request.messageOptions; const result = await this.didResolver.resolve(didUrl, resolutionOptions); return { result }; } default: { return this.didManager.processRequest(request); } } } async processDwnRequest(request: ProcessDwnRequest): Promise<DwnResponse> { return this.dwnManager.processRequest(request); } async processVcRequest(_request: ProcessVcRequest): Promise<VcResponse> { throw new Error('Not implemented'); } async sendDidRequest(_request: DidRequest): Promise<DidResponse> { throw new Error('Not implemented'); } async sendDwnRequest(request: SendDwnRequest): Promise<DwnResponse> { return this.dwnManager.sendRequest(request); } async sendVcRequest(_request: SendVcRequest): Promise<VcResponse> { throw new Error('Not implemented'); } async start(options: { passphrase: string }) { const { passphrase } = options; if (await this.firstLaunch()) { // 1A. Agent's first launch so initialize. await this.initialize({ passphrase }); } else { // 1B. Agent was previously initialized. // Unlock the data vault and cache the vault unlock key (VUK) in memory. await this.appData.unlock({ passphrase }); } // 2. Set the Agent's root did:key identifier. this.agentDid = await this.appData.getDid(); // 3. Import the Agent's private key into the KeyManager. const defaultSigningKey = cryptoToPortableKeyPair({ cryptoKeyPair: { privateKey : await this.appData.getPrivateKey(), publicKey : await this.appData.getPublicKey() }, keyData: { alias : await this.didManager.getDefaultSigningKey({ did: this.agentDid }), kms : 'memory' } }); // Import the Agent's signing key pair to the in-memory KMS key stores. await this.keyManager.setDefaultSigningKey({ key: defaultSigningKey }); } }