# Presentation definitions ### Presentation Definitions The DIF's spec for presentation exchange provides enough horsepower to do some amazing things https://identity.foundation/presentation-exchange/ ---- ### Presentation Definitions We link in presentation definitions using a hash link so you can verify you're using the same version of the presentation definition as when you specified it in your governance hl:zm9YZpCjPLPJ4Epc:z3TSgaEFFHxY2tsArhUreJ4ixgw9NW7DYuQ9QTPUJFDD ---- ### Presentation Definitions ```json! { "name": "Trusted Traveler Presentation Definition", "purpose": "Multi-vaccine and more...", "comment": "VP, OIDC, DIDComm, or CHAPI outer wrapper here", // Optional "presentation_definition": { "id": "32f54163-7166-48f1-93d8-ff217bdb0653", // Required "submission_requirements": [{ // Optional "name": "Trusted Traveler Health Proof", "rule": "pick", // Can be "pick" or "all" only "count": 1, // We need count only if choose to pick "from": "Health Proof Options" }], ``` ### Nested submission requirements ```json! { "name": "Trusted Traveler Presentation Definition", "purpose": "Multi-vaccine and more...", "comment": "VP, OIDC, DIDComm, or CHAPI outer wrapper here", "presentation_definition": { "id": "32f54163-7166-48f1-93d8-ff217bdb0653", "submission_requirements": [ { "name": "Trusted Traveler", "rule": "pick", "count": 1, "from_nested": [ { "name": "COVID-19 Health Proof Option", "rule": "pick", "count": 1, "from": "Exemption" }, { "name": "COVID-19 Health Proof Option", "rule": "pick", "count": 1, "from": "Vaccine" }, { "name": "COVID-19 Health Proof Option", "rule": "pick", "count": 1, "from": "Lab Result" } ] } ], "input_descriptors": [ { "id": "health_input_1", "name": "Vaccine_Exemption", "group": [ "Exemption" ], "purpose": "stuff", "schema": [ { "uri": "RuuJwd3JMffNwZ43DcJKN1:2:Vaccine_Exemption:1.4", "required": "true" } ], ... { "id": "health_input_2", "name": "Moderna Vaccination", "group": [ "Vaccine" ], "purpose": "stuff", "schema": [ { "uri": "RuuJwd3JMffNwZ43DcJKN1:2:Vaccination:1.4", "required": "true" } ], ... { "id": "health_input_2", "name": "Pfizer Vaccination", "group": [ "Vaccine" ], "purpose": "stuff", "schema": [ { "uri": "RuuJwd3JMffNwZ43DcJKN1:2:Vaccination:1.4", "required": "true" } ], ... ``` ---- ### Presentation Definitions ```json! "input_descriptors": [ { "id": "health_input_3", "name": "Lab_Result", "group": [ "Health Proof Option" ], "purpose": "stuff", "schema": [ { "uri": "RuuJwd3JMffNwZ43DcJKN1:2:Lab_Result:1.4", "required": "true" } ], ``` ---- ### Presentation Definitions ```json! "constraints": { "fields": [ { "path": [ "$.mpid" ], "filter": { "type": "string" } }, { "path": [ "$.patient_local_id" ], "filter": { "type": "string" } }, { "path": [ "$.patient_surnames" ], "filter": { "type": "string" } }, { "path": [ "$.patient_given_names" ], "filter": { "type": "string" } }, { "path": [ "$.patient_date_of_birth" ], "filter": { "type": "string" } }, { "path": [ "$.patient_gender_legal" ], "filter": { "type": "string" } }, { "path": [ "$.patient_street_address" ], "filter": { "type": "string" } }, { "path": [ "$.patient_city" ], "filter": { "type": "string" } }, { "path": [ "$.patient_state_province_region" ], "filter": { "type": "string" } }, { "path": [ "$.patient_postalcode" ], "filter": { "type": "string" } }, { "path": [ "$.patient_country" ], "filter": { "type": "string" } }, { "path": [ "$.patient_phone" ], "filter": { "type": "string" } }, { "path": [ "$.patient_email" ], "filter": { "type": "string" } }, { "path": [ "$.lab_observation_date_time" ], "filter": { "type": "string" } }, { "path": [ "$.lab_result" ], "filter": { "type": "string", "oneOf": [ { "const": "Negative", "dependent_fields": [ { "path": [ "$.lab_specimen_collected_date" ], "filter": { "type": "string", "minimum": "today:-:259200" } } ] }, { "const": "Positive", "dependent_fields": [ { "path": [ "$.lab_specimen_collected_date" ], "filter": { "type": "string", "maximum": "today:-:2419200" } } ] } ] } }, ... ``` ### Cartesian product of sets for input desciptors ```json= ... { "path": [ "$.lab_result" ], "filter": { "type": "string", "oneOf": [ { "const": "Negative", "dependent_fields": [ { "path": [ "$.lab_specimen_collected_date" ], "filter": { "type": "string", "maximum": "today", "minimum": "today:-:259200" } } ] }, { "const": "Positive", "dependent_fields": [ { "path": [ "$.lab_specimen_collected_date" ], "filter": { "type": "string", "maximum": "today:-:2419200" } } ] } ] } }, ... ``` ### Code to handle cartesian product of sets ```javascript= function cartesian(args) { let result = [], max = args.length - 1 // Recursive helper function function helper(arr, i) { for (let j = 0, l = args[i].length; j < l; j++) { let a = arr.slice(0) // clone arr a.push(args[i][j]) if (i == max) { result.push(a) } else helper(a, i + 1) } } helper([], 0) return result } ``` ### Simple input descriptor handler ```javascript= // (eldersonar) Simple input descriptors handler (no in-field conditions) const handleSimpleDescriptors = async ( descriptors, connectionID, type, count, ) => { try { const uid = uuid() let attributes = {} let predicates = {} attributes[uid] = { names: [], } // attributes[uid].names = [] for (let i = 0; i < descriptors.length; i++) { const schema_id = descriptors[i].schema[0].uri const name = descriptors[i].name const comment = `Requesting Presentation for ${descriptors[i].name}` const date = Math.floor(Date.now() / 1000) for (let j = 0; j < descriptors[i].constraints.fields.length; j++) { const path = descriptors[i].constraints.fields[j].path .join('') .split('$.')[1] // (eldersonar) TODO: turn into a loop. This will be not valid if have more than 1 path in the array // Push descriptors into array if (descriptors[i].constraints.fields[j].filter.exclusiveMinimum) { if ( descriptors[i].constraints.fields[ j ].filter.exclusiveMinimum.includes('today:') ) { predicates[path] = { p_type: '>', p_value: date - descriptors[i].constraints.fields[ j ].filter.exclusiveMinimum.split(':')[2], name: path, restrictions: [ { schema_id, }, ], } } else { predicates[path] = { p_type: '>', p_value: date, name: path, restrictions: [ { schema_id, }, ], } } } else if (descriptors[i].constraints.fields[j].filter.minimum) { if ( descriptors[i].constraints.fields[j].filter.minimum.includes( 'today:', ) ) { predicates[path] = { p_type: '>=', p_value: date - descriptors[i].constraints.fields[j].filter.minimum.split( ':', )[2], name: path, restrictions: [ { schema_id, }, ], } } else { predicates[path] = { p_type: '>=', p_value: date, name: path, restrictions: [ { schema_id, }, ], } } } else if ( descriptors[i].constraints.fields[j].filter.exclusiveMaximum ) { if ( descriptors[i].constraints.fields[ j ].filter.exclusiveMaximum.includes('today:') ) { predicates[path] = { p_type: '<', p_value: date - descriptors[i].constraints.fields[ j ].filter.exclusiveMaximum.split(':')[2], name: path, restrictions: [ { schema_id, }, ], } } else { predicates[path] = { p_type: '<', p_value: date, name: path, restrictions: [ { schema_id, }, ], } } } else if (descriptors[i].constraints.fields[j].filter.maximum) { if ( descriptors[i].constraints.fields[j].filter.maximum.includes( 'today:', ) ) { predicates[path] = { p_type: '<=', p_value: date - descriptors[i].constraints.fields[j].filter.maximum.split( ':', )[2], name: path, restrictions: [ { schema_id, }, ], } } else { predicates[path] = { p_type: '<=', p_value: date, name: path, restrictions: [ { schema_id, }, ], } } } else { // (eldersonar) Prepare attributes and create restrictions attributes[uid].names.push(path) attributes[uid].restrictions = [{schema_id: schema_id}] } } // (eldersonar) Assemble presentation request await createPresentationRequest( connectionID, predicates, attributes, name, comment, type, count, ) // (eldersonar) Clear variables at the end of each iteration attributes = {} predicates = {} } } catch (error) { console.log(error) } } ``` ### Request presentation ```javascript! // Governance presentation request const requestPresentation = async (connectionID, type, count) => { console.log(`Requesting Presentation from Connection: ${connectionID}`) const contact = await Contacts.getContactByConnection(connectionID, []) // Update traveler's answer to the question await Travelers.updateProofType(contact.contact_id, type) let pdf = {} if (type === 'Vaccination') { pdf = await Governance.getVaccinePresentationDefinition() } else if (type === 'Lab') { pdf = await Governance.getLabPresentationDefinition() } const inputDescriptors = pdf.presentation_definition.input_descriptors try { const date = Math.floor(Date.now() / 1000) // (eldersonar) Check if we have submission requirments if (pdf.presentation_definition.submission_requirements) { if ( !pdf.presentation_definition.submission_requirements[0].hasOwnProperty( 'from_nested', ) ) { // Loop through the input descriptors let i = inputDescriptors.length // (Eldersonar) Loop through all input descriptors while (i--) { // (eldersonar) Execute if there are any of input descriptors match the submission requirements group value if ( inputDescriptors[i].group.includes( pdf.presentation_definition.submission_requirements[0].from, ) ) { let predicateArray = [] let descriptor = {} descriptor = inputDescriptors[i] console.log('') console.log('array of inputDescriptors') console.log(inputDescriptors) // (Eldersonar) This flag allows to track which input descriptors needs to be removed from the list let remove = false // Loop through all descriptor fields for ( let j = 0; j < inputDescriptors[i].constraints.fields.length; j++ ) { // (Eldersonar) If an input descriptor has some in-field conditional logic if (inputDescriptors[i].constraints.fields[j].filter.oneOf) { // (Eldersonar) Get fields with in-field conditional logic predicateArray.push( inputDescriptors[i].constraints.fields[j].filter.oneOf, ) // (Eldersonar) Mark this input descriptor for deletion remove = true } } // (Eldersonar) Get cartesian sets here if (predicateArray.length) { console.log('') console.log('this is ready to become cartesian set: ') console.log(predicateArray) // (Eldersonar) Assign the result of cartesian product of sets to a variable let cartesianProduct = cartesian(predicateArray, descriptor) await handleCartesianProductSet( descriptor, cartesianProduct, connectionID, type, count, ) // (Eldersonar) Clear the predicate array before new iteration predicateArray = [] descriptor = {} console.log('') console.log('cartesian product of an array set') console.log(cartesianProduct) } cartesianProduct = [] if (i > -1 && remove) { inputDescriptors.splice(i, 1) } } else { console.log( 'There are no credentials of group ' + pdf.presentation_definition.submission_requirements[0].from, ) } } // (eldersonar) TODO: Wrap into an if statement to check if the the rest of the input descriptors are part of the submission requirment group. await handleSimpleDescriptors( inputDescriptors, connectionID, type, count, ) // (eldersonar) Handle nested submission requirments } else { console.log( '...........Handling creating proof requests from the nested submission requirements...........', ) for ( let g = 0; g < pdf.presentation_definition.submission_requirements[0].from_nested .length; g++ ) { let chosenDescriptors = [] for (let f = 0; f < inputDescriptors.length; f++) { if ( inputDescriptors[f].group.includes( pdf.presentation_definition.submission_requirements[0] .from_nested[g].from, ) ) { chosenDescriptors.push(inputDescriptors[f]) } } // Loop through the input descriptors let i = chosenDescriptors.length // (Eldersonar) Loop through all input descriptors while (i--) { // (eldersonar) Execute if there are any of input descriptors match the submission requirements group value if ( chosenDescriptors[i].group.includes( pdf.presentation_definition.submission_requirements[0] .from_nested[g].from, ) ) { let predicateArray = [] let descriptor = {} descriptor = chosenDescriptors[i] // (Eldersonar) This flag allows to track which input descriptors needs to be removed from the list let remove = false // Loop through all descriptor fields for ( let j = 0; j < chosenDescriptors[i].constraints.fields.length; j++ ) { // (Eldersonar) If an input descriptor has some in-field conditional logic if (chosenDescriptors[i].constraints.fields[j].filter.oneOf) { // (Eldersonar) Get fields with in-field conditional logic predicateArray.push( chosenDescriptors[i].constraints.fields[j].filter.oneOf, ) // (Eldersonar) Mark this input descriptor for deletion remove = true } } // (Eldersonar) Get cartesian sets here if (predicateArray.length) { console.log('') console.log('this is ready to become cartesian set: ') console.log(predicateArray) // (Eldersonar) Assign the result of cartesian product of sets to a variable let cartesianProduct = cartesian(predicateArray, descriptor) handleCartesianProductSet( descriptor, cartesianProduct, connectionID, type, count, ) // (Eldersonar) Clear the predicate array before new iteration predicateArray = [] descriptor = {} console.log('') console.log('cartesian product of an array set') console.log(cartesianProduct) } cartesianProduct = [] if (i > -1 && remove) { chosenDescriptors.splice(i, 1) } } else { console.log( 'There are no credentials of group ' + pdf.presentation_definition.submission_requirements[0].from, ) } } // (eldersonar) TODO: Wrap into an if statement to check if the the rest of the input descriptors are part of the submission requirment group. handleSimpleDescriptors(chosenDescriptors, connectionID, type, count) } } } } catch (error) { console.error('Error getting proof options') throw error } } ``` ### Handling presentations ```javascript= // Governance message handler const adminMessage = async (message) => { console.log('Received Presentations Message', message) const governance = await Governance.getGovernance() const privileges = await Governance.getPrivilegesByRoles() if (message.state === 'verified') { let endorserDID = null let schemaID = null const protocol = 'https://didcomm.org/issue-credential/1.0/' // Get cred def id and schema id if (message.presentation && message.presentation.identifiers.length) { endorserDID = message.presentation.identifiers[0].cred_def_id .split(':', 1) .toString() schemaID = message.presentation.identifiers[0].schema_id } // TODO: Check governance and don't send schema id const participantValidated = await Governance.validateParticipant( schemaID, protocol, endorserDID, ) // Update traveler's proof status const contact = await Contacts.getContactByConnection( message.connection_id, ['Traveler'], ) let pdf = {} if (contact.Traveler.dataValues.proof_type === 'Vaccination') { pdf = await Governance.getVaccinePresentationDefinition() } else if (contact.Traveler.dataValues.proof_type === 'Lab') { pdf = await Governance.getLabPresentationDefinition() } else { console.log( "The answer doesn't match any existing presentation exchange files", ) } const inputDescriptors = pdf.presentation_definition.input_descriptors await Travelers.updateProofStatus(contact.contact_id, message.state) if (message.verified === 'true' && participantValidated) { let attributes = '' let predicates = message.presentation.requested_proof.predicates // (mikekebert) Check the data format to see if the presentation requires the referrant pattern if (message.presentation.requested_proof.revealed_attr_groups) { attributes = message.presentation.requested_proof.revealed_attr_groups[ Object.keys( message.presentation.requested_proof.revealed_attr_groups, )[0] // Get first group available ].values // TODO: this needs to be a for-in loop or similar later } else { attributes = message.presentation.requested_proof.revealed_attrs } const issuerName = await getOrganization() let credentialVerifiedAttributes = null if (attributes) { let credentialAttributes = [ { name: 'traveler_surnames', value: attributes.patient_surnames.raw || '', }, { name: 'traveler_given_names', value: attributes.patient_given_names.raw || '', }, { name: 'traveler_date_of_birth', value: attributes.patient_date_of_birth.raw || '', }, { name: 'traveler_gender_legal', value: attributes.patient_gender_legal.raw || '', }, { name: 'traveler_country', value: attributes.patient_country.raw || '', }, { name: 'traveler_origin_country', value: '', }, { name: 'traveler_email', value: attributes.patient_email.raw || '', }, { name: 'trusted_traveler_id', value: uuid(), }, { name: 'trusted_traveler_issue_date_time', value: Math.round( DateTime.fromISO(new Date()).ts / 1000, ).toString(), }, { name: 'trusted_traveler_expiration_date_time', value: Math.round( DateTime.local().plus({days: 30}).ts / 1000, ).toString(), }, { name: 'governance_applied', value: governance.name + ' v' + governance.version, }, { name: 'credential_issuer_name', value: issuerName.dataValues.value.organizationName || '', }, { name: 'credential_issue_date', value: Math.round( DateTime.fromISO(new Date()).ts / 1000, ).toString(), }, ] // Validation happens here // (eldersonar) Check if we have submission requirments if (pdf.presentation_definition.submission_requirements) { // (eldersonar) Execute if there are any of input descriptors match the submission requirements group value if ( !pdf.presentation_definition.submission_requirements[0].hasOwnProperty( 'from_nested', ) ) { for (let i = 0; i < inputDescriptors.length; i++) { console.log('') console.log( `Comparing proof with ${inputDescriptors[i].name} input descriptor`, ) console.log('') let fields = [] let proofResult = false let fieldsValidationResult = false // (eldersonar) Execute if there are any of input descriptors match the submission requirements group value if ( inputDescriptors[i].group.includes( pdf.presentation_definition.submission_requirements[0].from, ) ) { // Get an array of attributes for ( let j = 0; j < inputDescriptors[i].constraints.fields.length; j++ ) { const fieldPath = inputDescriptors[i].constraints.fields[ j ].path .join('') .split('$.')[1] // (eldersonar) TODO: turn into a loop. This will be not valid if have more than 1 path in the array fields.push(fieldPath) } } // (eldersonar) Get and sort the list of proof attributes and descriptor fields const proofAttributeKeys = Object.keys(attributes) const proofPredicateKeys = Object.keys(predicates) const predicatesAndArrays = proofAttributeKeys.concat( proofPredicateKeys, ) const sortedProofFields = predicatesAndArrays.sort(function ( a, b, ) { return a.localeCompare(b) }) const sortedDescriptorFields = fields.sort(function (a, b) { return a.localeCompare(b) }) // (eldersonar) Start validation if (sortedProofFields.length && sortedDescriptorFields.length) { // (eldersonar) Check if there is no array match (no credential match or no predicate match) if ( JSON.stringify(sortedProofFields) != JSON.stringify(sortedDescriptorFields) ) { // (eldersonar) Get leftover fields with the filter let nonDuplicateFields = sortedProofFields.filter( (val) => !sortedDescriptorFields.includes(val), ) for ( let k = 0; k < inputDescriptors[i].constraints.fields.length; k++ ) { // (eldersonar) Check if input descriptor has in-field conditional logic if ( inputDescriptors[i].constraints.fields[k].filter.oneOf ) { for ( let l = 0; l < inputDescriptors[i].constraints.fields[k].filter.oneOf .length; l++ ) { for (let m = 0; m < nonDuplicateFields.length; m++) { const prefix = '$.' let lookupField = '' lookupField += prefix lookupField += nonDuplicateFields[m] // (eldersonar) If we can find the field name in the list of in-field predicates if ( inputDescriptors[i].constraints.fields[ k ].filter.oneOf[l].dependent_fields[0].path.includes( lookupField, ) ) { // (eldersonar) Removing predicate from the list of sorted fields const index = sortedProofFields.indexOf( nonDuplicateFields[m], ) if (index > -1) { sortedProofFields.splice(index, 1) } console.log(sortedProofFields) console.log(sortedDescriptorFields) console.log( JSON.stringify(sortedProofFields) === JSON.stringify(sortedDescriptorFields), ) // (eldersonar) Check if arrays match after the predicates were removed if ( JSON.stringify(sortedProofFields) === JSON.stringify(sortedDescriptorFields) ) { console.log('') console.log( '_____________________________________________', ) console.log('Validation of proof was successful.') fieldsValidationResult = validateFieldByField( attributes, inputDescriptors[i], ) proofResult = true } else { console.log('Validation failed.') proofResult = false } } else { // console.log("Validation failed. No match was found.") proofResult = false } } } } } } // (eldersonar) Perfect match, proof fields are validated! else { console.log('') console.log('_____________________________________________') console.log('Validation of proof was successful.') fieldsValidationResult = validateFieldByField( attributes, inputDescriptors[i], ) proofResult = true } } else { console.log('Error: lacking data for validation') } console.log('') console.log('Validation of proof status is: ', proofResult) console.log( 'Field-by-field validation status is: ', fieldsValidationResult, ) // Check if all level validation passed if (proofResult && fieldsValidationResult) { ... ``` ### Field by field validation ```javascript= const validateFieldByField = (attributes, inputDescriptor) => { // (eldersonar) Value validation happens here let result = null let typePass = false let formatPass = null let valuePass = false let patternPass = false for (let key in attributes) { if (attributes.hasOwnProperty(key)) { console.log('') console.log(key + ' -> ' + attributes[key].raw) // Create prefixed attribute key const prefix = '$.' let prefixedKey = '' prefixedKey += prefix prefixedKey += key for (let p = 0; p < inputDescriptor.constraints.fields.length; p++) { // (eldersonar) Validate if field can be found if (inputDescriptor.constraints.fields[p].path.includes(prefixedKey)) { // (eldersonar) Type validation if (inputDescriptor.constraints.fields[p].filter.type) { switch (inputDescriptor.constraints.fields[p].filter.type) { case 'string': // Support empty string && attributes[key].raw !== "" if (typeof attributes[key].raw === 'string') { // console.log('the type check (STRING) have passed') typePass = true } else { console.log('this is NOT A STRING or STRING IS EMPTY') typePass = false break } break case 'number': if (!isNaN(attributes[key].raw)) { // console.log('the type check (NUMBER) have passed') typePass = true } else { console.log('this is NOT A NUMBER') typePass = false break } break case 'boolean': if ( attributes[key].raw === 'true' || attributes[key].raw === 'false' ) { // console.log('the type check (BOOLEAN) have passed') typePass = true } else { console.log('this is NOT A BOOLEAN') typePass = false break } break default: console.log('Error: The type check failed') typePass = false break } } else { // console.log('no type was found for this attribute') typePass = true } // (eldersonar) Format validation if (inputDescriptor.constraints.fields[p].filter.format) { let dateNumber = parseInt(attributes[key].raw, 10) // (eldersonar) Check if the value can be transformed to a valid number if (attributes[key].raw === '') { // console.log('format passed') formatPass = true } else if (!isNaN(dateNumber)) { // console.log('the date check (NUMBER) have passed') let luxonDate = DateTime.fromMillis(dateNumber).toISO() let date = new DateTime(luxonDate).isValid // (eldersonar) Check if the valid Luxon datetime format if (date) { // console.log('the date is: ', date) // console.log('format passed') formatPass = true } else { // console.log('this is NOT A DATE') console.log('format failed') formatPass = false break } } else { // console.log('this is NOT A DATE') console.log('format failed') formatPass = false break } } else { // console.log('no format was found for this attribute') formatPass = true } // (eldersonar) Value validation if (inputDescriptor.constraints.fields[p].filter.const) { // (eldersonar) Check if the value is a number datatype if (!isNaN(inputDescriptor.constraints.fields[p].filter.const)) { const stringNumber = '' + inputDescriptor.constraints.fields[p].filter.const if (attributes[key].raw === stringNumber) { // console.log('value passed') valuePass = true } else { console.log('value failed') valuePass = false break } } else { if ( attributes[key].raw === inputDescriptor.constraints.fields[p].filter.const ) { // console.log('value passed') valuePass = true } else { console.log('value failed') valuePass = false break } } } else { // console.log('no value was found for this attribute') valuePass = true } // (eldersonar) Pattern validation if (inputDescriptor.constraints.fields[p].filter.pattern) { // Check if it's base64 encoded if (attributes[key].raw === '') { // console.log('pattern passed') patternPass = true } else if ( Buffer.from( inputDescriptor.constraints.fields[p].filter.pattern, 'base64', ).toString('base64') === inputDescriptor.constraints.fields[p].filter.pattern ) { // console.log('decoding....') const decodedPattern = Util.decodeBase64( inputDescriptor.constraints.fields[p].filter.pattern, ) const re = new RegExp(decodedPattern) // (eldersonar) Test pattern if (re.test(attributes[key].raw)) { // console.log('pattern passed') patternPass = true } else { console.log('pattern failed') patternPass = false break } // If not base64 encoded } else { const re = new RegExp( inputDescriptor.constraints.fields[p].filter.pattern, ) // (eldersonar) Test pattern if (re.test(attributes[key].raw)) { // console.log('pattern passed') patternPass = true } else { console.log('pattern failed') patternPass = false break } } } else { // console.log('no pattern was found for this attribute') patternPass = true } } } } // Break out of outer loop if validation failed if (!typePass || !valuePass || !patternPass || !formatPass) { result = false break } else { result = true } } return result } ``` ### Full file example ```json= { "name": "Trusted Traveler Presentation Definition", "purpose": "Multi-vaccine and more...", "comment": "VP, OIDC, DIDComm, or CHAPI outer wrapper here", "presentation_definition": { "id": "32f54163-7166-48f1-93d8-ff217bdb0653", "submission_requirements": [ { "name": "Trusted Traveler Health Proof", "rule": "pick", "count": 1, "from": "Health Proof Option" } ], "input_descriptors": [ { "id": "health_input_1", "name": "Vaccine_Exemption", "group": [ "Health Proof Option" ], "purpose": "stuff", "schema": [ { "uri": "RuuJwd3JMffNwZ43DcJKN1:2:Vaccine_Exemption:1.4", "required": "true" } ], "constraints": { "fields": [ { "path": [ "$.mpid" ], "id": "12345", // Optional "purpose": "Master patient identifier of source that wrote the record to the ledger", // Optional "filter": { // Required "predicate": "required", // Optional "type": "string", // Required "pattern": "did:example:gov1|did:example:gov2" // Optional } }, { "path": [ "$.credentialSubject.patient_local_id", // Normalizing the differences in structure between JSON-LD/JWT-based Verifiable Credentials and vanilla JSON Web Tokens (JWTs) [RFC7519]. "$.vc.credentialSubject.patient_local_id", "$.patient_local_id" ], "filter": { "type": "number", "pattern": "^[0-9]{9}|^([a-zA-Z]){4}([a-zA-Z]){2}([0-9a-zA-Z]){2}([0-9a-zA-Z]{3})?$" // Optional } }, { "path": [ "$.patient_surnames" ], "filter": { "type": "string" } }, { "path": [ "$.patient_given_names" ], "filter": { "type": "string" } }, { "path": [ "$.patient_surnames" ], "filter": { "type": "string" } }, { "path": [ "$.patient_date_of_birth" ], "filter": { "type": "string", "format": "date" } }, { "path": [ "$.patient_gender_legal" ], "filter": { "type": "string", "pattern": "" } }, { "path": [ "$.patient_street_address" ], "filter": { "type": "string" } }, { "path": [ "$.patient_city" ], "filter": { "type": "string" } }, { "path": [ "$.patient_state_province_region" ], "filter": { "type": "string", "pattern": "" } }, { "path": [ "$.patient_postalcode" ], "filter": { "type": "string", "pattern": "" } }, { "path": [ "$.patient_country" ], "filter": { "type": "string", "pattern": "" } }, { "path": [ "$.patient_phone" ], "filter": { "type": "number", "pattern": "" } }, { "path": [ "$.patient_surnames" ], "filter": { "type": "string" } }, { "path": [ "$.patient_email" ], "filter": { "type": "string", "pattern": "" } }, { "path": [ "$.exemption_record_id" ], "filter": { "type": "string" } }, { "path": [ "$.exemption_requestor" ], "filter": { "type": "string" } }, { "path": [ "$.exemption_requestor_relationship" ], "filter": { "type": "string" } }, { "path": [ "$.exemption_issue_date" ], "filter": { "type": "string", "format": "date" } }, { "path": [ "$.exemption_state_province_region" ], "filter": { "type": "string", "pattern": "" } }, { "path": [ "$.exemption_country" ], "filter": { "type": "string", "pattern": "" } }, { "path": [ "$.exemption_type" ], "filter": { "type": "string" } }, { "path": [ "$.exemption_medical_permanent" ], "filter": { "type": "string" } }, { "path": [ "$.exemption_note" ], "filter": { "type": "boolean", "pattern": "true" } }, { "path": [ "$.exemption_from_all" ], "filter": { "type": "string" } }, { "path": [ "$.patient_surnames" ], "filter": { "type": "boolean", "pattern": "true" } }, { "path": [ "$.exemption_diseases_code" ], "filter": { "type": "string" } }, { "path": [ "$.exemption_disease_code_qualifier" ], "filter": { "type": "string" } }, { "path": [ "$.exemption_disease_code_name" ], "filter": { "type": "string" } }, { "path": [ "$.exemption_medical_physician_surnames" ], "filter": { "type": "string" } }, { "path": [ "$.exemption_medical_physician_given_names" ], "filter": { "type": "string" } }, { "path": [ "$.exemption_medical_physician_full_name" ], "filter": { "type": "string" } }, { "path": [ "$.exemption_medical_physician_license_number" ], "filter": { "type": "string" } }, { "path": [ "$.exemption_medical_physician_license_type" ], "filter": { "type": "string" } }, { "path": [ "$.exemption_medical_physician_license_state_province_region" ], "filter": { "type": "string", "pattern": "" } }, { "path": [ "$.exemption_medical_physician_license_country" ], "filter": { "type": "string", "pattern": "" } }, { "path": [ "$.exemption_expiration_date" ], "filter": { "type": "string", "format": "date", "exclusiveMinimum": "today", "required": "true" } }, { "path": [ "$.exemption_credential_issuer" ], "filter": { "type": "string" } }, { "path": [ "$.certificate_original_issuer" ], "filter": { "type": "string" } }, { "path": [ "$.certificate_original_identifier" ], "filter": { "type": "string" } }, { "path": [ "$.credential_issuer_name" ], "filter": { "type": "string" } }, { "path": [ "$.credential_issue_date" ], "filter": { "type": "string", "format": "date" } } ] } }, { "id": "health_input_2", "name": "Vaccination", "group": [ "Health Proof Option" ], "purpose": "stuff", "schema": [ { "uri": "RuuJwd3JMffNwZ43DcJKN1:2:Vaccination:1.4", "required": "true" } ], "constraints": { "fields": [ { "path": [ "$.mpid" ], "filter": { "type": "string" } }, { "path": [ "$.patient_local_id" ], "filter": { "type": "string" } }, { "path": [ "$.sending_facility" ], "filter": { "type": "string" } }, { "path": [ "$.patient_surnames" ], "filter": { "type": "string" } }, { "path": [ "$.patient_given_names" ], "filter": { "type": "string" } }, { "path": [ "$.patient_date_of_birth" ], "filter": { "type": "string", "format": "date" } }, { "path": [ "$.patient_gender_legal" ], "filter": { "type": "string" } }, { "path": [ "$.patient_street_address" ], "filter": { "type": "string" } }, { "path": [ "$.patient_city" ], "filter": { "type": "string" } }, { "path": [ "$.patient_state_province_region" ], "filter": { "type": "string" } }, { "path": [ "$.patient_postalcode" ], "filter": { "type": "string" } }, { "path": [ "$.patient_country" ], "filter": { "type": "string" } }, { "path": [ "$.patient_phone" ], "filter": { "type": "number", "pattern": "" } }, { "path": [ "$.patient_email" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_record_id" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_administration_facility_id" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_administration_facility_id_qualifier" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_administration_facility_name" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_administration_state_province_region" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_administration_postalcode" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_administration_country" ], "filter": { "type": "string", "pattern": "^[0-9]{9}|^([a-zA-Z]){4}([a-zA-Z]){2}([0-9a-zA-Z]){2}([0-9a-zA-Z]{3})?$" } }, { "path": [ "$.vaccine_administration_date" ], "filter": { "type": "string", "exclusiveMaximum": "today:-:1209600" } }, { "path": [ "$.vaccine_dose_number" ], "filter": { "type": "number" } }, { "path": [ "$.vaccine_series_complete" ], "filter": { "const": "true", "type": "boolean", "pattern": "true" } }, { "path": [ "$.vaccine_lot_number" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_code" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_code_qualifier" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_code_name" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_manufacturer_code" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_manufacturer_code_qualifier" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_manufacturer_code_name" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_disease_target_code" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_disease_target_code_qualifier" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_disease_target_name" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_administration_provider_id" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_administration_provider_id_qualifier" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_administration_provider_fullname" ], "filter": { "type": "string" } }, { "path": [ "$.vaccine_education_reference_material" ], "filter": { "type": "string" } }, { "path": [ "$.certificate_original_issuer" ], "filter": { "type": "string" } }, { "path": [ "$.certificate_original_identifier" ], "filter": { "type": "string" } }, { "path": [ "$.credential_issuer_name" ], "filter": { "type": "string" } }, { "path": [ "$.credential_issue_date" ], "filter": { "type": "string", "format": "date" } } ] } }, { "id": "health_input_3", "name": "Lab_Result", "group": [ "Health Proof Option" ], "purpose": "stuff", "schema": [ { "uri": "RuuJwd3JMffNwZ43DcJKN1:2:Lab_Result:1.4", "required": "true" } ], "constraints": { "fields": [ { "path": [ "$.mpid" ], "filter": { "type": "string" } }, { "path": [ "$.patient_local_id" ], "filter": { "type": "string" } }, { "path": [ "$.patient_surnames" ], "filter": { "type": "string" } }, { "path": [ "$.patient_given_names" ], "filter": { "type": "string" } }, { "path": [ "$.patient_date_of_birth" ], "filter": { "type": "string" } }, { "path": [ "$.patient_gender_legal" ], "filter": { "type": "string" } }, { "path": [ "$.patient_street_address" ], "filter": { "type": "string" } }, { "path": [ "$.patient_city" ], "filter": { "type": "string" } }, { "path": [ "$.patient_state_province_region" ], "filter": { "type": "string" } }, { "path": [ "$.patient_postalcode" ], "filter": { "type": "string" } }, { "path": [ "$.patient_country" ], "filter": { "type": "string" } }, { "path": [ "$.patient_phone" ], "filter": { "type": "string" } }, { "path": [ "$.patient_email" ], "filter": { "type": "string" } }, { "path": [ "$.lab_observation_date_time" ], "filter": { "type": "string" } }, { "path": [ "$.lab_result" ], "filter": { "type": "string", "oneOf": [ { "const": "Negative", "dependent_fields": [ { "path": [ "$.lab_specimen_collected_date" ], "filter": { "type": "string", "minimum": "today:-:259200" } } ] }, { "const": "Positive", "dependent_fields": [ { "path": [ "$.lab_specimen_collected_date" ], "filter": { "type": "string", "maximum": "today:-:2419200" } } ] } ] } }, { "path": [ "$.lab_specimen_type" ], "filter": { "type": "string" } }, { "path": [ "$.lab_result_status" ], "filter": { "type": "string" } }, { "path": [ "$.lab_coding_qualifier" ], "filter": { "type": "string" } }, { "path": [ "$.lab_code" ], "filter": { "type": "string" } }, { "path": [ "$.lab_description" ], "filter": { "type": "string" } }, { "path": [ "$.lab_order_id" ], "filter": { "type": "string" } }, { "path": [ "$.lab_normality" ], "filter": { "type": "string" } }, { "path": [ "$.lab_comment" ], "filter": { "type": "string" } }, { "path": [ "$.ordering_facility_id" ], "filter": { "type": "string" } }, { "path": [ "$.ordering_facility_id_qualifier" ], "filter": { "type": "string" } }, { "path": [ "$.ordering_facility_name" ], "filter": { "type": "string" } }, { "path": [ "$.ordering_facility_state_province_region" ], "filter": { "type": "string" } }, { "path": [ "$.ordering_facility_postalcode" ], "filter": { "type": "string" } }, { "path": [ "$.ordering_facility_country" ], "filter": { "type": "string" } }, { "path": [ "$.performing_laboratory_id" ], "filter": { "type": "string" } }, { "path": [ "$.performing_laboratory_id_qualifier" ], "filter": { "type": "string" } }, { "path": [ "$.performing_laboratory_name" ], "filter": { "type": "string" } }, { "path": [ "$.performing_laboratory_state_province_region" ], "filter": { "type": "string" } }, { "path": [ "$.performing_laboratory_postalcode" ], "filter": { "type": "string" } }, { "path": [ "$.performing_laboratory_country" ], "filter": { "type": "string" } }, { "path": [ "$.lab_performed_by" ], "filter": { "type": "string" } }, { "path": [ "$.credential_issuer_name" ], "filter": { "type": "string" } }, { "path": [ "$.credential_issue_date" ], "filter": { "type": "string" } } ] } } ] } } ```