diff --git a/crates/claims/crates/data-integrity/core/src/lib.rs b/crates/claims/crates/data-integrity/core/src/lib.rs index 24a8853df..2d5a1b065 100644 --- a/crates/claims/crates/data-integrity/core/src/lib.rs +++ b/crates/claims/crates/data-integrity/core/src/lib.rs @@ -16,6 +16,7 @@ pub mod suite; pub use decode::*; use educe::Educe; pub use options::ProofOptions; +pub use proof::value_or_array; pub use proof::*; use serde::Serialize; use ssi_claims_core::{ diff --git a/crates/claims/crates/data-integrity/core/src/options.rs b/crates/claims/crates/data-integrity/core/src/options.rs index 0ed4e670e..791063bca 100644 --- a/crates/claims/crates/data-integrity/core/src/options.rs +++ b/crates/claims/crates/data-integrity/core/src/options.rs @@ -40,7 +40,12 @@ pub struct ProofOptions { /// Example domain values include: `domain.example`` (DNS domain), /// `https://domain.example:8443` (Web origin), `mycorp-intranet` (bespoke /// text string), and `b31d37d4-dd59-47d3-9dd8-c973da43b63a` (UUID). - #[serde(default, skip_serializing_if = "Vec::is_empty", rename = "domain")] + #[serde( + default, + with = "crate::value_or_array", + skip_serializing_if = "Vec::is_empty", + rename = "domain" + )] pub domains: Vec, /// Used to mitigate replay attacks. diff --git a/crates/claims/crates/data-integrity/core/src/proof/configuration/mod.rs b/crates/claims/crates/data-integrity/core/src/proof/configuration/mod.rs index 0e6fe7146..5e6d1e471 100644 --- a/crates/claims/crates/data-integrity/core/src/proof/configuration/mod.rs +++ b/crates/claims/crates/data-integrity/core/src/proof/configuration/mod.rs @@ -57,7 +57,11 @@ pub struct ProofConfiguration { /// Example domain values include: `domain.example`` (DNS domain), /// `https://domain.example:8443` (Web origin), `mycorp-intranet` (bespoke /// text string), and `b31d37d4-dd59-47d3-9dd8-c973da43b63a` (UUID). - #[serde(skip_serializing_if = "Vec::is_empty", rename = "domain")] + #[serde( + with = "crate::value_or_array", + skip_serializing_if = "Vec::is_empty", + rename = "domain" + )] pub domains: Vec, /// Used to mitigate replay attacks. diff --git a/crates/claims/crates/data-integrity/core/src/proof/configuration/reference.rs b/crates/claims/crates/data-integrity/core/src/proof/configuration/reference.rs index 30668a2a6..20b700163 100644 --- a/crates/claims/crates/data-integrity/core/src/proof/configuration/reference.rs +++ b/crates/claims/crates/data-integrity/core/src/proof/configuration/reference.rs @@ -30,7 +30,11 @@ pub struct ProofConfigurationRef<'a, S: CryptographicSuite> { #[serde(skip_serializing_if = "Option::is_none")] pub expires: Option, - #[serde(skip_serializing_if = "<[String]>::is_empty")] + #[serde( + with = "crate::value_or_array", + skip_serializing_if = "<[String]>::is_empty", + rename = "domain" + )] pub domains: &'a [String], #[serde(skip_serializing_if = "Option::is_none")] @@ -151,7 +155,11 @@ pub struct ProofConfigurationRefWithoutOptions<'a, S: CryptographicSuite> { #[serde(skip_serializing_if = "Option::is_none")] pub expires: Option, - #[serde(skip_serializing_if = "<[String]>::is_empty")] + #[serde( + with = "crate::value_or_array", + skip_serializing_if = "<[String]>::is_empty", + rename = "domain" + )] pub domains: &'a [String], #[serde(skip_serializing_if = "Option::is_none")] diff --git a/crates/claims/crates/data-integrity/core/src/proof/mod.rs b/crates/claims/crates/data-integrity/core/src/proof/mod.rs index 16c138d9c..660462792 100644 --- a/crates/claims/crates/data-integrity/core/src/proof/mod.rs +++ b/crates/claims/crates/data-integrity/core/src/proof/mod.rs @@ -81,7 +81,11 @@ pub struct Proof { /// Example domain values include: `domain.example`` (DNS domain), /// `https://domain.example:8443` (Web origin), `mycorp-intranet` (bespoke /// text string), and `b31d37d4-dd59-47d3-9dd8-c973da43b63a` (UUID). - #[serde(skip_serializing_if = "Vec::is_empty", rename = "domain")] + #[serde( + with = "crate::value_or_array", + skip_serializing_if = "Vec::is_empty", + rename = "domain" + )] pub domains: Vec, /// Used to mitigate replay attacks. @@ -441,3 +445,25 @@ impl<'de, S: DeserializeCryptographicSuite<'de>> Deserialize<'de> for Proofs } } } + +pub mod value_or_array { + use serde::{Deserialize, Serialize}; + use ssi_core::OneOrMany; + + pub fn serialize(value: &[T], serializer: S) -> Result + where + S: serde::Serializer, + { + match value.split_first() { + Some((first, [])) => first.serialize(serializer), + _ => value.serialize(serializer), + } + } + + pub fn deserialize<'de, T: Deserialize<'de>, D>(deserializer: D) -> Result, D::Error> + where + D: serde::Deserializer<'de>, + { + Ok(OneOrMany::deserialize(deserializer)?.into_vec()) + } +}