-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy patheuropean_test.go
147 lines (122 loc) · 8.86 KB
/
european_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package mobilecore
import (
"testing"
"time"
)
func TestExampleQRs(t *testing.T) {
now := time.Unix(1627462000, 0)
for i, testcase := range qrTestcases {
r1 := ReadEuropeanCredential(testcase.qr)
couldRead := r1.Error == ""
if couldRead != testcase.expectedReadability {
t.Fatal("Expected readability", testcase.expectedReadability, "of testcase", i, r1.Error)
}
r2 := IsDCC(testcase.qr)
if r2 != testcase.expectedReadability {
t.Fatal("Expected IsDCC", testcase.expectedReadability, "of testcase", i)
}
r3 := IsForeignDCC(testcase.qr)
if (testcase.expectedStatus == VERIFICATION_SUCCESS ||
testcase.expectedStatus == VERIFICATION_FAILED_IS_NL_DCC) &&
testcase.qr[0] == 'H' {
if testcase.expectedCountryCode == "NL" {
if r3 {
t.Fatal("Expected isForeignDCC false (NL) for testcase", i)
}
} else if !r3 {
t.Fatal("Expected isForeignDCC true for testcase", i)
}
} else if r3 {
t.Fatal("Expected IsForeignDCC false (unreadable) for testcase", i)
}
r4 := InitializeVerifier("./testdata")
if r4.Error != "" {
t.Fatal("Could not initialize verifier", r4.Error)
}
r5 := verify(testcase.qr, VERIFICATION_POLICY_3G, now)
didVerifyError := r5.Error != ""
expectError := testcase.expectedStatus == VERIFICATION_FAILED_ERROR
if didVerifyError != expectError {
t.Fatal("Presence of verification error is", didVerifyError, "while expecting", expectError, r5.Error)
}
if r5.Status != testcase.expectedStatus {
t.Fatal("Expected status", testcase.expectedStatus, "of testcase", i, "but got", r5.Status)
}
if testcase.expectedStatus != VERIFICATION_SUCCESS {
continue
}
testcase.expectedDetails.IssuerCountryCode = testcase.expectedCountryCode
if *r5.Details != *testcase.expectedDetails {
t.Fatal("Unexpected details for testcase", i)
}
}
}
func TestParseBirthDay(t *testing.T) {
cases := [][]string{
{"1980-01-12", "valid", "1980", "01", "12"},
{"2006-06-24", "valid", "2006", "06", "24"},
{"2020-12-05", "valid", "2020", "12", "05"},
{"1980-01", "valid", "1980", "01", ""},
{"1980", "valid", "1980", "", ""},
{"", "valid", "", "", ""},
{"1980-1-12", "invalid"},
{"1980-1--12", "invalid"},
{"1980-1-12", "invalid"},
{"1980-a1-12", "invalid"},
// We don't actually check if the date exists
{"1980-13-12", "valid", "1980", "13", "12"},
{"1980-02-31", "valid", "1980", "02", "31"},
{"1980-06-41", "valid", "1980", "06", "41"},
{"1980-31", "valid", "1980", "31", ""},
}
for i, c := range cases {
y, m, d, err := parseDateOfBirth(c[0])
if c[1] == "valid" {
if err != nil {
t.Fatal("Error on valid case", i)
}
if y != c[2] || m != c[3] || d != c[4] {
t.Fatal("Invalid value on case", i)
}
} else {
if err == nil {
t.Fatal("No error on invalid case", i)
}
}
}
}
type qrTestcase struct {
qr []byte
expectedStatus int
expectedDetails *VerificationDetails
expectedReadability bool
expectedCountryCode string
}
var defaultQR = []byte(`HC1:NCFA20690T9WTWGVLK-49NJ3B0J$OCC*AX*4FBBD%1*702T9DN03E53F3560+$GY50.FK8ZKO/EZKEZ967L6C56GVC*JC1A6C%63W5Y96.96TPCBEC7ZKW.C%DDDZC.H8B%E5$CLPCG/D%DD*X8AH8MZAGY8 JC0/DAC81/DMPCG/DFUCL+9VY87:EDOL9WEQDD+Q6TW6FA7C466KCN9E%961A6DL6FA7D46.JCP9EJY8L/5M/5546.96VF6.JCBECB1A-:8$966469L6OF6VX6FVCPD0KQEPD0LVC6JD846Y96D464W5B56UPCBJCOT9+EDL8FHZ95/D QEALEN44:+C%69AECAWE:34: CJ.CZKE9440/D+34S9E5LEWJC0FD3%4AIA%G7ZM81G72A6J+9RG7SNAH7B5OAU1B2X6LH86T9N096*6G%6AF60Z9P48Q1RI.3/LC8LNQ5RK/4N$4E0W WMH/3OQC2:B0WV4JQS0DH-D$23UJNUL6U*9GDIFL06+61DHX85TD34009K5DIURQAK6RT5B000FGWI%3L*E`)
var nlQR = []byte(`HC1:NCFA20690T9WTWGVLK-49NJ3B0J$OCC*AX*4FBBD%1*70J+9DN03E53F3560.PQY50.FK8ZKO/EZKEZ967L6C56GVC*JC1A6C%63W5Y96.96TPCBEC7ZKW.C%DDDZC.H8B%E5$CLPCG/D%DD*X8AH8MZAGY8 JC0/DAC81/DMPCG/DFUCL+9VY87:EDOL9WEQDD+Q6TW6FA7C466KCN9E%961A6DL6FA7D46.JCP9EJY8L/5M/5546.96VF6.JCBECB1A-:8$966469L6OF6VX6FVCPD0KQEPD0LVC6JD846Y96D464W5B56UPCBJCOT9+EDL8FHZ95/D QEALEN44:+C%69AECAWE:34: CJ.CZKE9440/D+34S9E5LEWJC0FD3%4AIA%G7ZM81G72A6J+9RG7SNAH7B5OAU1B2X6LH86T9N096*6G%6AF60Z9498-.ETWJB/ON3B+XAK7DF%HPZE9$BYKQUOF4:F25NZD0P6E+-0D%C4-3ISRA:PLO0PN6FN9HN0UUB7BBC%MB EXP8HE821WV%K000FGW6%II9F`)
var cuwSubjectAltNameQR = []byte(`HC1:NCF120F90T9WTWGVLK679LDU%KDP:M$-FX*4FBB4W0*70J+9DN03E53F35%63/FY50.FK8ZKO/EZKEZ967L6C56GVC*JC1A6C%63W5Y96.96TPCBEC7ZKW.CZ-C/ C/PDXKEW.C8WEHS8FN9GY8 JC0/DAC81/DMPCG/DFUCL+9VY87:EDOL9WEQDD+Q6TW6FA7C466KCK9E2H9G:6V6BEM6Q$D.UDRYA 96NF6L/5SW6VX6B$D% D3IA4W5646646-96:96XJC +D3KC-SCXJCCWENF6OF63W59%6.96WJCT3EJ+9%JC+QENQ4ZED+EDKWE3EFX3ET34X C:VDG7D82BUVDGECDZCCECRTCUOA04E4WEOPCN8FHZA1+92ZAQB9746VG7TS9%6BZ6B7C97H9IS86N8P:6769L+AI1A.Q6GK427B3GI2%LNOSX0DNYDFB1B6GQNJ. 2YR1:EAVYME9P71TG:OZV1A%QOGSQ2WRARA1LPZ5PBK.ZLMSGKROVQ4WFD1*DEIOBS9X:8V50U50BDWGBS%2`)
var missingSubjectAltNameQR = []byte(`HC1:NCF120F90T9WTWGVLK589F7I%KDP:M$-FX*4FBB4W0*70J+9DN03E53F35%64:HY50.FK8ZKO/EZKEZ967L6C56GVC*JC1A6C%63W5Y96.96TPCBEC7ZKW.CZ-C/ C/PDXKEW.C8WEHS8FN9GY8 JC0/DAC81/DMPCG/DFUCL+9VY87:EDOL9WEQDD+Q6TW6FA7C466KCK9E2H9G:6V6BEM6Q$D.UDRYA 96NF6L/5SW6VX6B$D% D3IA4W5646646-96:96XJC +D3KC-SCXJCCWENF6OF63W59%6.96WJCT3EJ+9%JC+QENQ4ZED+EDKWE3EFX3ET34X C:VDG7D82BUVDGECDZCCECRTCUOA04E4WEOPCN8FHZA1+92ZAQB9746VG7TS9F690N8*CBAY9LH8V09GTAQ7BL1BSG8.Q6WK427BCGW*/1RSNGLRRGB4C1G3DLDQX:FB5L%.CJTSET2ZF6-KUGVTHW40D4%HUCUHCJETO7RC7QQ2J2LT$1$6DG32INGI 3XVMZA7V50U507BWO1K80`)
var denylistedQR = []byte(`HC1:NCF%RN%TS3DH0RGPJB/IB-OM7533SR99H9M9*VIHWFA K:SCWH3HXK6UO2Y9SA3/-2E%5G%5TW5A 6+O6XL69/9-3AKI67ZMLEQZ76QW6.V99Q9E$BDZIC9J-XIJZIC0J$PIR$SBZI92K-+T38K:ZJ83BV.T8DUFAB4DNAHLW 70SO:GOLIROGOAQ53+LDYPWGO+9A4EOHCR:36UA73NPZ.4IWM%J81:6G16IFNPCL694F$9DK4LC6DQ4394HW6.Y5K45$84-/5$B4D64OBL395$W15ORL355*K7 O%PQX76LZ6B69X5QG5AFY1OSM3-E5ZM3765WU2IMMQUKPHP-E4/H8$1YCV$QECTUKK60VEQA6E+6UCE.UUMYJ3EVFDU9VU1$D.K9H5CKMQ53K$SC4EHXDE5SBCU7RVKG9LJJDX1V4-T2DD5*J/ZCAUHZDR6UT%1WJBN0-8URPSSNIJE7UH5%5000U50/EW%E2U0`)
var incorrectIssuerQR = []byte(`HC1:6BFOXN%TSMAHN-HJTK6.Q837FEMYV6:D4QA3Y66797$E7AOM6W430S5DO6+I-ML9LOQHIZC4.OI1RM8ZA*LPJX29+KCFF-+K*LPH*AA:GA.D8:AW/IT.7E1ME+8*2LH5OF820OPXC9IB8.A5:S9395*CBVZ0K1HO%0ORN./GZJJV8C SITK292W7*RBT1ON1EYHEQMIE9WT0K3M9UVZSVV*001HW%8UE9.955B9-NT0 2$$0X4PCY0+-CVYCDEBD0HX2JR$4O1K8KES/F-1JJ.KYII$GGX2M$C9.-B97U: KV%N %OU O4+G$UA6QKU IV*OI%KY*N9%LG O60SB+P9PK5-Q8%M-LI:7PV8PDJ3H3B 34Z.2WBPM.SY$NKUDN1B%18Y10UBR$641-ST*QGTAAY7.Y7U01 /287MRHMU/2/0GESOXESEP6K5IWYHHVN9GB%RMPRJZ/2+S4Y1QZJ498P6RV5XJ67EE/R1.DAVKBT53 F9IK6+4WM7N1BKRFO4CT2G910VI9E1`)
var defaultDetails = &VerificationDetails{"1", "1", "XX", "A", "D", "15", "01"}
var frenchVerificationDetails = &VerificationDetails{"1", "0", "FR", "J", "A", "04", "08"}
var wholeNumberFloatDoseQR = []byte(`HC1:NCF%RN%TS3DH0RGPJB/IB-OM7533SR769CIN3XHW2KWP5IJBOJAFYHPI1SA3/-2E%5G%5TW5A 6+O6XL69/9-3AKI6/Q6LEQZ76UW6S$99Q9E$BDZIJ7JGOIRHSK2C%0KJZIC0JYPI2SSK S.-3O4UBZI92K3TSH7JPOJZ0KRPI/JTPCTHABVCNAHLW 70SO:GOLIROGO3T59YLLYP-HQLTQV*OOGOBR7Z6NC8P$WA3AA9EPBDSM+QFE4:/6N9R%EPXCROGO3HOWGOKEQ395WDUK:V9Z0O598+94DM.J9WVHWVH+ZE5%PUU1NTIUZUG-VVLIWQHSUAOP6OH6XO9IE5IVU5P2-GA*PE+E6MPO+SEMF2/GA H2.GA JG TUAJ9WLIFO5HI8J.V/I8*Z7ON1Z:LBYFEKG*ZNLT7P 7:%BU*R/L0..P5:PGSG7 9RWIXJ40H1-BW42R$D8*ZSDTOVETQTB+:RHALY3WKAJVINC/RS$B.FC+.TAWPHWC5:1/77I*5+7N UMJRF/ORN 9AKF:ONZQNT4L72V6H6$%9224U50-BWLTUB5`)
var fractionalFloatDoseQR = []byte(`HC1:NCF%RN%TS3DH0RGPJB/IB-OM7533SR769FLT3XHW2KWP5IJBOJAFYHPI1SA3/-2E%5G%5TW5A 6+O6XL69/9-3AKI6/Q6LEQZ76UW6S$99Q9E$BDZIJ7JGOIRHSK2C%0KJZIC0JYPI2SSK S.-3O4UBZI92K3TSH7JPOJZ0KRPI/JTPCTHABVCNAHLW 70SO:GOLIROGO3T59YLY1S7HOPC5NDOEC5L64HX6IAS3DS2980IQ.DPL95OD6%28%%BPHQOGO+GOT*OBR7 Z4VBNL+1U46UF5/NVVAW+PPWC5PF6846A$QY76UW6VY9U3Q5WUZE98T5LAAY0Q$UPR$5:NLOEPNRAE69K PBKPC21%.PTM9*H9699LN9O11$DPPF5PK9CZL*H1VUUME1L8VNF6H*MF U8LELE1*.1-9VW11B%EHE14+1E*U6W1-Q6/LAPMHO99Y0VL+A*JKMJ58QKSAQQEHR8KS+D5DOGWF4EC6*MKSLFG5:SRWX1T554EWCNSQ%KD-T487*7H9DDF:KO:LKNVK/DHPUC+D1H0A:M88G000FGWSXB2 F`)
var qrTestcases = []*qrTestcase{
{defaultQR, VERIFICATION_SUCCESS, defaultDetails, true, "LL"},
{defaultQR[:50], VERIFICATION_FAILED_ERROR, nil, false, ""},
{defaultQR[6:], VERIFICATION_FAILED_UNRECOGNIZED_PREFIX, nil, false, ""},
{nlQR, VERIFICATION_FAILED_IS_NL_DCC, nil, true, "NL"},
// Special case of a missing prefix because of a T-Systems app problem
{defaultQR[4:], VERIFICATION_SUCCESS, defaultDetails, false, "LL"},
// Special case of float values that should be ints (Ireland)
{wholeNumberFloatDoseQR, VERIFICATION_SUCCESS, defaultDetails, true, "IE"},
{fractionalFloatDoseQR, VERIFICATION_FAILED_ERROR, defaultDetails, false, ""},
// QRs signed with a kid (in testdata) that either has the CUW subject alternative name, or a missing one
{cuwSubjectAltNameQR, VERIFICATION_SUCCESS, defaultDetails, true, "CW"},
{missingSubjectAltNameQR, VERIFICATION_FAILED_IS_NL_DCC, nil, true, "NL"},
// QR which has been denylisted in the (testdata) config
{denylistedQR, VERIFICATION_FAILED_ERROR, nil, true, ""},
// QR with "CNAM" as issuer, which should be corrected to "FR" based on the configured verification rules
{incorrectIssuerQR, VERIFICATION_SUCCESS, frenchVerificationDetails, true, "FR"},
}