We explain how to implement business/validation/verification rules on top of the Digital COVID Certificate. From now on, we'll drop the adjectives, and stick to “Rule”.
A rule in the context of the DCC consists of a logical expression, and some meta data.
The logical expression operates on a specific data structure, and should produce a valuetrue
or false
.
Rules are executed by a CertLogicEngine.
A true
result of a rule's execution/evaluation indicates that the rule “passes”, while a false
is grounds for denying fit-for-travel status.
The data structure a rule operates on can be rendered in JSON format as follows:
{
"payload": <the DCC JSON payload>,
"external": {
"valueSets": <the “compressed” value sets>,
// ...<all other (extra) external parameters>
}
}
The DCC payload JSON must conform to the DCC JSON Schema (currently at version/release 1.3.0), as well as to the technical specification for it.
The “compressed” value sets are derived from the eHN value sets repo. The (extra) external parameters may consist of data like the validation clock.
- Rule
- Description
- External Parameter
- Filter Parameter
- Validation Result
- ValueSet
Rule model contains information about rule and can be sended to CertLogic to validate rule
public enum RuleType: String {
case acceptence = "Acceptance" - Acceptance Rule Type
case invalidation = "Invalidation" - Invalidation Rule Type
}
public enum CertificateType: String {
case general = "General" - Genera Certificate
case vaccination = "Vaccination" - Vaccination Certificate
case recovery = "Recovery" - Recovery Certificate
case test = "Test" - Test Certificate
}
CertificateType used to convert String to Specific format
public class Rule: Codable {
public var identifier: String - Rule identifier
public var type: String - Type of Rule can be Acceptance or Invalidation
public var version: String - Version of Rule
public var schemaVersion: String - Schema version using in the rule
public var engine: String - Engine name now it's only "CertLogic" (not using now)
public var engineVersion: String - Engine version (not using now)
public var certificateType: String - Certification Type one of: "General", "Vaccination", "Recovery", "Test"
public var description: [Description] - Description of rule used for error info
public var validFrom: String - Valid from in String format received from server
public var validTo: String - Valid to in String format received from server
public var affectedString: [String] - Affected sctrings used for get error info
public var logic: JSON - Rule logic - passed to JSONLogic validator
public var countryCode: String - Rule country code Example IT - Italy
public var region: String? - Rule country region code RO - Roma region in Italy
public var hash: String? - Hash value for rule, received from server
public var ruleType: RuleType - Rule type in specific format converted from String
public var certificateFullType: CertificateType - Certificate Type in specific format converted from String
public var validFromDate: Date - Valid From in Date format converted from String
public var validToDate: Date - Valid To in Date format converted from String
public var versionInt: Int - Version of Rule in Int format
}
Description contains information about rule error for specific country
public class Description: Codable {
public var lang: String - Language code, example "EN"
public var desc: String - Description of rule error, example: "Vaccine must contains 2/2 doses"
}
External Parameter - used for send to CertLogic Engine information about user certificate, current date and time and list of ValueSets
public class ExternalParameter: Codable {
public var validationClock: Date - Current Date and Time in iso format
public var valueSets: Dictionary<String, [String]> - List of ValueSets
public var issuerCountryCode: String - Issuer Country code from HCert
public var exp: Date - exp Date from HCert
public var iat: Date - iat Date from HCert
public var kid: String? - kid string from HCert (not used now)
}
Filter Parameter - used for send to CertLogic Engine information we used to filter rules
public class FilterParameter {
public var validationClock: Date - current time
public var countryCode: String - Country code from list of Country's, example "IT", "AT", "DE", "BE"
public var region: String? - Region of Country
public var certificationType: CertificateType = .general - Certification Type from HCert
}
public class ValueSetItem: Codable {
public var display: String
public var lang: String
public var active: Bool
public var system: String
public var version: String
}
ValidationResult - result of CertLogicEngine works. ValidationResult contains information about rule result, can be three different types:
-
fail - Rule failed, this rule not valid and user can't be traveled in this country
-
passed - Rule passed, user can travel in this country
-
open - Rule can't be validated, invalid version, scheme, engine of rule.
public enum Result: Int { case fail = 0 - Fail Status case passed - Passed Status case open - Open Status } public class ValidationResult { public var rule: Rule? - Rule we validate public var result: Result = .open - Result of validation public var validationErrors: [Error]? - List of localized errors we get from Rule validation or from CertLogic }
Before start using CertLogicEngine you need:
-
Set the Rules, to make this use func updateRules, in parameters you need send array of Rule models. This is array of All rules for all counties.
.updateRules(rules: [Rule])
This function always delete all previous rules and set the rusles from new array with Rule objects.
-
Create new Filter Parameter example:
let certType = getCertificationType(type: hCert.type) let countryCode = hCert.ruleCountryCode FilterParameter(validationClock: Date(), countryCode: countryCode, certificationType: certType)
-
Create new External Parameter
Before create External Parameter you need create ValueSets Dictionary
var valueSets = [CertLogic.ValueSet]() public func getValueSetsForExternalParameters() -> Dictionary<String, [String]> { var returnValue = Dictionary<String, [String]>() valueSets.forEach { valueSet in if let keys: [String] = Array(valueSet.valueSetValues.keys) as? [String] { returnValue[valueSet.valueSetId] = keys } } return returnValue }
After that you can create Externa Parameter
ExternalParameter(validationClock: Date(),
valueSets: valueSets,
exp: hCert.exp,
iat: hCert.iat,
issuerCountryCode: hCert.issCode,
kid: hCert.kidStr)
-
Only after creating all of this objects you can use CertLogicEngine to validate certificate with rules you loaded before.
let result = CertLogicEngine().validate(filter: filterParameter, external: externalParameters, payload: hCert.body.description)
Result of .validate function it's array of validation result models: [ValidationResult]. This array contains .fail, .open, .passed results. If you need you can filter them and get only list of .fail or .open resuls.
Any rule should come with automated tests that exercise it. Such tests corroborate the rule writer's intention, but can also be used to check the validity of the execution of the same rule by different rules engines. That's particularly helpful with implementors of verifier apps having free choice in what rules engine to use.
TODO bring up-to-date with other repo
To test this functionality you can run the script run-tests.sh
, which tests all rule sets present against their (respective) tests.
$ ./run-tests.sh