@dcxp/root
Version:
DCX: Decentralized Credential Exchange. DWN protocol for verifiable credential exchange.
243 lines (212 loc) • 7.59 kB
text/typescript
import {
AgentCryptoApi,
AgentDidApi,
AgentDwnApi,
AgentIdentityApi,
AgentKeyManager,
AgentSyncApi,
DidInterface,
DidRequest,
DidResponse,
DwnDidStore,
DwnIdentityStore,
DwnInterface,
DwnKeyStore,
DwnResponse,
LocalKeyManager,
ProcessDwnRequest,
ProcessVcRequest,
SendDwnRequest,
SendVcRequest,
SyncEngineLevel,
VcResponse,
Web5PlatformAgent,
Web5Rpc,
Web5RpcClient,
} from '@web5/agent';
import { LevelStore } from '@web5/common';
import { BearerDid, DidDht, DidJwk, DidResolverCacheLevel } from '@web5/dids';
import { AgentInitializeParams } from '@web5/user-agent';
import { DcxIdentityVault } from './index.js';
export type DcxAgentInitializeParams = {
/**
* The password used to secure the Agent vault.
*
* The password selected should be strong and securely managed to prevent unauthorized access.
*/
password: string;
/**
* An optional recovery phrase used to deterministically generate the cryptographic keys for the
* Agent vault.
*
* Supplying this phrase enables the vault's contents to be restored or replicated across devices.
* If omitted, a new phrase is generated, which should be securely recorded for future recovery needs.
*/
recoveryPhrase?: string;
dwnEndpoints: string[];
};
export type DcxAgentParams<TKeyManager extends AgentKeyManager = LocalKeyManager> = {
/** Optional. The Decentralized Identifier (DID) representing this Web5 User Agent. */
agentDid?: BearerDid;
/** Encrypted vault used for managing the Agent's DID and associated keys. */
agentVault: DcxIdentityVault;
/** Provides cryptographic capabilties like signing, encryption, hashing and key derivation. */
cryptoApi: AgentCryptoApi;
/** Specifies the local path to be used by the Agent's persistent data stores. */
dataPath?: string;
/** Facilitates DID operations including create, update, and resolve. */
didApi: AgentDidApi<TKeyManager>;
/** Facilitates DWN operations including processing and sending requests. */
dwnApi: AgentDwnApi;
/** Facilitates decentralized Identity operations including create, import, and export. */
identityApi: AgentIdentityApi<TKeyManager>;
/** Responsible for securely managing the cryptographic keys of the agent. */
keyManager: TKeyManager;
/** Remote procedure call (RPC) client used to communicate with other Web5 services. */
rpcClient: Web5Rpc;
/** Facilitates data synchronization of DWN records between nodes. */
syncApi: AgentSyncApi;
};
export class DcxAgent<TKeyManager extends AgentKeyManager = LocalKeyManager>
implements Web5PlatformAgent<TKeyManager>
{
public crypto: AgentCryptoApi;
public did: AgentDidApi<TKeyManager>;
public dwn: AgentDwnApi;
public identity: AgentIdentityApi<TKeyManager>;
public keyManager: TKeyManager;
public rpc: Web5Rpc;
public sync: AgentSyncApi;
public vault: DcxIdentityVault;
private _agentDid?: BearerDid;
constructor(params: DcxAgentParams<TKeyManager>) {
this._agentDid = params.agentDid;
this.crypto = params.cryptoApi;
this.did = params.didApi;
this.dwn = params.dwnApi;
this.identity = params.identityApi;
this.keyManager = params.keyManager;
this.rpc = params.rpcClient;
this.sync = params.syncApi;
this.vault = params.agentVault;
// Set this agent to be the default agent.
this.did.agent = this;
this.dwn.agent = this;
this.identity.agent = this;
this.keyManager.agent = this;
this.sync.agent = this;
}
get agentDid(): BearerDid {
if (this._agentDid === undefined) {
throw new Error(
'DcxAgent: The "agentDid" property is not set. Ensure the agent is properly ' +
'initialized and a DID is assigned.',
);
}
return this._agentDid;
}
set agentDid(did: BearerDid) {
this._agentDid = did;
}
/**
* If any of the required agent components are not provided, instantiate default implementations.
*/
public static async create({
dataPath = 'DATA/DCX/AGENT',
agentDid,
agentVault,
cryptoApi,
didApi,
dwnApi,
identityApi,
keyManager,
rpcClient,
syncApi,
}: Partial<DcxAgentParams> = {}): Promise<DcxAgent> {
agentVault ??= new DcxIdentityVault({
keyDerivationWorkFactor : 210_000,
store : new LevelStore<string, string>({ location: `${dataPath}/VAULT_STORE` }),
});
cryptoApi ??= new AgentCryptoApi();
didApi ??= new AgentDidApi({
didMethods : [DidDht, DidJwk],
resolverCache : new DidResolverCacheLevel({ location: `${dataPath}/DID_RESOLVERCACHE` }),
store : new DwnDidStore(),
});
dwnApi ??= new AgentDwnApi({
dwn: await AgentDwnApi.createDwn({ dataPath, didResolver: didApi }),
});
identityApi ??= new AgentIdentityApi({ store: new DwnIdentityStore() });
keyManager ??= new LocalKeyManager({ keyStore: new DwnKeyStore() });
rpcClient ??= new Web5RpcClient();
syncApi ??= new AgentSyncApi({ syncEngine: new SyncEngineLevel({ dataPath }) });
// Instantiate the Agent using the provided or default components.
return new DcxAgent({
agentDid,
agentVault,
cryptoApi,
didApi,
dwnApi,
keyManager,
identityApi,
rpcClient,
syncApi,
});
}
public async firstLaunch(): Promise<boolean> {
// Check whether data vault is already initialize
return (await this.vault.isInitialized()) === false;
}
/**
* Initializes the User Agent with a password, and optionally a recovery phrase.
*
* This method is typically called once, the first time the Agent is launched, and is responsible
* for setting up the agent's operational environment, cryptographic key material, and readiness
* for processing Web5 requests.
*
* The password is used to secure the Agent vault, and the recovery phrase is used to derive the
* cryptographic keys for the vault. If a recovery phrase is not provided, a new recovery phrase
* will be generated and returned. The password should be chosen and entered by the end-user.
*/
public async initialize({
password,
recoveryPhrase,
dwnEndpoints,
}: DcxAgentInitializeParams): Promise<string> {
// Initialize the Agent vault.
recoveryPhrase = await this.vault.initialize({ password, recoveryPhrase, dwnEndpoints });
return recoveryPhrase;
}
async processDidRequest<T extends DidInterface>(request: DidRequest<T>): Promise<DidResponse<T>> {
return this.did.processRequest(request);
}
public async processDwnRequest<T extends DwnInterface>(
request: ProcessDwnRequest<T>,
): Promise<DwnResponse<T>> {
return this.dwn.processRequest(request);
}
public async processVcRequest(_request: ProcessVcRequest): Promise<VcResponse> {
throw new Error('Not implemented');
}
public async sendDidRequest<T extends DidInterface>(
_request: DidRequest<T>,
): Promise<DidResponse<T>> {
throw new Error('Not implemented');
}
public async sendDwnRequest<T extends DwnInterface>(
request: SendDwnRequest<T>,
): Promise<DwnResponse<T>> {
return this.dwn.sendRequest(request);
}
public async sendVcRequest(_request: SendVcRequest): Promise<VcResponse> {
throw new Error('Not implemented');
}
public async start({ password }: AgentInitializeParams): Promise<void> {
// If the Agent vault is locked, unlock it.
if (this.vault.isLocked()) {
await this.vault.unlock({ password });
}
// Set the Agent's DID.
this.agentDid = await this.vault.getDid();
}
}