diff --git a/apps/api-gateway/src/verification/dto/request-proof.dto.ts b/apps/api-gateway/src/verification/dto/request-proof.dto.ts index 3ab0d48ee..7d04d5960 100644 --- a/apps/api-gateway/src/verification/dto/request-proof.dto.ts +++ b/apps/api-gateway/src/verification/dto/request-proof.dto.ts @@ -1,29 +1,43 @@ -import { IsArray, IsBoolean, IsEmail, IsEnum, IsNotEmpty, IsNumberString, IsObject, IsOptional, IsString, IsUUID } from 'class-validator'; +import { ArrayNotEmpty, IsArray, IsBoolean, IsEmail, IsEnum, IsNotEmpty, IsNumberString, IsObject, IsOptional, IsString, ValidateIf, ValidateNested, IsUUID } from 'class-validator'; import { toLowerCase, trim } from '@credebl/common/cast.helper'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { Transform } from 'class-transformer'; +import { Transform, Type } from 'class-transformer'; import { AutoAccept } from '@credebl/enum/enum'; import { IProofFormats } from '../interfaces/verification.interface'; + export class ProofRequestAttribute { - @IsString() - @IsNotEmpty({ message: 'attributeName is required.' }) - attributeName: string; + @ValidateIf((obj) => obj.attributeNames === undefined) + @IsNotEmpty() + @IsString({each:true}) + attributeName?: string; + + @ValidateIf((obj) => obj.attributeName === undefined) + @IsArray({ message: 'attributeNames must be an array.' }) + @ArrayNotEmpty({ message: 'array can not be empty' }) + @IsString({ each: true}) + @IsNotEmpty({ each: true, message: 'each element cannot be empty' }) + attributeNames?: string[]; + + @ApiPropertyOptional() @IsString() @IsOptional() schemaId?: string; + @ApiPropertyOptional() @IsString() @IsOptional() @IsNotEmpty({ message: 'condition is required.' }) condition?: string; + @ApiPropertyOptional() @IsOptional() @IsNotEmpty({ message: 'value is required.' }) @IsNumberString({}, { message: 'Value must be a number' }) value?: string; + @ApiPropertyOptional() @IsString() @IsOptional() credDefId?: string; @@ -72,11 +86,14 @@ export class RequestProofDto extends ProofPayload { credDefId: 'string', schemaId: 'string' } - ] + ], + type: () => [ProofRequestAttribute] }) @IsArray({ message: 'attributes must be in array' }) + @ValidateNested() @IsObject({ each: true }) @IsNotEmpty({ message: 'please provide valid attributes' }) + @Type(() => ProofRequestAttribute) attributes: ProofRequestAttribute[]; @ApiPropertyOptional() @@ -106,11 +123,14 @@ export class OutOfBandRequestProof extends ProofPayload { credDefId: '', schemaId: '' } - ] + ], + type: () => [ProofRequestAttribute] }) @IsArray({ message: 'attributes must be in array' }) + @ValidateNested({each: true}) @IsObject({ each: true }) @IsNotEmpty({ message: 'please provide valid attributes' }) + @Type(() => ProofRequestAttribute) attributes: ProofRequestAttribute[]; @ApiProperty() diff --git a/apps/api-gateway/src/verification/verification.controller.ts b/apps/api-gateway/src/verification/verification.controller.ts index d7f9e8d2b..1d7dc4e6b 100644 --- a/apps/api-gateway/src/verification/verification.controller.ts +++ b/apps/api-gateway/src/verification/verification.controller.ts @@ -190,8 +190,7 @@ export class VerificationController { } else { throw new BadRequestException('Please provide unique attribute names'); } - - await this.validateAttribute(attrData); + } requestProof.orgId = orgId; @@ -315,27 +314,4 @@ export class VerificationController { return res.status(HttpStatus.CREATED).json(finalResponse); } - - async validateAttribute( - attrData: object - ): Promise { - - if (!attrData['attributeName']) { - throw new BadRequestException('attributeName must be required'); - } - - if (undefined !== attrData['condition'] && '' === attrData['condition'].trim()) { - throw new BadRequestException('condition cannot be empty'); - } - - if (undefined !== attrData['value'] && '' === attrData['value'].trim()) { - throw new BadRequestException('value cannot be empty'); - } - - if (attrData['condition']) { - if (isNaN(attrData['value'])) { - throw new BadRequestException('value must be an integer'); - } - } - } } \ No newline at end of file diff --git a/apps/verification/src/verification.service.ts b/apps/verification/src/verification.service.ts index ed5ce6f28..97db966a8 100644 --- a/apps/verification/src/verification.service.ts +++ b/apps/verification/src/verification.service.ts @@ -648,7 +648,8 @@ export class VerificationService { try { const getAgentDetails = await this.verificationRepository.getAgentEndPoint(orgId); const verificationMethodLabel = 'get-verified-proof'; - + let credDefId; + let schemaId; const orgAgentType = await this.verificationRepository.getOrgAgentType(getAgentDetails?.orgAgentTypeId); const url = await this.getAgentUrl(verificationMethodLabel, orgAgentType, getAgentDetails?.agentEndPoint, getAgentDetails?.tenantId, '', proofId); let apiKey: string = await this.cacheService.get(CommonConstants.CACHE_APIKEY_KEY); @@ -659,27 +660,39 @@ export class VerificationService { const payload = { apiKey, url }; const getProofPresentationById = await this._getVerifiedProofDetails(payload); + if (!getProofPresentationById?.response?.presentation) { throw new NotFoundException(ResponseMessages.verification.error.proofPresentationNotFound, { cause: new Error(), description: ResponseMessages.errorMessages.notFound }); } + const requestedAttributes = getProofPresentationById?.response?.request?.indy?.requested_attributes; const requestedPredicates = getProofPresentationById?.response?.request?.indy?.requested_predicates; const revealedAttrs = getProofPresentationById?.response?.presentation?.indy?.requested_proof?.revealed_attrs; + const extractedDataArray: IProofPresentationDetails[] = []; - if (requestedAttributes && requestedPredicates) { + if (0 !== Object.keys(requestedAttributes).length && 0 !== Object.keys(requestedPredicates).length) { + for (const key in requestedAttributes) { if (requestedAttributes.hasOwnProperty(key)) { const requestedAttributeKey = requestedAttributes[key]; const attributeName = requestedAttributeKey.name; - const credDefId = requestedAttributeKey?.restrictions[0]?.cred_def_id; - const schemaId = requestedAttributeKey?.restrictions[0]?.schema_id; + + if (requestedAttributeKey?.restrictions) { + + credDefId = requestedAttributeKey?.restrictions[0]?.cred_def_id; + schemaId = requestedAttributeKey?.restrictions[0]?.schema_id; + } else if (getProofPresentationById?.response?.presentation?.indy?.identifiers) { + + credDefId = getProofPresentationById?.response?.presentation?.indy?.identifiers[0].cred_def_id; + schemaId = getProofPresentationById?.response?.presentation?.indy?.identifiers[0].schema_id; + } if (revealedAttrs.hasOwnProperty(key)) { const extractedData: IProofPresentationDetails = { @@ -708,14 +721,17 @@ export class VerificationService { } } - } else if (requestedAttributes) { + } else if (0 !== Object.keys(requestedAttributes).length) { + for (const key in requestedAttributes) { if (requestedAttributes.hasOwnProperty(key)) { const attribute = requestedAttributes[key]; const attributeName = attribute.name; - const credDefId = attribute?.restrictions[0]?.cred_def_id; - const schemaId = attribute?.restrictions[0]?.schema_id; + + + [credDefId, schemaId] = await this._schemaCredDefRestriction(attribute, getProofPresentationById); + if (revealedAttrs.hasOwnProperty(key)) { const extractedData: IProofPresentationDetails = { @@ -727,14 +743,14 @@ export class VerificationService { } } } - } else if (requestedPredicates) { + } else if (0 !== Object.keys(requestedPredicates).length) { for (const key in requestedPredicates) { if (requestedPredicates.hasOwnProperty(key)) { const attribute = requestedPredicates[key]; const attributeName = attribute?.name; - const credDefId = attribute?.restrictions[0]?.cred_def_id; - const schemaId = attribute?.restrictions[0]?.schema_id; + + [credDefId, schemaId] = await this._schemaCredDefRestriction(attribute, getProofPresentationById); const extractedData: IProofPresentationDetails = { [attributeName]: `${requestedPredicates?.p_type}${requestedPredicates?.p_value}`, @@ -767,6 +783,23 @@ export class VerificationService { } } + async _schemaCredDefRestriction(attribute, getProofPresentationById): Promise { + let credDefId; + let schemaId; + + if (attribute?.restrictions) { + + credDefId = attribute?.restrictions[0]?.cred_def_id; + schemaId = attribute?.restrictions[0]?.schema_id; + } else if (getProofPresentationById?.response?.presentation?.indy?.identifiers) { + + credDefId = getProofPresentationById?.response?.presentation?.indy?.identifiers[0].cred_def_id; + schemaId = getProofPresentationById?.response?.presentation?.indy?.identifiers[0].schema_id; + } + + return [credDefId, schemaId]; + } + async _getVerifiedProofDetails(payload: IVerifiedProofData): Promise<{ response; }> {