diff --git a/apps/shared/src/events/proofEvents.ts b/apps/shared/src/events/proofEvents.ts new file mode 100644 index 0000000000000000000000000000000000000000..b40e17a5e327d382c7098621110fb0139504fc2f --- /dev/null +++ b/apps/shared/src/events/proofEvents.ts @@ -0,0 +1,106 @@ +import type { BaseEventInput } from './baseEvents.js'; +import type { + AnonCredsPredicateType, + AnonCredsProofRequestRestriction, +} from '@aries-framework/anoncreds'; + +import { JsonTransformer, ProofExchangeRecord } from '@aries-framework/core'; + +import { BaseEvent } from './baseEvents.js'; + +export type EventAnonCredsProofsGetAllInput = BaseEventInput; +export class EventAnonCredsProofsGetAll extends BaseEvent< + Array<ProofExchangeRecord> +> { + public static token = 'anoncreds.proofs.getAll'; + + public get instance() { + return this.data.map((d) => + JsonTransformer.fromJSON(d, ProofExchangeRecord), + ); + } + + public static fromEvent(e: EventAnonCredsProofsGetAll) { + return new EventAnonCredsProofsGetAll( + e.data, + e.tenantId, + e.id, + e.type, + e.timestamp, + ); + } +} + +export type EventAnonCredsProofsGetByIdInput = BaseEventInput<{ + proofRecordId: string; +}>; +export class EventAnonCredsProofsGetById extends BaseEvent<ProofExchangeRecord | null> { + public static token = 'anoncreds.proofs.getById'; + + public get instance() { + return JsonTransformer.fromJSON(this.data, ProofExchangeRecord); + } + + public static fromEvent(e: EventAnonCredsProofsGetById) { + return new EventAnonCredsProofsGetById( + e.data, + e.tenantId, + e.id, + e.type, + e.timestamp, + ); + } +} + +export type EventDidcommAnonCredsProofsRequestInput = BaseEventInput<{ + connectionId: string; + name: string; + requestedAttributes: { + [groupName: string]: { + names: Array<string>; + restrictions?: Array<AnonCredsProofRequestRestriction>; + }; + }; + requestedPredicates: { + [groupName: string]: { + name: string; + predicateType: AnonCredsPredicateType; + predicateValue: number; + restrictions?: Array<AnonCredsProofRequestRestriction>; + }; + }; +}>; +export class EventDidcommAnonCredsProofsRequest extends BaseEvent<ProofExchangeRecord> { + public static token = 'didcomm.anoncreds.proofs.request'; + + public get instance() { + return JsonTransformer.fromJSON(this.data, ProofExchangeRecord); + } + + public static fromEvent(e: EventDidcommAnonCredsProofsRequest) { + return new EventDidcommAnonCredsProofsRequest( + e.data, + e.tenantId, + e.id, + e.type, + e.timestamp, + ); + } +} + +export type EventAnonCredsProofsDeleteByIdInput = BaseEventInput<{ + proofRecordId: string; +}>; +export class EventAnonCredsProofsDeleteById extends BaseEvent { + public static token = 'anoncreds.proofs.deleteById'; + + public static fromEvent(e: EventDidcommAnonCredsProofsRequest) { + return new EventDidcommAnonCredsProofsRequest( + e.data, + e.tenantId, + e.id, + e.type, + e.timestamp, + ); + } +} diff --git a/apps/shared/src/index.ts b/apps/shared/src/index.ts index 0bb7774a5eabfada0ee848f6d01dd53189aae94a..33b17687bc37ddff5cb7691d490c6f1f0deb8ee4 100644 --- a/apps/shared/src/index.ts +++ b/apps/shared/src/index.ts @@ -12,6 +12,7 @@ export * from './events/credentialDefinitionEvents.js'; export * from './events/credentialEvents.js'; export * from './events/credentialOfferEvents.js'; export * from './events/credentialRequestEvents.js'; +export * from './events/proofEvents.js'; export * from './dto/pagination-params.dto.js'; export * from './dto/multitenancy-params.dto.js'; diff --git a/apps/ssi-abstraction/src/agent/agent.service.ts b/apps/ssi-abstraction/src/agent/agent.service.ts index b1d9bd9279c2175eae5386fe50ecdccc14996a9e..27304bcb83f7317cd9ccc2c477d4ee5ae0544812 100644 --- a/apps/ssi-abstraction/src/agent/agent.service.ts +++ b/apps/ssi-abstraction/src/agent/agent.service.ts @@ -6,7 +6,9 @@ import type { OnApplicationShutdown } from '@nestjs/common'; import { AnonCredsCredentialFormatService, AnonCredsModule, + AnonCredsProofFormatService, LegacyIndyCredentialFormatService, + LegacyIndyProofFormatService, } from '@aries-framework/anoncreds'; import { AnonCredsRsModule } from '@aries-framework/anoncreds-rs'; import { AskarModule } from '@aries-framework/askar'; @@ -23,7 +25,9 @@ import { LogLevel, PeerDidRegistrar, PeerDidResolver, + ProofsModule, V2CredentialProtocol, + V2ProofProtocol, WebDidResolver, } from '@aries-framework/core'; import { @@ -90,13 +94,14 @@ export class AgentService implements OnApplicationShutdown { } public get modules() { - const { autoAcceptConnection, autoAcceptCredential } = + const { autoAcceptConnection, autoAcceptCredential, autoAcceptProof } = this.configService.get('agent'); return { connections: new ConnectionsModule({ autoAcceptConnections: autoAcceptConnection, }), + credentials: new CredentialsModule({ autoAcceptCredentials: autoAcceptCredential, credentialProtocols: [ @@ -109,6 +114,18 @@ export class AgentService implements OnApplicationShutdown { ], }), + proofs: new ProofsModule({ + autoAcceptProofs: autoAcceptProof, + proofProtocols: [ + new V2ProofProtocol({ + proofFormats: [ + new AnonCredsProofFormatService(), + new LegacyIndyProofFormatService(), + ], + }), + ], + }), + anoncredsRs: new AnonCredsRsModule({ anoncreds }), anoncreds: new AnonCredsModule({ registries: [new IndyVdrAnonCredsRegistry()], diff --git a/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.controller.ts b/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.controller.ts new file mode 100644 index 0000000000000000000000000000000000000000..c29a03defeba3e94702a26aac505c0fe3bb3b7e0 --- /dev/null +++ b/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.controller.ts @@ -0,0 +1,59 @@ +import { Controller } from '@nestjs/common'; +import { MessagePattern } from '@nestjs/microservices'; +import { + EventAnonCredsProofsDeleteById, + EventAnonCredsProofsDeleteByIdInput, + EventAnonCredsProofsGetAll, + EventAnonCredsProofsGetAllInput, + EventAnonCredsProofsGetById, + EventAnonCredsProofsGetByIdInput, + EventDidcommAnonCredsProofsRequest, + EventDidcommAnonCredsProofsRequestInput, +} from '@ocm/shared'; + +import { AnonCredsProofsService } from './anoncredsProofs.service.js'; + +@Controller('anoncredsProofs') +export class AnonCredsProofsController { + public constructor(private proofsService: AnonCredsProofsService) {} + + @MessagePattern(EventAnonCredsProofsGetAll.token) + public async getAll( + options: EventAnonCredsProofsGetAllInput, + ): Promise<EventAnonCredsProofsGetAll> { + return new EventAnonCredsProofsGetAll( + await this.proofsService.getAll(options), + options.tenantId, + ); + } + + @MessagePattern(EventAnonCredsProofsGetById.token) + public async getById( + options: EventAnonCredsProofsGetByIdInput, + ): Promise<EventAnonCredsProofsGetById> { + return new EventAnonCredsProofsGetById( + await this.proofsService.getById(options), + options.tenantId, + ); + } + + @MessagePattern(EventAnonCredsProofsDeleteById.token) + public async deleteById( + options: EventAnonCredsProofsDeleteByIdInput, + ): Promise<EventAnonCredsProofsDeleteById> { + return new EventAnonCredsProofsDeleteById( + await this.proofsService.deleteById(options), + options.tenantId, + ); + } + + @MessagePattern(EventDidcommAnonCredsProofsRequest.token) + public async request( + options: EventDidcommAnonCredsProofsRequestInput, + ): Promise<EventDidcommAnonCredsProofsRequest> { + return new EventDidcommAnonCredsProofsRequest( + await this.proofsService.request(options), + options.tenantId, + ); + } +} diff --git a/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.module.ts b/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..5ab1719ba2aff98122bf50ede7538dde777c3615 --- /dev/null +++ b/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; + +import { AgentModule } from '../agent.module.js'; + +import { AnonCredsProofsController } from './anoncredsProofs.controller.js'; +import { AnonCredsProofsService } from './anoncredsProofs.service.js'; + +@Module({ + imports: [AgentModule], + providers: [AnonCredsProofsService], + controllers: [AnonCredsProofsController], +}) +export class AnonCredsProofsModule {} diff --git a/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.service.ts b/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..4512f284466cfefbe70ba37fa258894c573f616e --- /dev/null +++ b/apps/ssi-abstraction/src/agent/anoncredsProofs/anoncredsProofs.service.ts @@ -0,0 +1,88 @@ +import type { + EventAnonCredsProofsDeleteById, + EventAnonCredsProofsDeleteByIdInput, + EventAnonCredsProofsGetAll, + EventAnonCredsProofsGetAllInput, + EventAnonCredsProofsGetById, + EventAnonCredsProofsGetByIdInput, + EventDidcommAnonCredsProofsRequest, + EventDidcommAnonCredsProofsRequestInput, +} from '@ocm/shared'; + +import { Injectable } from '@nestjs/common'; + +import { WithTenantService } from '../withTenantService.js'; + +@Injectable() +export class AnonCredsProofsService { + public constructor(private withTenantService: WithTenantService) {} + + public async getAll({ + tenantId, + }: EventAnonCredsProofsGetAllInput): Promise< + EventAnonCredsProofsGetAll['data'] + > { + return this.withTenantService.invoke(tenantId, (t) => t.proofs.getAll()); + } + + public async getById({ + tenantId, + proofRecordId, + }: EventAnonCredsProofsGetByIdInput): Promise< + EventAnonCredsProofsGetById['data'] + > { + return this.withTenantService.invoke(tenantId, (t) => + t.proofs.getById(proofRecordId), + ); + } + + public async deleteById({ + tenantId, + proofRecordId, + }: EventAnonCredsProofsDeleteByIdInput): Promise< + EventAnonCredsProofsDeleteById['data'] + > { + return this.withTenantService.invoke(tenantId, async (t) => { + await t.proofs.deleteById(proofRecordId); + return {}; + }); + } + + public async request({ + tenantId, + connectionId, + name, + requestedAttributes, + requestedPredicates, + }: EventDidcommAnonCredsProofsRequestInput): Promise< + EventDidcommAnonCredsProofsRequest['data'] + > { + const transformedPredicates = Object.entries(requestedPredicates).reduce( + (prev, [key, value]) => ({ + ...prev, + [key]: { + name: value.name, + restrictions: value.restrictions, + p_type: value.predicateType, + p_value: value.predicateValue, + }, + }), + {}, + ); + + return this.withTenantService.invoke(tenantId, (t) => + t.proofs.requestProof({ + connectionId, + protocolVersion: 'v2', + proofFormats: { + anoncreds: { + name, + version: '1.0', + requested_attributes: requestedAttributes, + requested_predicates: transformedPredicates, + }, + }, + }), + ); + } +}