Skip to content
Snippets Groups Projects
Commit 09cd2fdc authored by Berend Sliedrecht's avatar Berend Sliedrecht
Browse files

feat(ssi): register custom didcomm endpoints on the indy did


Signed-off-by: default avatarBerend Sliedrecht <berend@animo.id>
parent ae8024d2
No related branches found
No related tags found
No related merge requests found
......@@ -19,6 +19,11 @@ export class EventDidsResolve extends BaseEvent<DidDocument> {
export type EventDidsRegisterIndyFromSeedInput = BaseEventInput<{
seed: string;
services?: Array<{
identifier: string;
url: string;
type: string;
}>;
}>;
export class EventDidsRegisterIndyFromSeed extends BaseEvent<Array<string>> {
public static token = 'dids.register.indy.fromSeed';
......
......@@ -28,6 +28,7 @@ import {
} from '@aries-framework/core';
import {
IndyVdrAnonCredsRegistry,
IndyVdrIndyDidRegistrar,
IndyVdrIndyDidResolver,
IndyVdrModule,
IndyVdrSovDidResolver,
......@@ -128,6 +129,7 @@ export class AgentService implements OnApplicationShutdown {
new PeerDidRegistrar(),
new KeyDidRegistrar(),
new JwkDidRegistrar(),
new IndyVdrIndyDidRegistrar()
],
}),
......
import type { EventDidsResolveInput } from '@ocm/shared';
import type { LEDGERS } from '../../config/ledger.js';
import type {
IndyVdrDidCreateOptions,
IndyVdrDidCreateResult,
} from '@aries-framework/indy-vdr';
import type {
EventDidsRegisterIndyFromSeed,
EventDidsRegisterIndyFromSeedInput,
EventDidsResolve,
EventDidsResolveInput,
} from '@ocm/shared';
import { KeyType, TypedArrayEncoder } from '@aries-framework/core';
import {
DidDocumentService,
Hasher,
KeyType,
TypedArrayEncoder,
} from '@aries-framework/core';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
......@@ -14,7 +29,10 @@ export class DidsService {
private configService: ConfigService,
) {}
public async resolve({ did, tenantId }: EventDidsResolveInput) {
public async resolve({
did,
tenantId,
}: EventDidsResolveInput): Promise<EventDidsResolve['data']> {
return this.withTenantService.invoke(tenantId, async (t) => {
const {
didDocument,
......@@ -36,32 +54,80 @@ export class DidsService {
public async registerDidIndyFromSeed({
tenantId,
seed,
}: {
tenantId: string;
seed: string;
}): Promise<Array<string>> {
const ledgerIds = this.configService.get('agent.ledgerIds');
services,
}: EventDidsRegisterIndyFromSeedInput): Promise<
EventDidsRegisterIndyFromSeed['data']
> {
const dids: Array<string> = [];
const ledgerIds = this.configService.get('agent.ledgerIds') as Array<
keyof typeof LEDGERS
>;
const publicDidSeed = this.configService.get(
'agent.publicDidSeed',
) as string;
const registeredPublicDidResponses = await registerPublicDids({
const publicDids = await registerPublicDids({
ledgerIds,
seed,
seed: publicDidSeed,
});
for (const publicDidResponse of registeredPublicDidResponses) {
await this.withTenantService.invoke(tenantId, (t) =>
t.dids.import({
overwrite: true,
did: publicDidResponse.did,
privateKeys: [
{
keyType: KeyType.Ed25519,
privateKey: TypedArrayEncoder.fromString(seed),
},
],
const { publicKey, publicKeyBase58 } = await this.withTenantService.invoke(
tenantId,
async (t) =>
t.wallet.createKey({
privateKey: TypedArrayEncoder.fromString(seed),
keyType: KeyType.Ed25519,
}),
);
);
await this.withTenantService.invoke(tenantId, async (t) =>
t.wallet.createKey({
privateKey: TypedArrayEncoder.fromString(publicDidSeed),
keyType: KeyType.Ed25519,
}),
);
const buffer = Hasher.hash(publicKey, 'sha2-256');
const id = TypedArrayEncoder.toBase58(buffer.slice(0, 16));
const verkey = publicKeyBase58;
for (const publicDid of publicDids) {
const did = `did:indy:${publicDid.namespace}:${id}`;
const didDocumentServices: Array<DidDocumentService> | undefined =
services?.map(
(s) =>
new DidDocumentService({
id: `${did}#${s.identifier}`,
type: s.type,
serviceEndpoint: s.url,
}),
);
await this.withTenantService.invoke(tenantId, async (t) => {
const result = (await t.dids.create<IndyVdrDidCreateOptions>({
did,
options: {
verkey,
endorserMode: 'internal',
endorserDid: publicDid.did,
services: didDocumentServices,
useEndpointAttrib: true,
},
})) as IndyVdrDidCreateResult;
if (result.didState.state !== 'finished') {
throw Error(
`An error occurred while trying to register the did: '${did}'. Result: ${JSON.stringify(result)}`,
);
}
dids.push(result.didState.did);
});
}
return registeredPublicDidResponses.map((r) => r.did);
return dids;
}
}
......@@ -11,14 +11,17 @@ type RegisterPublicDidOptions = {
};
type LedgerRegistrationBody = {
role?: 'ENDORSER';
seed: string;
role: 'ENDORSER';
seed?: string;
did?: string;
verkey?: string;
};
type RegisterPublicDidResponse = {
seed: string;
did: string;
verkey: string;
namespace: string;
};
export const registerPublicDids = async ({
......@@ -45,7 +48,7 @@ export const registerPublicDids = async ({
if (res.data) {
logger.info('Agent DID registered.');
res.data.did = `did:indy:${ledgerNamespace}:${res.data.did}`;
responses.push(res.data);
responses.push({ ...res.data, namespace: ledgerNamespace });
} else {
throw new Error('No data was returned from the ledger request');
}
......
......@@ -8,6 +8,7 @@ import type {
import { ClientsModule, Transport } from '@nestjs/microservices';
import { Test } from '@nestjs/testing';
import { EventDidsRegisterIndyFromSeed, EventDidsResolve } from '@ocm/shared';
import { randomBytes } from 'crypto';
import { firstValueFrom } from 'rxjs';
import { AgentModule } from '../src/agent/agent.module.js';
......@@ -58,16 +59,23 @@ describe('Dids', () => {
EventDidsRegisterIndyFromSeed,
EventDidsRegisterIndyFromSeedInput
>(EventDidsRegisterIndyFromSeed.token, {
seed: '12312367897123300000000000000000',
seed: randomBytes(16).toString('hex'),
tenantId,
services: [
{
url: 'https://example.org',
type: 'endpoint',
identifier: 'endpoint',
},
],
});
const response = await firstValueFrom(response$);
const eventInstance = EventDidsRegisterIndyFromSeed.fromEvent(response);
expect(eventInstance.instance).toMatchObject(
expect.arrayContaining(['did:indy:bcovrin:test:9MMeff63VnCpogD2FWfKnJ']),
);
expect(
eventInstance.instance[0].startsWith('did:indy:bcovrin:test:'),
).toBeTruthy();
});
it(EventDidsResolve.token, async () => {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment