From 439244c0293db67bb4a8afdded0229660dd18aa4 Mon Sep 17 00:00:00 2001 From: Berend Sliedrecht <berend@animo.id> Date: Fri, 2 Feb 2024 10:57:15 +0100 Subject: [PATCH] feat: use credo-ts Signed-off-by: Berend Sliedrecht <berend@animo.id> --- apps/shared/src/events/credentialEvents.ts | 2 + .../src/agent/agent.service.ts | 4 + .../anoncredsCredentials.service.ts | 18 +- .../src/agent/dids/dids.service.ts | 2 +- .../test/revocation.e2e-spec.ts | 155 +++++++++++++++++- 5 files changed, 174 insertions(+), 7 deletions(-) diff --git a/apps/shared/src/events/credentialEvents.ts b/apps/shared/src/events/credentialEvents.ts index b71dd2c..49a495d 100644 --- a/apps/shared/src/events/credentialEvents.ts +++ b/apps/shared/src/events/credentialEvents.ts @@ -54,6 +54,8 @@ export type EventDidcommAnonCredsCredentialsOfferInput = BaseEventInput<{ connectionId: string; credentialDefinitionId: string; attributes: Array<{ name: string; value: string; mimeType?: string }>; + revocationRegistryDefinitionId?: string; + revocationRegistryIndex?: number; }>; export class EventDidcommAnonCredsCredentialsOffer extends BaseEvent<CredentialExchangeRecord> { public static token = 'didcomm.anoncreds.credentials.offer'; diff --git a/apps/ssi-abstraction/src/agent/agent.service.ts b/apps/ssi-abstraction/src/agent/agent.service.ts index d9792cb..9ac30b0 100644 --- a/apps/ssi-abstraction/src/agent/agent.service.ts +++ b/apps/ssi-abstraction/src/agent/agent.service.ts @@ -13,10 +13,12 @@ import { import { AskarModule } from '@credo-ts/askar'; import { Agent, + CacheModule, ConnectionsModule, CredentialsModule, DidsModule, HttpOutboundTransport, + InMemoryLruCache, JwkDidRegistrar, JwkDidResolver, KeyDidRegistrar, @@ -131,6 +133,8 @@ export class AgentService implements OnApplicationShutdown { ], }), + cache: new CacheModule({ cache: new InMemoryLruCache({ limit: 500 }) }), + anoncreds: new AnonCredsModule({ anoncreds, registries: [new IndyVdrAnonCredsRegistry()], diff --git a/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.service.ts b/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.service.ts index c994a5a..a00ce2c 100644 --- a/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.service.ts +++ b/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.service.ts @@ -141,6 +141,8 @@ export class AnonCredsCredentialsService { connectionId, credentialDefinitionId, attributes, + revocationRegistryIndex, + revocationRegistryDefinitionId, }: EventDidcommAnonCredsCredentialsOfferInput): Promise< EventDidcommAnonCredsCredentialsOffer['data'] > { @@ -149,7 +151,12 @@ export class AnonCredsCredentialsService { protocolVersion: 'v2', connectionId, credentialFormats: { - anoncreds: { credentialDefinitionId, attributes }, + anoncreds: { + credentialDefinitionId, + attributes, + revocationRegistryDefinitionId, + revocationRegistryIndex, + }, }, }), ); @@ -159,6 +166,8 @@ export class AnonCredsCredentialsService { tenantId, credentialDefinitionId, attributes, + revocationRegistryIndex, + revocationRegistryDefinitionId, }: EventDidcommAnonCredsCredentialsOfferToSelfInput): Promise< EventDidcommAnonCredsCredentialsOfferToSelf['data'] > { @@ -186,7 +195,12 @@ export class AnonCredsCredentialsService { autoAcceptCredential: AutoAcceptCredential.Always, connectionId: connection.id, credentialFormats: { - anoncreds: { credentialDefinitionId, attributes }, + anoncreds: { + credentialDefinitionId, + attributes, + revocationRegistryDefinitionId, + revocationRegistryIndex, + }, }, }); }); diff --git a/apps/ssi-abstraction/src/agent/dids/dids.service.ts b/apps/ssi-abstraction/src/agent/dids/dids.service.ts index a1888d5..ed1fb32 100644 --- a/apps/ssi-abstraction/src/agent/dids/dids.service.ts +++ b/apps/ssi-abstraction/src/agent/dids/dids.service.ts @@ -169,7 +169,7 @@ export class DidsService { }), ); - const buffer = Hasher.hash(publicKey, 'sha2-256'); + const buffer = Hasher.hash(publicKey, 'sha-256'); const id = TypedArrayEncoder.toBase58(buffer.slice(0, 16)); const verkey = publicKeyBase58; diff --git a/apps/ssi-abstraction/test/revocation.e2e-spec.ts b/apps/ssi-abstraction/test/revocation.e2e-spec.ts index 83b1767..1fdab05 100644 --- a/apps/ssi-abstraction/test/revocation.e2e-spec.ts +++ b/apps/ssi-abstraction/test/revocation.e2e-spec.ts @@ -1,10 +1,22 @@ import type { INestApplication } from '@nestjs/common'; import type { ClientProxy } from '@nestjs/microservices'; -import type { EventAnonCredsRevocationRegisterRevocationRegistryDefinitionInput } from '@ocm/shared'; +import type { + EventAnonCredsCredentialsGetAllInput, + EventAnonCredsRevocationRegisterRevocationRegistryDefinitionInput, + EventAnonCredsRevocationRegisterRevocationStatusListInput, + EventAnonCredsRevocationRevokeInput, + EventDidcommAnonCredsCredentialsOfferToSelfInput, +} from '@ocm/shared'; import { ClientsModule, Transport } from '@nestjs/microservices'; import { Test } from '@nestjs/testing'; -import { EventAnonCredsRevocationRegisterRevocationRegistryDefinition } from '@ocm/shared'; +import { + EventAnonCredsCredentialsGetAll, + EventDidcommAnonCredsCredentialsOfferToSelf, + EventAnonCredsRevocationRegisterRevocationRegistryDefinition, + EventAnonCredsRevocationRegisterRevocationStatusList, + EventAnonCredsRevocationRevoke, +} from '@ocm/shared'; import { randomBytes } from 'crypto'; import { firstValueFrom } from 'rxjs'; @@ -100,7 +112,7 @@ describe('Revocation', () => { client.close(); }); - it( + xit( EventAnonCredsRevocationRegisterRevocationRegistryDefinition.token, async () => { const response$ = client.send< @@ -121,9 +133,144 @@ describe('Revocation', () => { expect( eventInstance.instance.revocationRegistryDefinitionId.startsWith( - 'did:indy:bcorvin:test:', + 'did:indy:bcovrin:test:', ), ).toBeTruthy(); }, ); + + xit(EventAnonCredsRevocationRegisterRevocationStatusList.token, async () => { + let revRegDefId: string = ''; + { + const response$ = client.send< + EventAnonCredsRevocationRegisterRevocationRegistryDefinition, + EventAnonCredsRevocationRegisterRevocationRegistryDefinitionInput + >(EventAnonCredsRevocationRegisterRevocationRegistryDefinition.token, { + tenantId, + tag: 'rev-tag-two', + issuerDid, + credentialDefinitionId, + maximumCredentialNumber: 100, + }); + const response = await firstValueFrom(response$); + const eventInstance = + EventAnonCredsRevocationRegisterRevocationRegistryDefinition.fromEvent( + response, + ); + + revRegDefId = eventInstance.instance.revocationRegistryDefinitionId; + } + + const response$ = client.send< + EventAnonCredsRevocationRegisterRevocationStatusList, + EventAnonCredsRevocationRegisterRevocationStatusListInput + >(EventAnonCredsRevocationRegisterRevocationStatusList.token, { + tenantId, + revocationRegistryDefinitionId: revRegDefId, + issuerDid, + }); + const response = await firstValueFrom(response$); + const eventInstance = + EventAnonCredsRevocationRegisterRevocationStatusList.fromEvent(response); + + expect(eventInstance.instance).toMatchObject({}); + }); + + it(EventAnonCredsRevocationRevoke.token, async () => { + let revRegDefId: string = ''; + let credentialId: string = ''; + + // Register the revocation registry definition + { + const response$ = client.send< + EventAnonCredsRevocationRegisterRevocationRegistryDefinition, + EventAnonCredsRevocationRegisterRevocationRegistryDefinitionInput + >(EventAnonCredsRevocationRegisterRevocationRegistryDefinition.token, { + tenantId, + tag: 'rev-tag-three', + issuerDid, + credentialDefinitionId, + maximumCredentialNumber: 100, + }); + const response = await firstValueFrom(response$); + const eventInstance = + EventAnonCredsRevocationRegisterRevocationRegistryDefinition.fromEvent( + response, + ); + + revRegDefId = eventInstance.instance.revocationRegistryDefinitionId; + } + + // Register the revocation Status List + { + const response$ = client.send< + EventAnonCredsRevocationRegisterRevocationStatusList, + EventAnonCredsRevocationRegisterRevocationStatusListInput + >(EventAnonCredsRevocationRegisterRevocationStatusList.token, { + tenantId, + revocationRegistryDefinitionId: revRegDefId, + issuerDid, + }); + const response = await firstValueFrom(response$); + const eventInstance = + EventAnonCredsRevocationRegisterRevocationStatusList.fromEvent( + response, + ); + + expect(eventInstance.instance).toMatchObject({}); + } + + // Issue a credential + { + const response$ = client.send< + EventDidcommAnonCredsCredentialsOfferToSelf, + EventDidcommAnonCredsCredentialsOfferToSelfInput + >(EventDidcommAnonCredsCredentialsOfferToSelf.token, { + tenantId, + attributes: [ + { name: 'Name', value: 'Berend' }, + { name: 'Age', value: '30' }, + ], + revocationRegistryDefinitionId: revRegDefId, + revocationRegistryIndex: 10, + credentialDefinitionId, + }); + const response = await firstValueFrom(response$); + const eventInstance = + EventDidcommAnonCredsCredentialsOfferToSelf.fromEvent(response); + + credentialId = eventInstance.instance.id; + } + + // Revoke the credential + { + const response$ = client.send< + EventAnonCredsRevocationRevoke, + EventAnonCredsRevocationRevokeInput + >(EventAnonCredsRevocationRevoke.token, { + tenantId, + credentialId, + }); + const response = await firstValueFrom(response$); + const eventInstance = EventAnonCredsRevocationRevoke.fromEvent(response); + expect(eventInstance.instance).toBeNull(); + } + + // Check the state + { + const response$ = client.send< + EventAnonCredsCredentialsGetAll, + EventAnonCredsCredentialsGetAllInput + >(EventAnonCredsCredentialsGetAll.token, { + tenantId, + }); + const response = await firstValueFrom(response$); + const eventInstance = EventAnonCredsCredentialsGetAll.fromEvent(response); + + const credRecord = eventInstance.instance.find( + (r) => r.id === credentialId, + ); + // console.log(credRecord); + } + }); }); -- GitLab