@dwn-protocol/id-sdk
Version:
SDK for accessing the features and capabilities
255 lines (223 loc) • 7.65 kB
text/typescript
import type {
IDRpc,
DidRequest,
VcResponse,
DidResponse,
DwnResponse,
SyncManager,
AppDataStore,
SendVcRequest,
SendDwnRequest,
ProcessVcRequest,
IDManagedAgent,
ProcessDwnRequest,
} from '../agent/index.js';
import { LevelStore } from '../common/index.js';
import { EdDsaAlgorithm } from '../crypto/index.js';
import { DidIonMethod, DidKeyMethod, DidResolver } from '../dids/index.js';
import {
LocalKms,
DidManager,
DwnManager,
KeyManager,
DidStoreDwn,
KeyStoreDwn,
AppDataVault,
IDRpcClient,
IdentityManager,
IdentityStoreDwn,
SyncManagerLevel,
PrivateKeyStoreDwn,
cryptoToPortableKeyPair,
} from '../agent/index.js';
export type IDProxyAgentOptions = {
agentDid: string;
appData: AppDataStore;
didManager: DidManager;
didResolver: DidResolver;
dwnManager: DwnManager;
identityManager: IdentityManager;
keyManager: KeyManager;
rpcClient: IDRpc;
syncManager: SyncManager;
}
export class IDProxyAgent implements IDManagedAgent {
agentDid: string;
appData: AppDataStore;
didManager: DidManager;
didResolver: DidResolver;
dwnManager: DwnManager;
identityManager: IdentityManager;
keyManager: KeyManager;
rpcClient: IDRpc;
syncManager: SyncManager;
constructor(options: IDProxyAgentOptions) {
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<IDProxyAgentOptions> = {}): Promise<IDProxyAgent> {
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/VAULT')
});
}
if (didManager === undefined) {
// A custom DidManager implementation was not specified, so
// instantiate a default with in-memory store.
didManager = new DidManager({
didMethods : [DidIonMethod, DidKeyMethod],
store : new DidStoreDwn()
});
}
if (didResolver === undefined) {
// A custom DidManager implementation was not specified, so
// instantiate a default with in-memory store.
didResolver = new DidResolver({ 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 store.
identityManager = new IdentityManager({
store: new IdentityStoreDwn()
});
}
if (keyManager === undefined) {
// A custom KeyManager implementation was not specified, so
// instantiate a default with KMSs.
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 Identity Agent.
const agent = new IDProxyAgent({
agentDid,
appData,
didManager,
didResolver,
dwnManager,
keyManager,
identityManager,
rpcClient,
syncManager
});
return agent;
}
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 Identity 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 Identity Agent.
const agentKeyPair = await new EdDsaAlgorithm().generateKey({
algorithm : { name: 'EdDSA', namedCurve: 'Ed25519' },
extractable : true,
keyUsages : ['sign', 'verify']
});
/** Initialize the AppDataStore with the Identity 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> {
throw new Error('Not implemented');
}
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 Identity Agent's root did:key identifier.
this.agentDid = await this.appData.getDid();
// 3. Import the Identity 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 });
}
}