import { CredentialValidationResult } from '../credential/credentialValidator.interface.js'; import { CredentialFormat, ExtractionResult, } from './vpTokenCredentialsExtractor.js'; export enum CredentialValidationTypes { Expiration = 'Expiration', NotYetValid = 'NotYetValid', Revocation = 'Revocation', Schema = 'Schema', CredentialSignature = 'CredentialSignature', } export enum ValidationResult { OK = 'OK', KO = 'KO', NotValidated = 'NotValidated', } interface CredentialsPresentedList { verifiableCredential: string | object; verifiableCredentialsDecoded?: object; validations: CredentialValidations[]; } export interface ValidationReport { globalResult: { result: string; errorMessage?: string; }; verifiablePresentation: any; credentialsPresentedList: CredentialsPresentedList[]; } interface CredentialValidations { validationType: CredentialValidationTypes; validationResult: ValidationResult; validationResultDetails?: string; } export class VerifiablePresentationValidationReport { private extractionResult: ExtractionResult; private credentialValidations: { [key: string]: CredentialValidations[] } = {}; private globalResult = true; private errorMessage: string = undefined; generate(): ValidationReport { return { globalResult: { result: this.globalResult ? ValidationResult.OK : ValidationResult.KO, ...(this.errorMessage && { errorMessage: this.errorMessage }), }, verifiablePresentation: this.extractionResult.vpTokenData.decodedVerifiablePresentation, credentialsPresentedList: this.extractionResult.vpTokenData.verifiableCredentials.map( (credential, index): CredentialsPresentedList => { const credentialId = this.extractionResult.vpTokenData.verifiableCredentialsDecoded[ index ]?.vc?.id; const validations = this.credentialValidations?.[credentialId] ?.length ? this.credentialValidations[credentialId] : this.buildNotValidatedList(); return { verifiableCredential: this.extractionResult.vpTokenData.verifiableCredentials[index] .verifiableCredential, ...(credential.format === CredentialFormat.JWT && { verifiableCredentialsDecoded: this.extractionResult.vpTokenData .verifiableCredentialsDecoded[index], }), validations, }; }, ), }; } addExtractionResult(extractionResult: ExtractionResult) { this.extractionResult = extractionResult; } updateCredentialInformation( type: CredentialValidationTypes, credentialId: string, result: CredentialValidationResult, ): void { if (!this.credentialValidations[credentialId]) { this.credentialValidations[credentialId] = []; } this.globalResult = this.globalResult && result.valid; this.credentialValidations[credentialId].push({ validationType: type, validationResult: result.valid ? ValidationResult.OK : ValidationResult.KO, ...(result.message && { validationResultDetails: result.message }), }); } updatePresentationInformation(result: { valid: boolean; messages?: string[]; }) { this.globalResult = this.globalResult && result.valid; this.errorMessage = result?.messages ? result.messages.join() : this.errorMessage; } updateFailedPresentation( messages: string[], credentialId?: string, validationTypes?: CredentialValidationTypes[], ) { this.globalResult = false; this.errorMessage = messages.join(); if (!credentialId && !validationTypes) { return; } if (!this.credentialValidations[credentialId]) { this.credentialValidations[credentialId] = []; } validationTypes.map((validationType) => { this.credentialValidations[credentialId].push({ validationType: validationType, validationResult: ValidationResult.NotValidated, }); }); } private buildNotValidatedList(): CredentialValidations[] { return Object.values(CredentialValidationTypes).map( (validationType): CredentialValidations => ({ validationType, validationResult: ValidationResult.NotValidated, }), ); } }