import { ValueSets } from "./value_sets" ; import { Constants } from "./constants" ; import { COLORS } from "./colors" ; enum CertificateType { Vaccination = 'Vaccination Pass' , Test = 'Test Pass' , Recovery = 'Recovery Pass' } enum TextAlignment { right = 'PKTextAlignmentRight' } interface Field { key : string ; label : string ; value : string ; textAlignment ? : string ; } export interface PassDictionary { headerFields : Array < Field > ; primaryFields : Array < Field > ; secondaryFields : Array < Field > ; auxiliaryFields : Array < Field > ; backFields : Array < Field > ; } export interface PayloadBody { color : COLORS ; rawData : string ; decodedData : Uint8Array ; } export class Payload { certificateType : CertificateType ; rawData : string ; backgroundColor : string ; labelColor : string ; foregroundColor : string ; img1x : Buffer ; img2x : Buffer ; dark : boolean ; generic : PassDictionary ; constructor ( body , valueSets ) { const dark = body . color != COLORS . WHITE ; const healthCertificate = body . decodedData [ '-260' ] ; const covidCertificate = healthCertificate [ '1' ] ; if ( covidCertificate == undefined ) { throw new Error ( 'certificateData' ) ; } const nameInformation = covidCertificate [ 'nam' ] ; const dateOfBirth = covidCertificate [ 'dob' ] ; if ( nameInformation == undefined ) { throw new Error ( 'nameMissing' ) ; } if ( dateOfBirth == undefined ) { throw new Error ( 'dobMissing' ) ; } const firstName = nameInformation [ 'gn' ] ; const lastName = nameInformation [ 'fn' ] ; const transliteratedFirstName = nameInformation [ 'gnt' ] . replaceAll ( '<' , ' ' ) ; const transliteratedLastName = nameInformation [ 'fnt' ] . replaceAll ( '<' , ' ' ) ; const nameRegex = new RegExp ( '^[\\p{Script=Latin}\\p{P}\\p{M}\\p{Z}]+$' , 'u' ) ; let name ; if ( nameRegex . test ( firstName ) && nameRegex . test ( lastName ) ) { name = `${ firstName } ${ lastName }` ; } else { name = `${ transliteratedFirstName } ${ transliteratedLastName }` ; } let properties ; if ( covidCertificate [ 'v' ] !== undefined ) { this . certificateType = CertificateType . Vaccination ; properties = covidCertificate [ 'v' ] [ 0 ] ; } if ( covidCertificate [ 't' ] !== undefined ) { this . certificateType = CertificateType . Test ; properties = covidCertificate [ 't' ] [ 0 ] ; } if ( covidCertificate [ 'r' ] !== undefined ) { this . certificateType = CertificateType . Recovery ; properties = covidCertificate [ 'r' ] [ 0 ] ; } if ( this . certificateType == undefined ) { throw new Error ( 'certificateType' ) ; } const countryCode = properties [ 'co' ] ; const uvci = properties [ 'ci' ] ; const certificateIssuer = properties [ 'is' ] ; if ( ! ( countryCode in valueSets . countryCodes ) ) { throw new Error ( 'invalidCountryCode' ) ; } const country = valueSets . countryCodes [ countryCode ] . display ; const encodedData = Buffer . from ( body . rawData ) . toString ( 'base64' ) ; const url = window . location . protocol + "//" + window . location . host ; const generic = { headerFields : [ { key : "type" , label : "EU Digital COVID" , value : this . certificateType } ] , primaryFields : [ { key : "name" , label : "Name" , value : name } ] , secondaryFields : [ ] , auxiliaryFields : [ ] , backFields : [ { key : "enlarge" , label : "Enlarging the QR Code" , value : `Inside the Wallet app on iOS, press and hold the link below. This does not work when accessing the Wallet by double-clicking the side button.\n<a href='${ url }/pass#${ encodedData }'>Enlarge QR Code</a>` } , { key : "uvci" , label : "Unique Certificate Identifier (UVCI)" , value : uvci } , { key : "issuer" , label : "Certificate Issuer" , value : certificateIssuer } ] } ; this . rawData = body . rawData ; this . backgroundColor = dark ? body . color : COLORS . WHITE ; this . labelColor = dark ? COLORS . WHITE : COLORS . GREY ; this . foregroundColor = dark ? COLORS . WHITE : COLORS . BLACK ; this . img1x = dark ? Constants . img1xWhite : Constants . img1xBlack ; this . img2x = dark ? Constants . img2xWhite : Constants . img2xBlack ; this . dark = dark ; this . generic = Payload . fillPassData ( this . certificateType , generic , properties , valueSets , country , dateOfBirth , url ) ; } static fillPassData ( type , data , properties , valueSets , country , dateOfBirth , url ) { switch ( type ) { case CertificateType . Vaccination : const dose = `${ properties [ 'dn' ] }/${ properties [ 'sd' ] }` ; const dateOfVaccination = properties [ 'dt' ] ; const medialProductKey = properties [ 'mp' ] ; const manufacturerKey = properties [ 'ma' ] ; if ( ! ( medialProductKey in valueSets . medicalProducts ) ) { throw new Error ( 'invalidMedicalProduct' ) ; } if ( ! ( manufacturerKey in valueSets . manufacturers ) ) { throw new Error ( 'invalidManufacturer' ) ; } const vaccineName = valueSets . medicalProducts [ medialProductKey ] . display . replace ( /\s*\([^)]*\)\s*/g , "" ) ; const manufacturer = valueSets . manufacturers [ manufacturerKey ] . display ; data . secondaryFields . push ( ... [ { key : "dose" , label : "Dose" , value : dose } , { key : "dov" , label : "Date of Vaccination" , value : dateOfVaccination , textAlignment : TextAlignment . right } ] ) ; data . auxiliaryFields . push ( ... [ { key : "vaccine" , label : "Vaccine" , value : vaccineName } , { key : "dob" , label : "Date of Birth" , value : dateOfBirth , textAlignment : TextAlignment . right } ] ) ; data . backFields . push ( ... [ { key : "cov" , label : "Country of Vaccination" , value : country } , { key : "manufacturer" , label : "Manufacturer" , value : manufacturer } , { key : "disclaimer" , label : "Disclaimer" , value : "This certificate is not a travel document. It is only valid in combination with the ID card of the certificate holder and may expire one year + 14 days after the last dose. The validity of this certificate was not checked by CovidPass." } ] ) ; break ; case CertificateType . Test : const testTypeKey = properties [ 'tt' ] ; const testDateTimeString = properties [ 'sc' ] ; const testResultKey = properties [ 'tr' ] ; const testingCentre = properties [ 'tc' ] ; if ( ! ( testResultKey in valueSets . testResults ) ) { throw new Error ( 'invalidTestResult' ) ; } if ( ! ( testTypeKey in valueSets . testTypes ) ) { throw new Error ( 'invalidTestType' ) ; } let testResult = valueSets . testResults [ testResultKey ] . display ; switch ( testResult ) { case 'Not detected' : testResult = 'Negative' ; break ; case 'Detected' : testResult = 'Positive' ; break ; } const testType = valueSets . testTypes [ testTypeKey ] . display ; const testTime = testDateTimeString . replace ( /.*T/ , '' ) . replace ( 'Z' , ' ' ) + 'UTC' ; const testDate = testDateTimeString . replace ( /T.*/ , '' ) ; data . secondaryFields . push ( ... [ { key : "result" , label : "Test Result" , value : testResult } , { key : "dot" , label : "Date of Test" , value : testDate , textAlignment : TextAlignment . right } ] ) ; data . auxiliaryFields . push ( ... [ { key : "time" , label : "Time of Test" , value : testTime } , { key : "dob" , label : "Date of Birth" , value : dateOfBirth , textAlignment : TextAlignment . right } , ] ) ; data . backFields . push ( { key : "cot" , label : "Country of Test" , value : country } ) ; if ( testingCentre !== undefined ) data . backFields . push ( { key : "centre" , label : "Testing Centre" , value : testingCentre } ) ; data . backFields . push ( ... [ { key : "test" , label : "Test Type" , value : testType } , { key : "disclaimer" , label : "Disclaimer" , value : "This certificate is not a travel document. It is only valid in combination with the ID card of the certificate holder and may expire 24h after the test. The validity of this certificate was not checked by CovidPass." } ] ) ; break ; case CertificateType . Recovery : const firstPositiveTestDate = properties [ 'fr' ] ; const validFrom = properties [ 'df' ] ; const validUntil = properties [ 'du' ] ; data . secondaryFields . push ( ... [ { key : "until" , label : "Valid Until" , value : validUntil , } , { key : "dot" , label : "Date of positive Test" , value : firstPositiveTestDate , textAlignment : TextAlignment . right } ] ) ; data . auxiliaryFields . push ( ... [ { key : "from" , label : "Valid From" , value : validFrom , } , { key : "dob" , label : "Date of Birth" , value : dateOfBirth , textAlignment : TextAlignment . right } ] ) ; data . backFields . push ( ... [ { key : "cot" , label : "Country of Test" , value : country } , { key : "disclaimer" , label : "Disclaimer" , value : "This certificate is not a travel document. It is only valid in combination with the ID card of the certificate holder. The validity of this certificate was not checked by CovidPass." } ] ) ; break ; default : throw new Error ( 'certificateType' ) ; } data . backFields . push ( ... [ { key : "credits" , label : "" , value : `Created with <a href='${ url }'>CovidPass</a>` } ] ) ; return data ; } }