import ErrorHelpers from '../error_handling/ErrorHelpers' ; import { AuthenticationErrorCode , AuthenticationErrorDescription , ClaimToken , IExpectedSiop , ITokenValidator , TokenType } from '../index' ; import { IValidationResponse } from '../input_validation/IValidationResponse' ; import { SiopValidation } from '../input_validation/SiopValidation' ; import ValidationQueue from '../input_validation/ValidationQueue' ; import ValidationQueueItem from '../input_validation/ValidationQueueItem' ; import IValidatorOptions from '../options/IValidatorOptions' ; import ValidationOptions from '../options/ValidationOptions' ; import VerifiableCredentialConstants from '../verifiable_credential/VerifiableCredentialConstants' ; const errorCode = ( error ) => ErrorHelpers . errorCode ( 'VCSDKSTVa' , error ) ; /**
 * Class to validate a token
 */ export default class SiopTokenValidator implements ITokenValidator { param validatorOption param expected constructor ( protected validatorOption , protected expected ) { } param queue param queueItem public async validate ( queue , queueItem ) { const options = new ValidationOptions ( this . validatorOption , this . expected . type ) ; const validator = new SiopValidation ( options , this . expected ) ; let validationResult = await validator . validate ( queueItem . tokenToValidate ) ; if ( validationResult . result ) { validationResult = this . getTokens ( validationResult , queue , queueItem . tokenToValidate . type ) ; } validationResult = this . validateReplayProtection ( validationResult ) ; return validationResult as IValidationResponse ; } param validationResponse protected validateReplayProtection ( validationResponse ) { if ( this . expected . nonce ) { if ( this . expected . nonce !== validationResponse . payloadObject . nonce ) { return { result : false , status : this . validatorOption . invalidTokenError , code : errorCode ( 1 ) , detailedError : `Expected nonce '${ this . expected . nonce }' does not match '${ validationResponse . payloadObject . nonce }'.` , wwwAuthenticateError : AuthenticationErrorCode . invalidToken , } ; } } if ( this . expected . state ) { if ( this . expected . state !== validationResponse . payloadObject . state ) { return { result : false , status : this . validatorOption . invalidTokenError , code : errorCode ( 2 ) , detailedError : `Expected state '${ this . expected . state }' does not match '${ validationResponse . payloadObject . state }'.` , wwwAuthenticateError : AuthenticationErrorCode . invalidToken , } ; } } return validationResponse ; } param validationResponse param queue param knownTokenType public getTokens ( validationResponse , queue , knownTokenType ? ) { let type ; if ( validationResponse . payloadObject [ VerifiableCredentialConstants . PRESENTATION_SUBMISSION ] ) { type = TokenType . siopPresentationExchange ; } else if ( knownTokenType === TokenType . siopIssuance || knownTokenType === TokenType . siopPresentationAttestation || validationResponse . payloadObject [ VerifiableCredentialConstants . ATTESTATIONS ] ) { type = TokenType . siopPresentationAttestation ; } else { type = TokenType . siop ; } switch ( type ) { case TokenType . siopPresentationAttestation : const attestations = validationResponse . payloadObject [ VerifiableCredentialConstants . ATTESTATIONS ] ; if ( attestations ) { try { if ( ! validationResponse . tokensArePopulated ) { validationResponse . tokensToValidate = ClaimToken . getClaimTokensFromAttestations ( attestations ) ; } } catch ( err ) { console . error ( err ) ; return { result : false , status : 400 , detailedError : err . message , code : errorCode ( 3 ) , innerError : err } ; } } break ; case TokenType . siopPresentationExchange : try { validationResponse . tokensToValidate = ClaimToken . getClaimTokensFromPresentationExchange ( validationResponse . payloadObject ) ; } catch ( err ) { console . error ( err ) ; return { result : false , status : 403 , detailedError : err . message , code : errorCode ( 4 ) , innerError : err } ; } break ; default : return { result : false , status : this . validatorOption . invalidTokenError , detailedError : AuthenticationErrorDescription . malformedToken , code : errorCode ( 5 ) , wwwAuthenticateError : AuthenticationErrorCode . invalidRequest , } ; } if ( validationResponse . tokensToValidate ) { const safeguards = this . validateSafeguards ( validationResponse . tokensToValidate ) ; if ( ! safeguards . result ) { return safeguards ; } for ( let key in validationResponse . tokensToValidate ) { queue . enqueueItem ( new ValidationQueueItem ( key , validationResponse . tokensToValidate [ key ] ) ) ; } } return validationResponse ; } param claimTokens returns private validateSafeguards ( claimTokens ) { if ( claimTokens ) { const validatorSafeguards = this . validatorOption . validationSafeguards ; let tokens = Object . values ( claimTokens ) ; const vpInSiop = tokens . filter ( ( claimToken ) => claimToken . type === TokenType . verifiablePresentationJwt ) ; if ( vpInSiop . length > validatorSafeguards . maxNumberOfVPTokensInSiop ) { return { result : false , status : 403 , code : errorCode ( 6 ) , detailedError : `The number of presentations in the SIOP ${ vpInSiop . length } exceeds the maximum ${ validatorSafeguards . maxNumberOfVPTokensInSiop }.` } ; } let oversized = tokens . filter ( ( claimToken ) => typeof claimToken . rawToken === 'string' && claimToken . rawToken . length > validatorSafeguards . maxSizeOfVPTokensInSiop ) ; if ( oversized . length !== 0 ) { return { result : false , status : 403 , code : errorCode ( 7 ) , detailedError : `The SIOP has an oversized VP tokens. Size ${ ( < string > oversized [ 0 ] . rawToken ) . length }. Maximum size: ${ validatorSafeguards . maxSizeOfVPTokensInSiop }.` } ; } tokens = Object . values ( claimTokens ) ; const idTokensInSiop = tokens . filter ( ( claimToken ) => claimToken . type === TokenType . idToken ) ; if ( idTokensInSiop . length > validatorSafeguards . maxNumberOfIdTokensInSiop ) { return { result : false , status : 403 , code : errorCode ( 8 ) , detailedError : `The number of id tokens in the SIOP ${ idTokensInSiop . length } exceeds the maximum ${ validatorSafeguards . maxNumberOfIdTokensInSiop }.` } ; } oversized = tokens . filter ( ( claimToken ) => typeof claimToken . rawToken === 'string' && claimToken . rawToken . length > validatorSafeguards . maxSizeOfIdToken ) ; if ( oversized . length !== 0 ) { return { result : false , status : 403 , code : errorCode ( 9 ) , detailedError : `The SIOP has an oversized Id tokens. Size ${ ( < string > oversized [ 0 ] . rawToken ) . length }. Maximum size: ${ validatorSafeguards . maxSizeOfIdToken }.` } ; } } return < IValidationResponse > { result : true } ; } /**
     * Gets the type of token to validate
     */ public get isType ( ) : TokenType { return this . expected . type ; } }