Skip to content
This repository was archived by the owner on Sep 15, 2023. It is now read-only.

Commit 333c5ce

Browse files
authored
Merge pull request #23 from admin-ch/feature/sdk-3.0
Update SDK to 3.0.0 with verification mode support
2 parents 804c9f7 + 3af13f6 commit 333c5ce

File tree

14 files changed

+375
-140
lines changed

14 files changed

+375
-140
lines changed

README.md

Lines changed: 139 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,20 @@ The service is now exposed on port 8080 (change the first number in the `-p` arg
3030

3131
Certificates can be verified by sending POST requests to `/v1/verify`, where the payload should be JSON with the following format:
3232
```json
33-
{
33+
{
34+
"mode": "The verification mode, e.g. THREE_G",
3435
"hcert": "The raw payload of the certificate QR code beginning with 'HC1:'"
3536
}
3637
```
38+
The `mode` field must be one of the currently valid verification modes. A list of modes can be obtained with a `GET` request to the `v1/modes` endpoint:
39+
40+
```json
41+
[
42+
"THREE_G",
43+
"TWO_G"
44+
]
45+
```
46+
3747

3848
The endpoint will respond with status code 400 if the certificate couldn't be decoded. Otherwise, it will respond with status code 200 and the following JSON:
3949
```json
@@ -54,128 +64,156 @@ The endpoint will respond with status code 400 if the certificate couldn't be de
5464
"invalidState": "..."
5565
}
5666
```
57-
where only one of the three fields `successState`, `errorState`, `invalidState` is set to a non-null value, thereby indicating the corresponding verification-status.
67+
where only one of the three fields `successState`, `errorState`, `invalidState` is set to a non-null value, thereby indicating the corresponding verification-status. Since the introduction of different verification modes, the presence of the `successState` object is no longer sufficient to indicate the validity of a certificate. You must also check the value of the `successState.successState.modeValidity.modeValidityState` field. It can currently take one of the following values:
68+
69+
| Value | Meaning |
70+
|--------------|----------------------------------------------------|
71+
| SUCCESS | The certificate fulfills all criteria of this mode |
72+
| INVALID | The certificate is not valid under this mode |
73+
| UNKNOWN_MODE | An invalid verification mode was specified |
5874

5975
<details>
6076
<summary>Examples</summary>
6177

6278
Request payload:
6379
```json
64-
{"hcert": "HC1:NCFJ60EG0/3WUWGSLKH47GO0KNJ9DSWQIIWT9CK+500XKY-CE59-G80:84F3ZKG%QU2F30GK JEY50.FK6ZK7:EDOLOPCF8F746KG7+59.Q6+A80:6JM8SX8RM8.A8TL6IA7-Q6.Q6JM8WJCT3EYM8XJC +DXJCCWENF6OF63W5$Q69L6%JC+QE$.32%E6VCHQEU$DE44NXOBJE719$QE0/D+8D-ED.24-G8$:8.JCBECB1A-:8$96646AL60A60S6Q$D.UDRYA 96NF6L/5QW6307KQEPD09WEQDD+Q6TW6FA7C466KCN9E%961A6DL6FA7D46JPCT3E5JDJA76L68463W5/A6..DX%DZJC3/DH$9- NTVDWKEI3DK2D4XOXVD1/DLPCG/DU2D4ZA2T9GY8MPCG/DY-CAY81C9XY8O/EZKEZ96446256V50G7AZQ4CUBCD9-FV-.6+OJROVHIBEI3KMU/TLRYPM0FA9DCTID.GQ$NYE3NPBP90/9IQH24YL7WMO0CNV1 SDB1AHX7:O26872.NV/LC+VJ75L%NGF7PT134ERGJ.I0 /49BB6JA7WKY:AL19PB120CUQ37XL1P9505-YEFJHVETB3CB-KE8EN9BPQIMPRTEW*DU+X2STCJ6O6S4XXVJ$UQNJW6IIO0X20D4S3AWSTHTA5FF7I/J9:8ALF/VP 4K1+8QGI:N0H 91QBHPJLSMNSJC BFZC5YSD.9-9E5R8-.IXUB-OG1RRQR7JEH/5T852EA3T7P6 VPFADBFUN0ZD93MQY07/4OH1FKHL9P95LIG841 BM7EXDR/PLCUUE88+-IX:Q"}
80+
{"mode": "TWO_G", "hcert": "HC1:NCF260VG0/3WUWGSLKH47GO0.TSZV5ZBHU3M8CK8PV*70YM8FN0E$C$T1WY0-FCA0LD97TK0F90IECRHGWJC0FDL:4:KEPH7M/ESDD746KG7+592X61:6WA7Q46PF6XW6M*83:64R6XX8T%61A6WJCT3EYM8%JC+QE$.32%E6VCHQEU$DE44NXOBJE719$QE0/D+8D-ED.24-G8$:83KCZPCNF6OF64W5KF6-96/SA5R6%961G73564KCJPCITA2OA4KCD3DX47B46IL6646H*6KWEKDDC%6-Q6QW66464KCAWE6T9G%6G%67W5JPCT3E6JD646+/6C464W51S6..DX%DZJC1/DI-AXVD3VCI3DYUC6$C5WEW.C7WEV+A:S92T8I3D6WEITA2OA$PC5$CUZC$$5Y$5FBBY10D-ABIHJSEJVDKIDPRT/7D4BN/+40SDH4EIBR2:4$0G4MCT0N6BSWBVN.9AYA.UA4ANCEOUJEKOR04R36QT7A2I20KE JK5N47THHSU..7U05V/6UAKGZ3DPO.KB8-P2DM0RB:PC$65LHU3638$N WI*AP OPCGO:MAF4G*39D8T5C4BR3UMNB1R*Q8I5G35HCPC*V9OZJ0/K:OKTC1N E:JO17HKWQOR81JP0BCBL8%5IA6J8VJMM0L$60$BLNACPAN4NOKQ6XPC8Q2F9B-B$YGHDAFGKY$MS/I1YLYTVC$OHJAX LLKDLHGYAB-SON0A807AMH/CUPQ99TUXEAJ5486FQK1B%A2VM0C569O9AK-DH6MPU:UVPTCZLA:Q-+0EK8G4"}
6581
```
6682

6783
Response for valid certificate:
6884
```json
6985
{
70-
"certificate":{
71-
"version":"1.0.0",
72-
"person":{
73-
"familyName":"vaccine",
74-
"standardizedFamilyName":"VACCINE",
75-
"givenName":"valid from today",
76-
"standardizedGivenName":"VALID<FROM<TODAY"
77-
},
78-
"dateOfBirth":"15.01.1970",
79-
"personName":{
80-
"familyName":"vaccine",
81-
"standardizedFamilyName":"VACCINE",
82-
"givenName":"valid from today",
83-
"standardizedGivenName":"VALID<FROM<TODAY"
84-
},
85-
"formattedDateOfBirth":"15.01.1970"
86-
},
87-
"successState":{
88-
"isLightCertificate":false,
89-
"validityRange":{
90-
"validFrom":[
91-
2021,
92-
10,
93-
13,
94-
0,
95-
0
96-
],
97-
"validUntil":[
98-
2022,
99-
10,
100-
12,
101-
0,
102-
0
103-
]
86+
"certificate": {
87+
"version": "1.0.0",
88+
"person": {
89+
"familyName": "Valid",
90+
"standardizedFamilyName": "VALID",
91+
"givenName": "Vaccine",
92+
"standardizedGivenName": "VACCINE"
93+
},
94+
"dateOfBirth": "05.02.2003",
95+
"personName": {
96+
"familyName": "Valid",
97+
"standardizedFamilyName": "VALID",
98+
"givenName": "Vaccine",
99+
"standardizedGivenName": "VACCINE"
100+
},
101+
"formattedDateOfBirth": "05.02.2003"
102+
},
103+
"successState": {
104+
"successState": {
105+
"modeValidity": {
106+
"mode": "THREE_G",
107+
"modeValidityState": "SUCCESS"
104108
}
105-
},
106-
"errorState":null,
107-
"invalidState":null
109+
},
110+
"isLightCertificate": false
111+
},
112+
"errorState": null,
113+
"invalidState": null
108114
}
109115
```
110116

111117
Response for invalid certificate (e.g. expired)
112118
```json
113119
{
114-
"certificate":{
115-
"version":"1.0.0",
116-
"person":{
117-
"familyName":"vaccine",
118-
"standardizedFamilyName":"VACCINE",
119-
"givenName":"valid until today",
120-
"standardizedGivenName":"VALID<UNTIL<TODAY"
121-
},
122-
"dateOfBirth":"15.01.1970",
123-
"personName":{
124-
"familyName":"vaccine",
125-
"standardizedFamilyName":"VACCINE",
126-
"givenName":"valid until today",
127-
"standardizedGivenName":"VALID<UNTIL<TODAY"
128-
},
129-
"formattedDateOfBirth":"15.01.1970"
130-
},
131-
"successState":null,
132-
"errorState":null,
133-
"invalidState":{
134-
"signatureState":{
135-
136-
},
137-
"revocationState":{
138-
139-
},
140-
"nationalRulesState":{
141-
"validityRange":{
142-
"validFrom":[
143-
2020,
144-
10,
145-
13,
146-
0,
147-
0
148-
],
149-
"validUntil":[
150-
2021,
151-
10,
152-
12,
153-
0,
154-
0
155-
]
156-
},
157-
"ruleId":"VR-CH-0006"
120+
"certificate": {
121+
"version": "1.0.0",
122+
"person": {
123+
"familyName": "Expired",
124+
"standardizedFamilyName": "EXPIRED",
125+
"givenName": "Vaccine",
126+
"standardizedGivenName": "VACCINE"
127+
},
128+
"dateOfBirth": "03.02.1999",
129+
"personName": {
130+
"familyName": "Expired",
131+
"standardizedFamilyName": "EXPIRED",
132+
"givenName": "Vaccine",
133+
"standardizedGivenName": "VACCINE"
134+
},
135+
"formattedDateOfBirth": "03.02.1999"
136+
},
137+
"successState": null,
138+
"errorState": null,
139+
"invalidState": {
140+
"signatureState": {},
141+
"revocationState": {},
142+
"nationalRulesState": {
143+
"validityRange": {
144+
"validFrom": [
145+
2020,
146+
12,
147+
13,
148+
0,
149+
0
150+
],
151+
"validUntil": [
152+
2021,
153+
12,
154+
12,
155+
0,
156+
0
157+
]
158158
},
159-
"validityRange":{
160-
"validFrom":[
161-
2020,
162-
10,
163-
13,
164-
0,
165-
0
166-
],
167-
"validUntil":[
168-
2021,
169-
10,
170-
12,
171-
0,
172-
0
173-
]
174-
}
175-
}
159+
"ruleId": "VR-CH-0006"
160+
},
161+
"validityRange": {
162+
"validFrom": [
163+
2020,
164+
12,
165+
13,
166+
0,
167+
0
168+
],
169+
"validUntil": [
170+
2021,
171+
12,
172+
12,
173+
0,
174+
0
175+
]
176+
}
177+
}
176178
}
177179
```
178180

181+
Response for a certificate that is basically valid (i.e. recognized in Switzerland and within its validity period), but not sufficient for the current verification mode, e.g. a test certificate in 2G (vaccine/recovery only) mode:
182+
183+
```json
184+
{
185+
"certificate": {
186+
"version": "1.0.0",
187+
"person": {
188+
"familyName": "Valid",
189+
"standardizedFamilyName": "VALID",
190+
"givenName": "Test",
191+
"standardizedGivenName": "TEST"
192+
},
193+
"dateOfBirth": "14.06.2007",
194+
"personName": {
195+
"familyName": "Valid",
196+
"standardizedFamilyName": "VALID",
197+
"givenName": "Test",
198+
"standardizedGivenName": "TEST"
199+
},
200+
"formattedDateOfBirth": "14.06.2007"
201+
},
202+
"successState": {
203+
"successState": {
204+
"modeValidity": {
205+
"mode": "TWO_G",
206+
"modeValidityState": "INVALID"
207+
}
208+
},
209+
"isLightCertificate": false
210+
},
211+
"errorState": null,
212+
"invalidState": null
213+
}
214+
```
215+
Pay special attention to the `successState` object. It is present, indicating that the certificate itself is valid, but the `modeValidityState` indicates that it is invalid under the selected mode.
216+
179217
</details>
180218

181219
## Contribution Guide
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package ch.admin.bag.covidcertificate.backend.verification.check.model;
2+
3+
import javax.validation.constraints.NotNull;
4+
5+
public class SimpleControllerPayload extends HCertPayload {
6+
@NotNull
7+
private String mode;
8+
9+
public String getMode() {
10+
return mode;
11+
}
12+
13+
public void setMode(String mode) {
14+
this.mode = mode;
15+
}
16+
}

ch-covidcertificate-backend-verification-check/ch-covidcertificate-backend-verification-check-ws/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
<dependency>
7575
<groupId>ch.admin.bag.covidcertificate</groupId>
7676
<artifactId>sdk-core</artifactId>
77-
<version>2.0.4</version>
77+
<version>3.0</version>
7878
</dependency>
7979

8080
<dependency>

ch-covidcertificate-backend-verification-check/ch-covidcertificate-backend-verification-check-ws/src/main/java/ch/admin/bag/covidcertificate/backend/verification/check/ws/controller/SimpleController.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
package ch.admin.bag.covidcertificate.backend.verification.check.ws.controller;
22

3-
import ch.admin.bag.covidcertificate.backend.verification.check.model.HCertPayload;
3+
import ch.admin.bag.covidcertificate.backend.verification.check.model.SimpleControllerPayload;
44
import ch.admin.bag.covidcertificate.backend.verification.check.ws.model.DecodingException;
55
import ch.admin.bag.covidcertificate.backend.verification.check.ws.model.SimpleVerificationResponse;
66
import ch.admin.bag.covidcertificate.backend.verification.check.ws.verification.VerificationService;
77
import ch.admin.bag.covidcertificate.sdk.core.models.state.VerificationState;
88
import ch.admin.bag.covidcertificate.sdk.core.models.state.VerificationState.ERROR;
99
import ch.admin.bag.covidcertificate.sdk.core.models.state.VerificationState.INVALID;
10+
import ch.admin.bag.covidcertificate.sdk.core.models.trustlist.ActiveModes;
1011
import ch.ubique.openapi.docannotations.Documentation;
1112
import java.time.Instant;
13+
import java.util.List;
14+
import java.util.stream.Collectors;
1215
import org.slf4j.Logger;
1316
import org.slf4j.LoggerFactory;
1417
import org.springframework.context.annotation.Profile;
1518
import org.springframework.http.HttpStatus;
1619
import org.springframework.http.ResponseEntity;
1720
import org.springframework.web.bind.annotation.CrossOrigin;
1821
import org.springframework.web.bind.annotation.ExceptionHandler;
22+
import org.springframework.web.bind.annotation.GetMapping;
1923
import org.springframework.web.bind.annotation.PostMapping;
2024
import org.springframework.web.bind.annotation.RequestBody;
2125
import org.springframework.web.bind.annotation.RequestMapping;
@@ -44,15 +48,18 @@ public SimpleController(VerificationService verificationService) {
4448
})
4549
@CrossOrigin(origins = {"https://editor.swagger.io"})
4650
@PostMapping("/verify")
47-
public @ResponseBody SimpleVerificationResponse verify(@RequestBody HCertPayload hCertPayload) {
51+
public @ResponseBody SimpleVerificationResponse verify(@RequestBody SimpleControllerPayload hCertPayload) {
52+
String verificationMode = hCertPayload.getMode();
4853
final var start = Instant.now();
54+
4955
// Decode hcert
5056
logger.info("Decoding hcert");
5157
final var certificateHolder = verificationService.decodeHCert(hCertPayload);
5258

5359
logger.info("Verifying hcert");
5460
// Verify hcert
55-
final var verificationState = verificationService.verifyDcc(certificateHolder);
61+
final var verificationState = verificationService.verifyDccSingleMode(certificateHolder,
62+
verificationMode);
5663

5764
// Build response
5865
final var simpleVerificationResponse =
@@ -71,7 +78,18 @@ public SimpleController(VerificationService verificationService) {
7178
return simpleVerificationResponse;
7279
}
7380

74-
@ExceptionHandler(DecodingException.class)
81+
@Documentation(
82+
description = "Get currently valid verification modes"
83+
)
84+
@CrossOrigin(origins = {"https://editor.swagger.io"})
85+
@GetMapping("/modes")
86+
public @ResponseBody List<String> getVerificationModes() {
87+
return verificationService.getVerificationModes().stream().map(ActiveModes::getId).collect(
88+
Collectors.toList());
89+
}
90+
91+
92+
@ExceptionHandler(DecodingException.class)
7593
@ResponseStatus(HttpStatus.BAD_REQUEST)
7694
public ResponseEntity<String> invalidHCert(DecodingException e) {
7795
logger.info("Decoding exception thrown: {}", e.getMessage());

ch-covidcertificate-backend-verification-check/ch-covidcertificate-backend-verification-check-ws/src/main/java/ch/admin/bag/covidcertificate/backend/verification/check/ws/controller/VerificationController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public VerificationController(VerificationService verificationService) {
6969
final var certificateHolder = verificationService.decodeHCert(hCertPayload);
7070

7171
// Verify hcert
72-
final var verificationState = verificationService.verifyDcc(certificateHolder);
72+
final var verificationState = verificationService.verifyDccAllModes(certificateHolder);
7373

7474
// Build response
7575
final var verificationResponse = new VerificationResponse();

0 commit comments

Comments
 (0)