From 9a382a16a018c6ff1f77b7e17ada7ee73bdc4a55 Mon Sep 17 00:00:00 2001 From: Ariel Gentile Date: Tue, 7 May 2024 10:21:29 -0300 Subject: [PATCH] feat: initial presentation controller --- src/app.module.ts | 2 + .../invitation/InvitationController.ts | 4 +- .../presentations/PresentationsController.ts | 122 ++++++++++++++++++ src/controllers/types.ts | 4 +- 4 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 src/controllers/presentations/PresentationsController.ts diff --git a/src/app.module.ts b/src/app.module.ts index 7171365..8995d21 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -6,6 +6,7 @@ import { CredentialTypesController } from './controllers/credentials/CredentialT import { InvitationController } from './controllers/invitation/InvitationController' import { QrController } from './controllers/invitation/QrController' import { MessageController } from './controllers/message/MessageController' +import { PresentationsController } from './controllers/presentations/PresentationsController' import { AgentService } from './services/AgentService' import { UrlShorteningService } from './services/UrlShorteningService' import { ServiceAgent } from './utils/ServiceAgent' @@ -20,6 +21,7 @@ export class ServiceAgentModule { ConnectionController, CredentialTypesController, MessageController, + PresentationsController, InvitationController, QrController, ], diff --git a/src/controllers/invitation/InvitationController.ts b/src/controllers/invitation/InvitationController.ts index 2991bc8..aa1d988 100644 --- a/src/controllers/invitation/InvitationController.ts +++ b/src/controllers/invitation/InvitationController.ts @@ -112,7 +112,7 @@ export class InvitationController { const shortUrl = `${process.env.PUBLIC_API_BASE_URL ?? 'http://localhost:3001'}/s?id=${shortUrlId}` return { - presentationRequestId: request.proofRecord.id, + proofExchangeId: request.proofRecord.id, url, shortUrl, } @@ -191,7 +191,7 @@ export class InvitationController { const shortUrl = `${process.env.PUBLIC_API_BASE_URL ?? 'http://localhost:3001'}/s?id=${shortUrlId}` return { - credentialOfferId: request.credentialRecord.id, + credentialExchangeId: request.credentialRecord.id, url, shortUrl, } diff --git a/src/controllers/presentations/PresentationsController.ts b/src/controllers/presentations/PresentationsController.ts new file mode 100644 index 0000000..5adbd91 --- /dev/null +++ b/src/controllers/presentations/PresentationsController.ts @@ -0,0 +1,122 @@ +import { + BadRequestException, + Controller, + Delete, + Get, + InternalServerErrorException, + Logger, + NotFoundException, + Param, +} from '@nestjs/common' +import { ApiTags } from '@nestjs/swagger' + +import { Claim } from '../../model' +import { AgentService } from '../../services/AgentService' +import { CredentialTypeInfo } from '../types' + +@ApiTags('presentations') +@Controller({ + path: 'presentations', + version: '1', +}) +export class PresentationsController { + private readonly logger = new Logger(PresentationsController.name) + + constructor(private readonly agentService: AgentService) {} + + /** + * Get all created credential types + * + * @returns + */ + @Get('/') + public async getAllCredentialTypes(): Promise { + const agent = await this.agentService.getAgent() + + const credentialDefinitions = await agent.modules.anoncreds.getCreatedCredentialDefinitions({}) + + return Promise.all( + credentialDefinitions.map(async record => { + const schemaResult = await agent.modules.anoncreds.getSchema(record.credentialDefinition.schemaId) + + const schema = schemaResult.schema + + return { + id: record.credentialDefinitionId, + name: (record.getTag('name') as string) ?? schema?.name, + version: (record.getTag('version') as string) ?? schema?.version, + attributes: schema?.attrNames || [], + } + }), + ) + } + + /** + * Delete a presentation exchange record + * + * @param proofExchangeId Proof Exchange Id + */ + @Delete('/:proofExchangeId') + public async deleteProofExchangeById(@Param('proofExchangeId') proofExchangeId: string) { + const agent = await this.agentService.getAgent() + await agent.proofs.deleteById(proofExchangeId, { deleteAssociatedDidCommMessages: true }) + } + + /** + * Export a credential type, including its underlying cryptographic data for importing it in another instance + * + * @param credentialTypeId Credential Type Id + * @returns ConnectionRecord + */ + @Get('/:proofExchangeId') + public async getPresentationById(@Param('proofExchangeId') proofExchangeId: string) { + const agent = await this.agentService.getAgent() + + if (!proofExchangeId) { + throw new BadRequestException({ reason: 'proofExchangeId is required' }) + } + + const record = await agent.proofs.findById(proofExchangeId) + + if (!record) { + throw new NotFoundException({ reason: `proof exchange with id "${proofExchangeId}" not found.` }) + } + + try { + const formatData = await agent.proofs.getFormatData(record.id) + + const revealedAttributes = + formatData.presentation?.anoncreds?.requested_proof.revealed_attrs ?? + formatData.presentation?.indy?.requested_proof.revealed_attrs + + const revealedAttributeGroups = + formatData.presentation?.anoncreds?.requested_proof?.revealed_attr_groups ?? + formatData.presentation?.indy?.requested_proof.revealed_attr_groups + + const claims: Claim[] = [] + if (revealedAttributes) { + for (const [name, value] of Object.entries(revealedAttributes)) { + claims.push(new Claim({ name, value: value.raw })) + } + } + + if (revealedAttributeGroups) { + for (const [, groupAttributes] of Object.entries(revealedAttributeGroups)) { + for (const attrName in groupAttributes.values) { + claims.push(new Claim({ name: attrName, value: groupAttributes.values[attrName].raw })) + } + } + } + return { + claims, + verified: record.isVerified ?? false, + state: record.state, + proofExchangeId: record.id, + threadId: record.threadId, + updatedAt: record.updatedAt, + } + } catch (error) { + throw new InternalServerErrorException(error) + } + } +} diff --git a/src/controllers/types.ts b/src/controllers/types.ts index 72cb080..7e12359 100644 --- a/src/controllers/types.ts +++ b/src/controllers/types.ts @@ -53,7 +53,7 @@ export type RequestedCredential = { } export interface CreatePresentationRequestResult { - presentationRequestId: string + proofExchangeId: string url: string shortUrl: string } @@ -70,7 +70,7 @@ export interface CreateCredentialOfferOptions { } export interface CreateCredentialOfferResult { - credentialOfferId: string + credentialExchangeId: string url: string shortUrl: string }