import { logger } from "ethers" ; import { SchemaId } from "../@types/document" ; import { validateSchema as validate } from "../validate" ; import { VerifiableCredentialSignedProof , VerifiableCredentialWrappedProof , VerifiableCredentialWrappedProofStrict , } from "../../3.0/types" ; import { ArrayProof , Signature , SignatureStrict } from "../../2.0/types" ; import { clone , cloneDeepWith } from "lodash" ; import { buildAjv , getSchema } from "../ajv" ; import { Kind , Mode } from "./@types/diagnose" ; type Version = "2.0" | "3.0" ; interface DiagnoseError { message : string ; } const handleError = ( debug , ... messages ) => { if ( debug ) { for ( const message of messages ) { logger . info ( message ) ; } } return messages . map ( ( message ) => ( { message } ) ) ; } ; function transformSchema ( schema ) { const excludeKeys = [ "enum" , "pattern" ] ; function omit ( value ) { if ( value && typeof value === "object" ) { const key = excludeKeys . find ( ( key ) => value [ key ] ) ; if ( key ) { const node = clone ( value ) ; excludeKeys . forEach ( ( key ) => { delete node [ key ] ; } ) ; return node ; } } } const newSchema = cloneDeepWith ( schema , omit ) ; if ( newSchema ?. definitions ?. identityProof ?. oneOf ) { newSchema . definitions . identityProof . anyOf = newSchema ?. definitions ?. identityProof ?. oneOf ; delete newSchema ?. definitions ?. identityProof ?. oneOf ; } return newSchema ; } const ajv = buildAjv ( { transform : transformSchema , validateFormats : false } ) ; param version param kind param debug param mode param document export const diagnose = ( { version , kind , document , debug = false , mode , } ) : DiagnoseError [ ] => { if ( ! document ) { return handleError ( debug , "The document must not be empty" ) ; } if ( typeof document !== "object" ) { return handleError ( debug , "The document must be an object" ) ; } const errors = validate ( document , getSchema ( version === "3.0" ? SchemaId . v3 : SchemaId . v2 , mode === "non-strict" ? ajv : undefined ) , kind ) ; if ( errors . length > 0 ) { return handleError ( debug , `The document does not match OpenAttestation schema ${ version === "3.0" ? "3.0" : "2.0" }` , ... errors . map ( ( error ) => `${ error . instancePath || "document" } - ${ error . message }` ) ) ; } if ( kind === "raw" ) { return [ ] ; } if ( version === "3.0" ) { return diagnoseV3 ( { mode , debug , document , kind } ) ; } else { return diagnoseV2 ( { mode , debug , document , kind } ) ; } } ; const diagnoseV2 = ( { kind , document , debug , mode } ) => { try { mode === "strict" ? SignatureStrict . check ( document . signature ) : Signature . check ( document . signature ) ; } catch ( e ) { if ( e instanceof Error ) { return handleError ( debug , e . message ) ; } else { console . error ( e ) ; } } if ( kind === "signed" ) { if ( ! document . proof || ! ( document . proof . length > 0 ) ) { return handleError ( debug , `The document does not have a proof` ) ; } try { ArrayProof . check ( document . proof ) ; } catch ( e ) { if ( e instanceof Error ) { return handleError ( debug , e . message ) ; } else { console . error ( e ) ; } } } return [ ] ; } ; const diagnoseV3 = ( { kind , document , debug , mode } ) => { if ( document . version !== SchemaId . v3 ) { return handleError ( debug , `The document schema version is wrong. Expected ${ SchemaId . v3 }, received ${ document . version }` ) ; } try { mode === "strict" ? VerifiableCredentialWrappedProofStrict . check ( document . proof ) : VerifiableCredentialWrappedProof . check ( document . proof ) ; } catch ( e ) { if ( e instanceof Error ) { return handleError ( debug , e . message ) ; } else { console . error ( e ) ; } } if ( kind === "signed" ) { if ( ! document . proof ) { return handleError ( debug , `The document does not have a proof` ) ; } try { VerifiableCredentialSignedProof . check ( document . proof ) ; } catch ( e ) { if ( e instanceof Error ) { return handleError ( debug , e . message ) ; } else { console . error ( e ) ; } } } return [ ] ; } ;