An example of the JSON payload of a DCC is as follows (with the most important data fields annotated, and explained below):
{
"ver": "1.3.0", (1)
"nam": {
"fn": "Achternaam",
"fnt": "ACHTERNAAM",
"gn": "Voornaam",
"gnt": "VOORNAAM"
},
"dob": "1998-06-06",
"v": [ (2)
{
"tg": "840539006", (3)
"vp": "1119349007",
"mp": "EU/1/20/1528", (4)
"ma": "ORG-100013793",
"dn": 2, (5)
"sd": 2, (6)
"dt": "2021-02-18", (7)
"co": "AW",
"is": "Ministry of Health Welfare and Sport",
"ci": "urn:uvci:01:NL:ad86e2d1f61546d19dbca9b70a950aef"
}
]
}
-
The version of the JSON Schema for the DCC.
-
The vaccination “event”.
-
A code for the disease targeted - matches up with the one value in this so-called value set.
-
A code for the vaccine used - matches up with a value in this value set.
-
The dose number.
-
The number of required doses for this particular vaccine.
-
The date of vaccination.
This represents the second of the two vaccinations needed with the BioNTech/Pfizer COVID-19 vaccin. To determine whether this person is fit-for-travel/-entry, we want to check at least the following things:
-
Whether this vaccination is against COVID-19.
-
Whether the vaccine used is one of the EMA-approved ones.
-
Whether the number of doses is sufficient.
-
Whether this vaccination happened at least 14 days ago, and no more than 365 days ago.
For brevity, and because it uses the current time as external data, we’re going to implement only the last of these rules.
This means that we have to compare the dt
date field with the current date (or date-time).
In quasi-mathematical notation, we have to check whether the following holds:
dt + 14 days <= now <= dt + 365 days
We’re going to implement this rule using CertLogic. CertLogic uses JSON to express rules such as this one, which operate on a certain given data context. For the purposes of the DCC, the data context has to look as follows (conforming to section 7.4 of this document):
{
"payload": <the DCC JSON above>,
"external": {
"validationClock": "2021-07-01T13:37:00.000+02:00", (1)
"valueSets": { (2)
"disease-agent-targeted": [
"840539006"
],
"vaccines-covid-19-names": [
"BBIBP-CorV",
"CVnCoV",
"Convidecia",
"CoronaVac",
"Covaxin",
"EU/1/20/1507",
"EU/1/20/1525",
"EU/1/20/1528",
"EU/1/21/1529",
"EpiVacCorona",
"Inactivated-SARS-CoV-2-Vero-Cell",
"Sputnik-V"
],
<...(IDs of) other value sets...>
}
}
}
-
The current time, as a string in the JSON Schema
date-time
format. -
The
valueSets
sub object should contain a “compression” of the value sets from their GitHub repo. Only the value set IDs are mentioned.
First of all, a DCC can contain a vaccination, a test, or a recovery event.
If a DCC doesn’t contain a vaccination event, then the v
field of the JSON payload will be empty (i.e., have the value undefined
).
It that’s the case, then there will be no dt
field, and trying to perform a date(-time)-comparison doesn’t make sense.
In this case, the rule should produce a value true
because this rule shouldn’t prevent being fit-for-travel/-entry just because the DCC doesn’t represent a vaccination.
We do that as follows with CertLogic:
{
"if": [
{ (1)
"var": "payload.v.0"
},
<date(-time) comparison logic>, (2)
true (3)
]
}
-
The first operand of this if-operation, which is the guard condition.
-
The second operand is the then-branch.
-
The third operand is the else-branch.
This expression uses an if-operation to distinguish between the DCC representing a vaccination event, or something else.
The first operand, which is the guard condition of the if-operation is a var
- or data access-operation.
Such an operation drills down into the data context using the path payload.v.0
, producing null
for any missing/unaddressable value.
With this particular path and the data context from Example data context., the var
-operation produces the object which is the first (with index 0) object in the array value of the v
-field of the payload
object, or a null
value if that’s not present.
If the guard condition produces a null
value, then the third operand, which is the else-branch, gets executed, and is returned as value of the if-operation.
In general, an if-operation executes the then-branch when the guard condition produces a truthy value, and the else-branch when the condition produces a falsy value.
What values are truthy, which are falsy, and which are neither, is specified here.
Now, let’s assume that the DCC we’re dealing with represents a vaccination event - such as in the JSON payload of an example DCC.
To perform date(-time)-comparison, we use the not-after
- and plusTime
-operations.
The not-after
-operation is equivalent to ⇐
and only works for dates and date-times - mixing dates with date-times is fine.
<d1> ⇐ <d2>
evaluates to true
precisely when <d1>
represents
Usually, comparison involves two operands, but in CertLogic, the comparison operations can also have three operands:
{ "not-after": [ <op1>, <op2>, <op3> ] }
performs the logic <op1> ⇐ <op2> and <op2> ⇐ <op3>. That’s especially useful for dealing with date(-time) validity ranges.
Finally, to convert a string containing a date or date-time in any of the allowed formats into an actual date-time, you use plusTime
-operation.
That operation takes three operands: a string with a date or date-time, an integer amount, and a string "day"
, or "hour"
.
It converts the string to a date-time, and adds the specified number of days or hours to that time (UTC-time, disregarding DST transitions).
E.g., the expression to produce the current time is: { "plusTime": [ { "var": "external.validationClock" }, 0, "day" } ] }
.
When we combine all this, we arrive at the following CertLogic expression to perform the comparison dt + 14 days ⇐ now ⇐ dt + 365 days
for a DCC with a vaccincation event, and otherwise produce true
:
{
"if": [
{
"var": "payload.v.0"
},
{
"not-after": [
{ (1)
"plusTime": [
{
"var": "payload.v.0.dt"
},
14,
"day"
]
},
{ (2)
"plusTime": [
{
"var": "external.validationClock"
},
0,
"day"
]
},
{ (3)
"plusTime": [
{
"var": "payload.v.0.dt"
},
365,
"day"
]
}
]
},
true
]
}
-
Expresses:
dt
+ 14 days, withdt
residing inpayload
/v
/[0]
. -
Expresses “now”, or the validation time used by the verifier app.
-
Expresses:
dt
+ 365 days.