use serde::{Deserialize, Serialize};
use serde_bytes::ByteBuf;
use crate::{
assertion::{Assertion, AssertionBase, AssertionCbor},
assertions::labels,
crypto::base64,
error::Result,
};
#[derive(Serialize, Deserialize, Default, Debug, PartialEq, Eq)]
pub struct CertificateStatus {
#[serde(
rename = "ocspVals",
serialize_with = "serialize_bytes_vec",
deserialize_with = "deserialize_bytes_vec"
)]
pub ocsp_vals: Vec<ByteBuf>,
}
impl CertificateStatus {
pub const LABEL: &'static str = labels::CERTIFICATE_STATUS;
pub fn new(ocsp_vals: Vec<Vec<u8>>) -> Self {
let mut cs = CertificateStatus {
ocsp_vals: Vec::new(),
};
for oscp_val in ocsp_vals {
cs.ocsp_vals.push(ByteBuf::from(oscp_val));
}
cs
}
pub fn add_ocsp_vals(mut self, ocsp_vals: Vec<Vec<u8>>) -> Self {
for ocsp_val in ocsp_vals {
self.ocsp_vals.push(ByteBuf::from(ocsp_val));
}
self
}
}
impl AsRef<Vec<ByteBuf>> for CertificateStatus {
fn as_ref(&self) -> &Vec<ByteBuf> {
&self.ocsp_vals
}
}
impl AssertionCbor for CertificateStatus {}
impl AssertionBase for CertificateStatus {
const LABEL: &'static str = Self::LABEL;
fn to_assertion(&self) -> Result<Assertion> {
Self::to_cbor_assertion(self)
}
fn from_assertion(assertion: &Assertion) -> Result<Self> {
Self::from_cbor_assertion(assertion)
}
}
fn serialize_bytes_vec<S>(
bytes_vec: &Vec<ByteBuf>,
serializer: S,
) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
if serializer.is_human_readable() {
let base64_vec: Vec<String> = bytes_vec.iter().map(|buf| base64::encode(buf)).collect();
base64_vec.serialize(serializer)
} else {
bytes_vec.serialize(serializer)
}
}
fn deserialize_bytes_vec<'de, D>(deserializer: D) -> std::result::Result<Vec<ByteBuf>, D::Error>
where
D: serde::Deserializer<'de>,
{
if deserializer.is_human_readable() {
let base64_vec: Vec<String> = Vec::deserialize(deserializer)?;
base64_vec
.into_iter()
.map(|s| {
base64::decode(&s)
.map(ByteBuf::from)
.map_err(serde::de::Error::custom)
})
.collect()
} else {
Vec::<ByteBuf>::deserialize(deserializer)
}
}
#[cfg(test)]
pub mod tests {
#![allow(clippy::expect_used)]
#![allow(clippy::unwrap_used)]
use crate::{assertion::AssertionBase, assertions::CertificateStatus};
#[test]
fn assertions_certificate_status() {
let original = CertificateStatus::new(vec!["ocsp_val".into()]);
assert_eq!(original.ocsp_vals.len(), 1);
let assertion = original.to_assertion().unwrap();
assert_eq!(assertion.mime_type(), "application/cbor");
assert_eq!(assertion.label(), CertificateStatus::LABEL);
let result = CertificateStatus::from_assertion(&assertion).unwrap();
assert_eq!(result, original)
}
#[test]
fn test_json_round_trip() {
let json = serde_json::json!({
"ocspVals" : [
"b2NzcF92YWw=",
""
]
});
let original: CertificateStatus = serde_json::from_value(json).unwrap();
let assertion = original.to_assertion().unwrap();
let result = CertificateStatus::from_assertion(&assertion).unwrap();
assert_eq!(result, original);
}
}