import { ICard } from './ICard' ; import { IPublicKey , ICardCrypto } from '../types' ; import { SelfSigner , VirgilSigner } from './constants' ; /**
 * Interface to be implemented by an object capable of verifying the validity
 * of Virgil Cards.
 */ export interface ICardVerifier { param { ICard } card returns { boolean } verifyCard ( card ) : boolean ; } /**
 * Signature identifier and the public key to be used to verify additional
 * signatures of the cards, if any.
 */ export interface IVerifierCredentials { /**
     * String identifying the signature to be verified with `publicKeyBase64`.
     */ signer : string ; /**
     * Public key to be used to verify the signature identified by `signer`.
     */ publicKeyBase64 : string ; } /**
 * The  VirgilCardVerifier constructor options.
  export interface IVirgilCardVerifierParams { /**
     * Indicates whether the "self" signature of the cards should be verified.
     * Self signature is a signature generated with the card's corresponding
     * private key.
     */ verifySelfSignature ? : boolean ; /**
     * Indicates whether the "virgil" signature of the cards should be
     * verified. Virgil signature is appended to the list of card's signatures
     * when the card is published.
     */ verifyVirgilSignature ? : boolean ; /**
     * Array of arrays of  IVerifierCredentials objects to be used to
     * verify additional signatures of the cards, if any.
     *
     * If whitelists are provided, the card must have at least one signature
     * from each whitelist.
      whitelists ? : IWhitelist [ ] ; } export type IWhitelist = IVerifierCredentials [ ] ; const DEFAULTS = { verifySelfSignature : true , verifyVirgilSignature : true , whitelists : [ ] } ; const VIRGIL_CARDS_PUBKEY_BASE64 = 'MCowBQYDK2VwAyEAljOYGANYiVq1WbvVvoYIKtvZi2ji9bAhxyu6iV/LF8M=' ; /**
 * Class responsible for validating cards by verifying their digital
 * signatures.
 */ export class VirgilCardVerifier implements ICardVerifier { see IVirgilCardVerifierParams public whitelists : IWhitelist [ ] ; see IVirgilCardVerifierParams public verifySelfSignature : boolean ; see IVirgilCardVerifierParams public verifyVirgilSignature : boolean ; /**
     * Public key of the Virgil Cards service used for "virgil" signature
     * verification.
     */ public readonly virgilCardsPublicKey : IPublicKey ; param { ICardCrypto } crypto - Object implementing the
     *  ICardCrypto interface.
     *  param { IVirgilCardVerifierParams } options public constructor ( private readonly crypto , options ? ) { const params = { ... DEFAULTS , ... ( options || { } ) } ; this . verifySelfSignature = params . verifySelfSignature ! ; this . verifyVirgilSignature = params . verifyVirgilSignature ! ; this . whitelists = params . whitelists ! ; this . virgilCardsPublicKey = crypto . importPublicKey ( { value : VIRGIL_CARDS_PUBKEY_BASE64 , encoding : 'base64' } ) ; } param { ICard } card returns { boolean } public verifyCard ( card ) { if ( this . selfValidationFailed ( card ) ) { return false ; } if ( this . virgilValidationFailed ( card ) ) { return false ; } if ( ! this . whitelists || this . whitelists . length === 0 ) { return true ; } const signers = card . signatures . map ( s => s . signer ) ; for ( const whitelist of this . whitelists ) { if ( whitelist == null || whitelist . length === 0 ) { return false ; } const intersectedCreds = whitelist . filter ( x => signers . indexOf ( x . signer ) !== - 1 ) ; if ( intersectedCreds . length === 0 ) { return false ; } const isValidForSome = intersectedCreds . some ( cred => this . validateSignerSignature ( card , this . getPublicKey ( cred . publicKeyBase64 ) , cred . signer ) ) ; if ( ! isValidForSome ) { return false ; } } return true ; } private selfValidationFailed ( card ) { return this . verifySelfSignature && ! this . validateSignerSignature ( card , card . publicKey , SelfSigner ) ; } private virgilValidationFailed ( card ) { return this . verifyVirgilSignature && ! this . validateSignerSignature ( card , this . virgilCardsPublicKey , VirgilSigner ) ; } private getPublicKey ( signerPublicKeyBase64 ) { return this . crypto . importPublicKey ( { value : signerPublicKeyBase64 , encoding : 'base64' } ) ; } private validateSignerSignature ( card , signerPublicKey , signer ) { const signature = card . signatures . find ( s => s . signer === signer ) ; if ( signature == null ) return false ; const extendedSnapshot = signature . snapshot == null ? card . contentSnapshot : card . contentSnapshot + signature . snapshot ; return this . crypto . verifySignature ( { value : extendedSnapshot , encoding : 'utf8' } , { value : signature . signature , encoding : 'base64' } , signerPublicKey ) ; } }