Skip to content
Snippets Groups Projects
Commit ebb39da2 authored by Steffen Schulze's avatar Steffen Schulze
Browse files

Merge branch 'custom-service-endpoints' into 'main'

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

See merge request eclipse/xfsc/ocm/ocm-engine!31
parents 62e6bdf0 09cd2fdc
No related branches found
No related tags found
No related merge requests found
...@@ -19,6 +19,11 @@ export class EventDidsResolve extends BaseEvent<DidDocument> { ...@@ -19,6 +19,11 @@ export class EventDidsResolve extends BaseEvent<DidDocument> {
export type EventDidsRegisterIndyFromSeedInput = BaseEventInput<{ export type EventDidsRegisterIndyFromSeedInput = BaseEventInput<{
seed: string; seed: string;
services?: Array<{
identifier: string;
url: string;
type: string;
}>;
}>; }>;
export class EventDidsRegisterIndyFromSeed extends BaseEvent<Array<string>> { export class EventDidsRegisterIndyFromSeed extends BaseEvent<Array<string>> {
public static token = 'dids.register.indy.fromSeed'; public static token = 'dids.register.indy.fromSeed';
......
...@@ -32,6 +32,7 @@ import { ...@@ -32,6 +32,7 @@ import {
} from '@aries-framework/core'; } from '@aries-framework/core';
import { import {
IndyVdrAnonCredsRegistry, IndyVdrAnonCredsRegistry,
IndyVdrIndyDidRegistrar,
IndyVdrIndyDidResolver, IndyVdrIndyDidResolver,
IndyVdrModule, IndyVdrModule,
IndyVdrSovDidResolver, IndyVdrSovDidResolver,
...@@ -145,6 +146,7 @@ export class AgentService implements OnApplicationShutdown { ...@@ -145,6 +146,7 @@ export class AgentService implements OnApplicationShutdown {
new PeerDidRegistrar(), new PeerDidRegistrar(),
new KeyDidRegistrar(), new KeyDidRegistrar(),
new JwkDidRegistrar(), 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 { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
...@@ -14,7 +29,10 @@ export class DidsService { ...@@ -14,7 +29,10 @@ export class DidsService {
private configService: ConfigService, 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) => { return this.withTenantService.invoke(tenantId, async (t) => {
const { const {
didDocument, didDocument,
...@@ -36,32 +54,80 @@ export class DidsService { ...@@ -36,32 +54,80 @@ export class DidsService {
public async registerDidIndyFromSeed({ public async registerDidIndyFromSeed({
tenantId, tenantId,
seed, seed,
}: { services,
tenantId: string; }: EventDidsRegisterIndyFromSeedInput): Promise<
seed: string; EventDidsRegisterIndyFromSeed['data']
}): Promise<Array<string>> { > {
const ledgerIds = this.configService.get('agent.ledgerIds'); 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, ledgerIds,
seed, seed: publicDidSeed,
}); });
for (const publicDidResponse of registeredPublicDidResponses) { const { publicKey, publicKeyBase58 } = await this.withTenantService.invoke(
await this.withTenantService.invoke(tenantId, (t) => tenantId,
t.dids.import({ async (t) =>
overwrite: true, t.wallet.createKey({
did: publicDidResponse.did, privateKey: TypedArrayEncoder.fromString(seed),
privateKeys: [ keyType: KeyType.Ed25519,
{
keyType: KeyType.Ed25519,
privateKey: TypedArrayEncoder.fromString(seed),
},
],
}), }),
); );
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 = { ...@@ -11,14 +11,17 @@ type RegisterPublicDidOptions = {
}; };
type LedgerRegistrationBody = { type LedgerRegistrationBody = {
role?: 'ENDORSER'; role: 'ENDORSER';
seed: string; seed?: string;
did?: string;
verkey?: string;
}; };
type RegisterPublicDidResponse = { type RegisterPublicDidResponse = {
seed: string; seed: string;
did: string; did: string;
verkey: string; verkey: string;
namespace: string;
}; };
export const registerPublicDids = async ({ export const registerPublicDids = async ({
...@@ -45,7 +48,7 @@ export const registerPublicDids = async ({ ...@@ -45,7 +48,7 @@ export const registerPublicDids = async ({
if (res.data) { if (res.data) {
logger.info('Agent DID registered.'); logger.info('Agent DID registered.');
res.data.did = `did:indy:${ledgerNamespace}:${res.data.did}`; res.data.did = `did:indy:${ledgerNamespace}:${res.data.did}`;
responses.push(res.data); responses.push({ ...res.data, namespace: ledgerNamespace });
} else { } else {
throw new Error('No data was returned from the ledger request'); throw new Error('No data was returned from the ledger request');
} }
......
...@@ -8,6 +8,7 @@ import type { ...@@ -8,6 +8,7 @@ import type {
import { ClientsModule, Transport } from '@nestjs/microservices'; import { ClientsModule, Transport } from '@nestjs/microservices';
import { Test } from '@nestjs/testing'; import { Test } from '@nestjs/testing';
import { EventDidsRegisterIndyFromSeed, EventDidsResolve } from '@ocm/shared'; import { EventDidsRegisterIndyFromSeed, EventDidsResolve } from '@ocm/shared';
import { randomBytes } from 'crypto';
import { firstValueFrom } from 'rxjs'; import { firstValueFrom } from 'rxjs';
import { AgentModule } from '../src/agent/agent.module.js'; import { AgentModule } from '../src/agent/agent.module.js';
...@@ -58,16 +59,23 @@ describe('Dids', () => { ...@@ -58,16 +59,23 @@ describe('Dids', () => {
EventDidsRegisterIndyFromSeed, EventDidsRegisterIndyFromSeed,
EventDidsRegisterIndyFromSeedInput EventDidsRegisterIndyFromSeedInput
>(EventDidsRegisterIndyFromSeed.token, { >(EventDidsRegisterIndyFromSeed.token, {
seed: '12312367897123300000000000000000', seed: randomBytes(16).toString('hex'),
tenantId, tenantId,
services: [
{
url: 'https://example.org',
type: 'endpoint',
identifier: 'endpoint',
},
],
}); });
const response = await firstValueFrom(response$); const response = await firstValueFrom(response$);
const eventInstance = EventDidsRegisterIndyFromSeed.fromEvent(response); const eventInstance = EventDidsRegisterIndyFromSeed.fromEvent(response);
expect(eventInstance.instance).toMatchObject( expect(
expect.arrayContaining(['did:indy:bcovrin:test:9MMeff63VnCpogD2FWfKnJ']), eventInstance.instance[0].startsWith('did:indy:bcovrin:test:'),
); ).toBeTruthy();
}); });
it(EventDidsResolve.token, async () => { 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