diff --git a/apps/shared/src/events/credentialOfferEvents.ts b/apps/shared/src/events/credentialOfferEvents.ts index d120f84048244d20cbcc87d3bf96966b8b58725b..da38971397df39dea1925d48c75c9fcf5e65e5e3 100644 --- a/apps/shared/src/events/credentialOfferEvents.ts +++ b/apps/shared/src/events/credentialOfferEvents.ts @@ -1,6 +1,11 @@ import type { BaseEventInput } from './baseEvents.js'; import type { AnonCredsCredentialOffer } from '@aries-framework/anoncreds'; +import { + CredentialExchangeRecord, + JsonTransformer, +} from '@aries-framework/core'; + import { BaseEvent } from './baseEvents.js'; export type EventAnonCredsCredentialOfferGetAllInput = BaseEventInput; @@ -11,7 +16,9 @@ export class EventAnonCredsCredentialOfferGetAll extends BaseEvent< public static token = 'anoncreds.credentialOffers.getAll'; public get instance() { - return this.data; + return this.data.map((d) => + JsonTransformer.fromJSON(d, CredentialExchangeRecord), + ); } public static fromEvent(e: EventAnonCredsCredentialOfferGetAll) { @@ -33,7 +40,9 @@ export class EventAnonCredsCredentialOfferGetById extends BaseEvent<AnonCredsCre public static token = 'anoncreds.credentialOffers.getById'; public get instance() { - return this.data; + return this.data + ? JsonTransformer.fromJSON(this.data, CredentialExchangeRecord) + : null; } public static fromEvent(e: EventAnonCredsCredentialOfferGetById) { diff --git a/apps/shared/src/events/credentialRequestEvents.ts b/apps/shared/src/events/credentialRequestEvents.ts index 213562f3808bf913a181d11653eadd62ff8f6802..f143033cf1e12a4cb4744e401e7062e03a60c404 100644 --- a/apps/shared/src/events/credentialRequestEvents.ts +++ b/apps/shared/src/events/credentialRequestEvents.ts @@ -1,6 +1,11 @@ import type { BaseEventInput } from './baseEvents.js'; import type { AnonCredsCredentialRequest } from '@aries-framework/anoncreds'; +import { + CredentialExchangeRecord, + JsonTransformer, +} from '@aries-framework/core'; + import { BaseEvent } from './baseEvents.js'; export type EventAnonCredsCredentialRequestGetAllInput = BaseEventInput; @@ -11,7 +16,9 @@ export class EventAnonCredsCredentialRequestGetAll extends BaseEvent< public static token = 'anoncreds.credentialRequests.getAll'; public get instance() { - return this.data; + return this.data.map((d) => + JsonTransformer.fromJSON(d, CredentialExchangeRecord), + ); } public static fromEvent(e: EventAnonCredsCredentialRequestGetAll) { @@ -33,7 +40,9 @@ export class EventAnonCredsCredentialRequestGetById extends BaseEvent<AnonCredsC public static token = 'anoncreds.credentialRequests.getById'; public get instance() { - return this.data; + return this.data + ? JsonTransformer.fromJSON(this.data, CredentialExchangeRecord) + : null; } public static fromEvent(e: EventAnonCredsCredentialRequestGetById) { diff --git a/apps/shared/src/events/proofEvents.ts b/apps/shared/src/events/proofEvents.ts index b40e17a5e327d382c7098621110fb0139504fc2f..195777bd81c2776394480abb9a1223295476b71e 100644 --- a/apps/shared/src/events/proofEvents.ts +++ b/apps/shared/src/events/proofEvents.ts @@ -38,7 +38,9 @@ export class EventAnonCredsProofsGetById extends BaseEvent<ProofExchangeRecord | public static token = 'anoncreds.proofs.getById'; public get instance() { - return JsonTransformer.fromJSON(this.data, ProofExchangeRecord); + return this.data + ? JsonTransformer.fromJSON(this.data, ProofExchangeRecord) + : this.data; } public static fromEvent(e: EventAnonCredsProofsGetById) { diff --git a/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.controller.ts b/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.controller.ts index 1cef75b483beddd9ff786a9b095c3402a2349e33..11a6d93ec55d88eb5ef91aab973f8d67c0c7e2ff 100644 --- a/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.controller.ts +++ b/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.controller.ts @@ -1,10 +1,10 @@ import { Controller } from '@nestjs/common'; import { MessagePattern } from '@nestjs/microservices'; import { - EventDidcommAnonCredsCredentialsGetAll, - EventDidcommAnonCredsCredentialsGetAllInput, - EventDidcommAnonCredsCredentialsGetById, - EventDidcommAnonCredsCredentialsGetByIdInput, + EventAnonCredsCredentialsGetAll, + EventAnonCredsCredentialsGetAllInput, + EventAnonCredsCredentialsGetById, + EventAnonCredsCredentialsGetByIdInput, EventDidcommAnonCredsCredentialsOffer, EventDidcommAnonCredsCredentialsOfferInput, EventDidcommAnonCredsCredentialsOfferToSelfInput, @@ -17,21 +17,21 @@ import { AnonCredsCredentialsService } from './anoncredsCredentials.service.js'; export class AnonCredsCredentialsController { public constructor(private credentialsService: AnonCredsCredentialsService) {} - @MessagePattern(EventDidcommAnonCredsCredentialsGetAll.token) + @MessagePattern(EventAnonCredsCredentialsGetAll.token) public async getAll( - options: EventDidcommAnonCredsCredentialsGetAllInput, - ): Promise<EventDidcommAnonCredsCredentialsGetAll> { - return new EventDidcommAnonCredsCredentialsGetAll( + options: EventAnonCredsCredentialsGetAllInput, + ): Promise<EventAnonCredsCredentialsGetAll> { + return new EventAnonCredsCredentialsGetAll( await this.credentialsService.getAll(options), options.tenantId, ); } - @MessagePattern(EventDidcommAnonCredsCredentialsGetById.token) + @MessagePattern(EventAnonCredsCredentialsGetById.token) public async getById( - options: EventDidcommAnonCredsCredentialsGetByIdInput, - ): Promise<EventDidcommAnonCredsCredentialsGetById> { - return new EventDidcommAnonCredsCredentialsGetById( + options: EventAnonCredsCredentialsGetByIdInput, + ): Promise<EventAnonCredsCredentialsGetById> { + return new EventAnonCredsCredentialsGetById( await this.credentialsService.getById(options), options.tenantId, ); diff --git a/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.service.ts b/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.service.ts index 3eb52b6e61e023f4deb42ebefbc8ff500af4cc99..6cb0cb773aa0dea8f4390dc3ae1adf0935ee0c11 100644 --- a/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.service.ts +++ b/apps/ssi-abstraction/src/agent/anoncredsCredentials/anoncredsCredentials.service.ts @@ -1,6 +1,6 @@ import type { - EventDidcommAnonCredsCredentialsGetAllInput, - EventDidcommAnonCredsCredentialsGetByIdInput, + EventAnonCredsCredentialsGetAllInput, + EventAnonCredsCredentialsGetByIdInput, EventDidcommAnonCredsCredentialsOfferInput, EventDidcommAnonCredsCredentialsOfferToSelfInput, } from '@ocm/shared'; @@ -20,7 +20,7 @@ export class AnonCredsCredentialsService { public async getAll({ tenantId, - }: EventDidcommAnonCredsCredentialsGetAllInput): Promise< + }: EventAnonCredsCredentialsGetAllInput): Promise< Array<CredentialExchangeRecord> > { return this.withTenantService.invoke(tenantId, (t) => @@ -31,7 +31,7 @@ export class AnonCredsCredentialsService { public async getById({ tenantId, credentialRecordId, - }: EventDidcommAnonCredsCredentialsGetByIdInput): Promise<CredentialExchangeRecord | null> { + }: EventAnonCredsCredentialsGetByIdInput): Promise<CredentialExchangeRecord | null> { return this.withTenantService.invoke(tenantId, (t) => t.credentials.findById(credentialRecordId), ); diff --git a/apps/ssi-abstraction/src/agent/anoncredsProofs/__tests__/anoncredsProofs.controller.spec.ts b/apps/ssi-abstraction/src/agent/anoncredsProofs/__tests__/anoncredsProofs.controller.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..91eb60562a79e398f61630432b4c6628ea053a40 --- /dev/null +++ b/apps/ssi-abstraction/src/agent/anoncredsProofs/__tests__/anoncredsProofs.controller.spec.ts @@ -0,0 +1,77 @@ +import { ProofExchangeRecord, ProofState } from '@aries-framework/core'; +import { Test } from '@nestjs/testing'; + +import { mockConfigModule } from '../../../config/__tests__/mockConfig.js'; +import { AgentModule } from '../../agent.module.js'; +import { AnonCredsProofsController } from '../anoncredsProofs.controller.js'; +import { AnonCredsProofsService } from '../anoncredsProofs.service.js'; + +describe('AnonCredsProofsController', () => { + let proofsController: AnonCredsProofsController; + let proofsService: AnonCredsProofsService; + + beforeEach(async () => { + const moduleRef = await Test.createTestingModule({ + imports: [mockConfigModule(), AgentModule], + controllers: [AnonCredsProofsController], + providers: [AnonCredsProofsService], + }).compile(); + + proofsService = moduleRef.get(AnonCredsProofsService); + proofsController = moduleRef.get(AnonCredsProofsController); + }); + + it('get all', async () => { + const result: Array<ProofExchangeRecord> = []; + jest.spyOn(proofsService, 'getAll').mockResolvedValue(result); + + const event = await proofsController.getAll({ + tenantId: 'some-id', + }); + + expect(event.data).toStrictEqual(result); + }); + + it('get by id', async () => { + const result: ProofExchangeRecord | null = null; + jest.spyOn(proofsService, 'getById').mockResolvedValue(result); + + const event = await proofsController.getById({ + tenantId: 'some-id', + proofRecordId: 'some-id', + }); + + expect(event.data).toStrictEqual(result); + }); + + it('request', async () => { + const result = new ProofExchangeRecord({ + state: ProofState.Done, + threadId: 'some-id', + protocolVersion: 'v2', + }); + jest.spyOn(proofsService, 'request').mockResolvedValue(result); + + const event = await proofsController.request({ + tenantId: 'some-id', + connectionId: 'some-id', + name: 'My New Proof Request', + requestedAttributes: { + identity: { + names: ['name'], + restrictions: [{ issuer_id: 'did:web:government.org' }], + }, + }, + requestedPredicates: { + 'age > 18': { + name: 'age', + restrictions: [{ issuer_id: 'did:web:government.org' }], + predicateType: '>', + predicateValue: 18, + }, + }, + }); + + expect(event.data).toStrictEqual(result); + }); +}); diff --git a/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.service.ts b/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.service.ts index 4512f284466cfefbe70ba37fa258894c573f616e..6de76335a02b03d4221795d498357d7d615eb4a5 100644 --- a/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.service.ts +++ b/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.service.ts @@ -32,7 +32,7 @@ export class AnonCredsProofsService { EventAnonCredsProofsGetById['data'] > { return this.withTenantService.invoke(tenantId, (t) => - t.proofs.getById(proofRecordId), + t.proofs.findById(proofRecordId), ); } diff --git a/apps/ssi-abstraction/test/anoncredsProofs.e2e-spec.ts b/apps/ssi-abstraction/test/anoncredsProofs.e2e-spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..fe6c5f7bf768c38d421e5514558879d4f8e8b625 --- /dev/null +++ b/apps/ssi-abstraction/test/anoncredsProofs.e2e-spec.ts @@ -0,0 +1,133 @@ +import type { INestApplication } from '@nestjs/common'; +import type { ClientProxy } from '@nestjs/microservices'; +import type { + EventAnonCredsProofsGetAllInput, + EventAnonCredsProofsGetByIdInput, + EventDidcommAnonCredsProofsRequestInput, +} from '@ocm/shared'; + +import { ProofState } from '@aries-framework/core'; +import { ClientsModule, Transport } from '@nestjs/microservices'; +import { Test } from '@nestjs/testing'; +import { + EventAnonCredsProofsGetAll, + EventAnonCredsProofsGetById, + EventDidcommAnonCredsProofsRequest, +} from '@ocm/shared'; +import { firstValueFrom } from 'rxjs'; + +import { AgentModule } from '../src/agent/agent.module.js'; +import { AnonCredsProofsModule } from '../src/agent/anoncredsProofs/anoncredsProofs.module.js'; +import { ConnectionsModule } from '../src/agent/connections/connections.module.js'; +import { ConnectionsService } from '../src/agent/connections/connections.service.js'; +import { DidsModule } from '../src/agent/dids/dids.module.js'; +import { TenantsModule } from '../src/agent/tenants/tenants.module.js'; +import { TenantsService } from '../src/agent/tenants/tenants.service.js'; +import { mockConfigModule } from '../src/config/__tests__/mockConfig.js'; + +describe('Proofs', () => { + const TOKEN = 'PROOFS_CLIENT_SERVICE'; + let app: INestApplication; + let client: ClientProxy; + let tenantId: string; + + let connectionId: string; + let credentialDefinitionId: string; + + beforeAll(async () => { + const moduleRef = await Test.createTestingModule({ + imports: [ + mockConfigModule(3004, true), + AgentModule, + ConnectionsModule, + AnonCredsProofsModule, + TenantsModule, + DidsModule, + ClientsModule.register([{ name: TOKEN, transport: Transport.NATS }]), + ], + }).compile(); + + app = moduleRef.createNestApplication(); + + app.connectMicroservice({ transport: Transport.NATS }); + + await app.startAllMicroservices(); + await app.init(); + + client = app.get(TOKEN); + await client.connect(); + + const tenantsService = app.get(TenantsService); + const { id: tId } = await tenantsService.create(TOKEN); + tenantId = tId; + + const connectionsService = app.get(ConnectionsService); + const { id } = await connectionsService.createConnectionWithSelf({ + tenantId, + }); + connectionId = id; + }); + + afterAll(async () => { + await app.close(); + client.close(); + }); + + it(EventAnonCredsProofsGetAll.token, async () => { + const response$ = client.send< + EventAnonCredsProofsGetAll, + EventAnonCredsProofsGetAllInput + >(EventAnonCredsProofsGetAll.token, { tenantId }); + const response = await firstValueFrom(response$); + const eventInstance = EventAnonCredsProofsGetAll.fromEvent(response); + + expect(eventInstance.instance).toEqual(expect.arrayContaining([])); + }); + + it(EventAnonCredsProofsGetById.token, async () => { + const response$ = client.send< + EventAnonCredsProofsGetById, + EventAnonCredsProofsGetByIdInput + >(EventAnonCredsProofsGetById.token, { + tenantId, + proofRecordId: 'some-id', + }); + const response = await firstValueFrom(response$); + const eventInstance = EventAnonCredsProofsGetById.fromEvent(response); + + expect(eventInstance.instance).toEqual(null); + }); + + it(EventDidcommAnonCredsProofsRequest.token, async () => { + const response$ = client.send< + EventDidcommAnonCredsProofsRequest, + EventDidcommAnonCredsProofsRequestInput + >(EventDidcommAnonCredsProofsRequest.token, { + tenantId, + name: 'My Test Proof Request', + connectionId, + requestedAttributes: { + Identity: { + names: ['Name'], + restrictions: [{ cred_def_id: credentialDefinitionId }], + }, + }, + requestedPredicates: { + 'Age > 21': { + name: 'Age', + restrictions: [{ cred_def_id: credentialDefinitionId }], + predicateType: '>', + predicateValue: 21, + }, + }, + }); + + const response = await firstValueFrom(response$); + const eventInstance = + EventDidcommAnonCredsProofsRequest.fromEvent(response); + + expect(eventInstance.instance).toMatchObject({ + state: ProofState.RequestSent, + }); + }); +});