diff --git a/datatypes-examples.xml b/datatypes-examples.xml index 96d5f04..2b8b32b 100644 --- a/datatypes-examples.xml +++ b/datatypes-examples.xml @@ -150,9 +150,15 @@ + + aarsoppgave-bedriftAS-2025 + + + + - 2020-09-21 - 5000 + 2025-01-01 + 42000.00 @@ -407,12 +413,6 @@ - - aarsoppgave-bedriftAS-2025 - - - - Bedrift AS Ansettelseskontrakt @@ -424,9 +424,16 @@ 2025-01-01T10:00:00+02:00 2030-01-01T10:00:00+02:00 Drivers Licence - This document confirms that the holder has a license to drive vehicles under the specified - categories. - + This document confirms that the holder has a license to drive vehicles under the specified categories. - + + Driver’s License + We would like to verify your driver’s license. + + driversLicence + JWT_VC_JSON + + + + \ No newline at end of file diff --git a/datatypes.xsd b/datatypes.xsd index 23c5fbb..b878401 100644 --- a/datatypes.xsd +++ b/datatypes.xsd @@ -1,491 +1,1847 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/readme.md b/readme.md index a504dbf..65ed3d5 100644 --- a/readme.md +++ b/readme.md @@ -22,6 +22,7 @@ |[ShareDocumentsRequestSharingStopped](#sharedocumentsrequestsharingstopped)|Stop sharing of documents for ShareDocumentsRequest| |[SignedDocument](#signeddocument)|Details about a signed document| |[VerifiableCredentialNotice](#verifiablecredentialnotice)|Represents a legal document (Certificate, Licence, Permit, etc.) issued to a single person.| +|[VerifiablePresentationNotice](#verifiablepresentationnotice)|A request for a verifiable presentation. The request must include a credentials query of either dcql_query og simple_query.| ## Appointment @@ -455,24 +456,57 @@ Payment information for an invoice ``` +## OpeningReceipt + +To open the document the user must accept to send an opening receipt + +### Fields + +|Name|Type|Required|Description| +|----|----|--------|-----------| +|group|String|yes|This is the group identifier for the opening receipt| + +### XML + +```xml + + aarsoppgave-bedriftAS-2025 + +``` + +## OpeningReceiptAccepted + +The document has been opened, and the opening receipt has been accepted and sent. + +### Fields + +|Name|Type|Required|Description| +|----|----|--------|-----------| + + +### XML + +```xml + +``` + ## Payslip For treating documents as Payslips. ### Fields -| Name | Type | Required | Description | -|-------------|------------|----------|----------------------------------------| -| paymentDate | LocalDate | no | The date when the salary is paid out | -| netAmount | BigDecimal | no | Net salary, the actual amount paid out | - +|Name|Type|Required|Description| +|----|----|--------|-----------| +|paymentDate|LocalDate|no|The date when the salary is paid out| +|netAmount|BigDecimal|no|Net salary, the actual amount received| ### XML ```xml - 2020-09-21 - 5000 + 2025-01-01 + 42000.00 ``` @@ -1151,44 +1185,6 @@ Stop sharing of documents for ShareDocumentsRequest ```xml ``` -``` - -## OpeningReceipt - -To open the document the user must accept to send an opening receipt - -### Complemented by: -[OpeningReceiptAccepted](#openingreceiptaccepted) - -### Fields - -|Name|Type|Required|Description| -|----|----|--------|-----------| -|group|String|yes|This is the group identifier for the opening receipt| - -### XML - -```xml - - aarsoppgave-bedriftAS-2025 - -``` - -## OpeningReceiptAccepted - -The document has been opened, and the opening receipt has been accepted and sent. - -### Fields - -|Name|Type|Required|Description| -|----|----|--------|-----------| - - -### XML - -```xml - -``` ## SignedDocument @@ -1233,7 +1229,55 @@ Represents a legal document (Certificate, Licence, Permit, etc.) issued to a sin DL-1234567890 2025-01-01T10:00:00+02:00 2030-01-01T10:00:00+02:00 - Drivers Licence - This document confirms that the holder has a license to drive vehicles under the specified categories. + Drivers Licence + This document confirms that the holder has a license to drive vehicles under the specified categories. ``` + +## VerifiablePresentationNotice + +A request for a verifiable presentation. The request must include a credentials query of either dcql_query og simple_query. + +### Fields + +|Name|Type|Required|Description| +|----|----|--------|-----------| +|title|String|yes|The title of the presentation request| +|description|String|yes|A detailed explanation of the presentation request.| +|simpleQuery|[SimpleQuery](#verifiablepresentationnoticesimplequery)|no|A simplified credential query format| +|dcqlQuery|[DcqlQuery](#verifiablepresentationnoticedcqlquery)|no|A credentials query following the Digital Credentials Query Language (DCQL) specification.| + +### VerifiablePresentationNotice.SimpleQuery + +|Name|Type|Required|Description| +|----|----|--------|-----------| +|type|String|no|| +|format|[Format](#verifiablepresentationnoticeformat)|no|| + +### VerifiablePresentationNotice.Format + +Valid values: + +* JWT_VC_JSON +* MSO_MDOC +* SD_JWT + +### VerifiablePresentationNotice.DcqlQuery + +|Name|Type|Required|Description| +|----|----|--------|-----------| +|credentials|List|yes|List of credential queries as per DCQL.| +|credentialSets|List|no|Optional credential sets for advanced DCQL queries.| + +### XML + +```xml + + Driver’s License + We would like to verify your driver’s license. + + driversLicence + JWT_VC_JSON + + +``` diff --git a/src/main/java/no/digipost/api/datatypes/DataType.java b/src/main/java/no/digipost/api/datatypes/DataType.java index 9cad35e..6132fc8 100644 --- a/src/main/java/no/digipost/api/datatypes/DataType.java +++ b/src/main/java/no/digipost/api/datatypes/DataType.java @@ -24,6 +24,7 @@ import no.digipost.api.datatypes.types.share.ShareDocumentsRequestDocumentsShared; import no.digipost.api.datatypes.types.share.ShareDocumentsRequestSharingStopped; import no.digipost.api.datatypes.types.verifiableCredential.VerifiableCredentialNotice; +import no.digipost.api.datatypes.types.verifiableCredential.VerifiablePresentationNotice; @JsonTypeInfo(use = JsonTypeInfo.Id.SIMPLE_NAME, property = "type", include = JsonTypeInfo.As.EXISTING_PROPERTY) @JsonSubTypes({ @@ -47,6 +48,7 @@ , @JsonSubTypes.Type(OpeningReceipt.class) , @JsonSubTypes.Type(OpeningReceiptAccepted.class) , @JsonSubTypes.Type(VerifiableCredentialNotice.class) + , @JsonSubTypes.Type(VerifiablePresentationNotice.class) }) public interface DataType { diff --git a/src/main/java/no/digipost/api/datatypes/DataTypeIdentifier.java b/src/main/java/no/digipost/api/datatypes/DataTypeIdentifier.java index f7c203e..e3fcf13 100644 --- a/src/main/java/no/digipost/api/datatypes/DataTypeIdentifier.java +++ b/src/main/java/no/digipost/api/datatypes/DataTypeIdentifier.java @@ -20,6 +20,7 @@ import no.digipost.api.datatypes.types.share.ShareDocumentsRequestDocumentsShared; import no.digipost.api.datatypes.types.share.ShareDocumentsRequestSharingStopped; import no.digipost.api.datatypes.types.verifiableCredential.VerifiableCredentialNotice; +import no.digipost.api.datatypes.types.verifiableCredential.VerifiablePresentationNotice; import java.util.Collections; import java.util.Map; @@ -62,6 +63,7 @@ public enum DataTypeIdentifier { , OPENING_RECEIPT(OpeningReceipt.class, "OPRC", OpeningReceipt.EXAMPLE) , OPENING_RECEIPT_ACCEPTED(OpeningReceiptAccepted.class, "OPAC", OpeningReceiptAccepted.EXAMPLE) , VERIFIABLE_CREDENTIAL_NOTICE(VerifiableCredentialNotice.class, "VCNO", VerifiableCredentialNotice.EXAMPLE) + , VERIFIABLE_PRESENTATION_NOTICE(VerifiablePresentationNotice.class, "VPNO", VerifiablePresentationNotice.EXAMPLE) ; private final Class dataType; diff --git a/src/main/java/no/digipost/api/datatypes/types/verifiableCredential/DcqlQuery.java b/src/main/java/no/digipost/api/datatypes/types/verifiableCredential/DcqlQuery.java new file mode 100644 index 0000000..cdde866 --- /dev/null +++ b/src/main/java/no/digipost/api/datatypes/types/verifiableCredential/DcqlQuery.java @@ -0,0 +1,133 @@ +package no.digipost.api.datatypes.types.verifiableCredential; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlElementWrapper; +import lombok.*; +import no.digipost.api.datatypes.documentation.Description; + +import java.util.List; + +import static no.digipost.api.datatypes.types.verifiableCredential.Format.*; + +@Value +@AllArgsConstructor +@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) +@With +public class DcqlQuery { + + @XmlElementWrapper(name = "credentials") + @XmlElement(name = "credential") + @JsonProperty("credentials") + @Description("List of credential queries as per DCQL.") + @NotNull + List credentials; + + @XmlElementWrapper(name = "credential_sets") + @XmlElement(name = "credential_set") + @JsonProperty("credential_sets") + @Description("Optional credential sets for advanced DCQL queries.") + List credentialSets; + + + @Value + @AllArgsConstructor + @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) + @With + public static class Credential { + @XmlElement(name = "id") + String id; + + @XmlElement(name = "format") + Format format; + + @XmlElement(name = "meta") + Meta meta; + + @XmlElementWrapper(name = "claims") + @XmlElement(name = "claim") + List claims; + + @XmlElementWrapper(name = "claim_sets") + @XmlElement(name = "claim_set") + @JsonProperty("claim_sets") + List claimSets; + + public static Credential jwtVc(String id, List typeValues) { + return new Credential(id, JWT_VC_JSON, new Meta(typeValues, null, null), null, null); + } + + public static Credential mdoc(String id, String doctypeValue) { + return new Credential(id, MSO_MDOC, new Meta(null, doctypeValue, null), null, null); + } + + public static Credential sdJwt(String id, List vctValues) { + return new Credential(id, SD_JWT, new Meta(null, null, vctValues), null, null); + } + } + + @Value + @AllArgsConstructor + @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) + @With + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class Meta { + @XmlElement(name = "type_values") + @JsonProperty("type_values") + @Description("Must be specified when format is JWT_VC_JSON") + List typeValues; + + @XmlElement(name = "doctype_value") + @JsonProperty("doctype_value") + @Description("Must be specified when format is MSO_MDOC") + String doctypeValue; + + @XmlElementWrapper(name = "vct_values") + @XmlElement(name = "vct_value") + @JsonProperty("vct_values") + @Description("Must be specified when format is SD_JWT") + List vctValues; + } + + @Value + @AllArgsConstructor + @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) + @With + public static class Claim { + @XmlElementWrapper(name = "path") + @XmlElement(name = "path_element") + List path; + + @XmlElement(name = "id") + String id; + + @XmlElementWrapper(name = "values") + @XmlElement(name = "value") + List values; + } + + @Value + @AllArgsConstructor + @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) + @With + public static class ClaimSet { + @XmlElementWrapper(name = "claims") + @XmlElement(name = "claim_id") + List claims; + } + + @Value + @AllArgsConstructor + @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) + @With + public static class CredentialSet { + @XmlElementWrapper(name = "options") + @XmlElement(name = "option") + List options; + + @XmlElement(name = "required") + Boolean required; + } +} diff --git a/src/main/java/no/digipost/api/datatypes/types/verifiableCredential/Format.java b/src/main/java/no/digipost/api/datatypes/types/verifiableCredential/Format.java new file mode 100644 index 0000000..8a00fd9 --- /dev/null +++ b/src/main/java/no/digipost/api/datatypes/types/verifiableCredential/Format.java @@ -0,0 +1,21 @@ +package no.digipost.api.datatypes.types.verifiableCredential; + +import com.fasterxml.jackson.annotation.JsonValue; + +public enum Format { + + JWT_VC_JSON("jwt_vc_json"), + MSO_MDOC("mso_mdoc"), + SD_JWT("sd_jwt"); + + private final String value; + + Format(String value) { + this.value = value; + } + + @JsonValue + public String getValue() { + return value; + } +} diff --git a/src/main/java/no/digipost/api/datatypes/types/verifiableCredential/SimpleQuery.java b/src/main/java/no/digipost/api/datatypes/types/verifiableCredential/SimpleQuery.java new file mode 100644 index 0000000..a44454f --- /dev/null +++ b/src/main/java/no/digipost/api/datatypes/types/verifiableCredential/SimpleQuery.java @@ -0,0 +1,17 @@ +package no.digipost.api.datatypes.types.verifiableCredential; + +import jakarta.xml.bind.annotation.XmlElement; +import lombok.*; + +@Value +@AllArgsConstructor +@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) +@With +public class SimpleQuery { + + @XmlElement(name = "type") + String type; + + @XmlElement(name = "format") + Format format; +} diff --git a/src/main/java/no/digipost/api/datatypes/types/verifiableCredential/VerifiablePresentationNotice.java b/src/main/java/no/digipost/api/datatypes/types/verifiableCredential/VerifiablePresentationNotice.java new file mode 100644 index 0000000..3857eaa --- /dev/null +++ b/src/main/java/no/digipost/api/datatypes/types/verifiableCredential/VerifiablePresentationNotice.java @@ -0,0 +1,71 @@ +package no.digipost.api.datatypes.types.verifiableCredential; + +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlElementWrapper; +import jakarta.xml.bind.annotation.XmlRootElement; +import lombok.*; +import no.digipost.api.datatypes.DataType; +import no.digipost.api.datatypes.documentation.Description; + +import java.util.List; + +import static no.digipost.api.datatypes.types.verifiableCredential.Format.JWT_VC_JSON; + +@XmlRootElement(name = "verifiable-presentation-notice") +@Value +@AllArgsConstructor +@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) +@With +@Description("A request for a verifiable presentation. The request must include a credentials query of either dcql_query og simple_query.") +public class VerifiablePresentationNotice implements DataType { + + @XmlElement(required = true) + @Description("The title of the presentation request") + String title; + + @XmlElement(required = true) + @Description("A detailed explanation of the presentation request.") + String description; + + @XmlElement + @Description("A simplified credential query format") + SimpleQuery simpleQuery; + + @XmlElement + @Description("A credentials query following the Digital Credentials Query Language (DCQL) specification.") + DcqlQuery dcqlQuery; + + + @Value + @AllArgsConstructor + @NoArgsConstructor(force = true, access = AccessLevel.PRIVATE) + @With + public static class Option { + @XmlElementWrapper(name = "credential_ids") + @XmlElement(name = "credential_id") + List credentialIds; + } + + public static VerifiablePresentationNotice EXAMPLE = new VerifiablePresentationNotice( + "Driver’s License", + "We would like to verify your driver’s license.", + new SimpleQuery("driversLicence", JWT_VC_JSON), + null + ); + + // example førerkort with DCQL + public static VerifiablePresentationNotice DCQL_EXAMPLE = new VerifiablePresentationNotice( + "Driver’s License", + "We would like to verify your driver’s license.", + null, + new DcqlQuery( + List.of( + DcqlQuery.Credential.jwtVc( + "credential1", + List.of("driversLicence") + ) + ), + null + ) + ); +} diff --git a/src/main/resources/no/digipost/api/datatypes/types/jaxb.index b/src/main/resources/no/digipost/api/datatypes/types/jaxb.index index 38c3389..9305002 100644 --- a/src/main/resources/no/digipost/api/datatypes/types/jaxb.index +++ b/src/main/resources/no/digipost/api/datatypes/types/jaxb.index @@ -16,5 +16,6 @@ share.ShareDocumentsRequest share.ShareDocumentsRequestSharingStopped share.ShareDocumentsRequestDocumentsShared verifiableCredential.VerifiableCredentialNotice +verifiableCredential.VerifiablePresentationNotice openingreceipt.OpeningReceipt openingreceipt.OpeningReceiptAccepted diff --git a/src/test/java/no/digipost/api/datatypes/types/PresentationNoticeTest.java b/src/test/java/no/digipost/api/datatypes/types/PresentationNoticeTest.java new file mode 100644 index 0000000..0bd8164 --- /dev/null +++ b/src/test/java/no/digipost/api/datatypes/types/PresentationNoticeTest.java @@ -0,0 +1,23 @@ +package no.digipost.api.datatypes.types; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import no.digipost.api.datatypes.types.verifiableCredential.DcqlQuery; +import no.digipost.api.datatypes.types.verifiableCredential.VerifiablePresentationNotice; +import org.junit.jupiter.api.Test; + +public class PresentationNoticeTest { + + @Test + public void dcqlShouldSerializeCorrectlyAsJson() throws JsonProcessingException { + VerifiablePresentationNotice dcqlExample = VerifiablePresentationNotice.DCQL_EXAMPLE; + + DcqlQuery dcqlQuery = dcqlExample.getDcqlQuery(); + ObjectMapper jsonMapper = new ObjectMapper(); + + String dcqlJson = jsonMapper.writeValueAsString(dcqlQuery); + String expected = "{\"credentials\":[{\"id\":\"credential1\",\"format\":\"jwt_vc_json\",\"meta\":{\"type_values\":[\"driversLicence\"]},\"claims\":null,\"claim_sets\":null}],\"credential_sets\":null}"; + + assert dcqlJson.equals(expected); + } +}