yacme_protocol/
base64.rs

1use std::fmt::Write;
2use std::marker::PhantomData;
3
4use base64ct::Encoding;
5use serde::{de, ser, Serialize};
6
7use crate::fmt::{self, IndentWriter};
8
9/// Wrapper type to indicate that the inner type should be serialized
10/// as bytes with a Base64 URL-safe encoding.
11#[derive(Debug, Clone)]
12pub struct Base64Data<T>(pub T);
13
14impl<T> From<T> for Base64Data<T> {
15    fn from(value: T) -> Self {
16        Base64Data(value)
17    }
18}
19
20impl<T> ser::Serialize for Base64Data<T>
21where
22    T: AsRef<[u8]>,
23{
24    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
25    where
26        S: serde::Serializer,
27    {
28        let target = base64ct::Base64UrlUnpadded::encode_string(self.0.as_ref());
29        serializer.serialize_str(&target)
30    }
31}
32
33impl<T> fmt::AcmeFormat for Base64Data<T>
34where
35    T: AsRef<[u8]>,
36{
37    fn fmt<W: fmt::Write>(&self, f: &mut IndentWriter<'_, W>) -> fmt::Result {
38        write!(
39            f,
40            "b64\"{}\"",
41            base64ct::Base64UrlUnpadded::encode_string(self.0.as_ref())
42        )
43    }
44}
45
46/// Wrapper type to indicate that the inner type should be serialized
47/// as JSON and then Base64 URL-safe encoded and serialized as a string.
48#[derive(Debug, Clone)]
49pub struct Base64JSON<T>(pub T);
50
51impl<T> Base64JSON<T>
52where
53    T: Serialize,
54{
55    pub(crate) fn serialized_value(&self) -> Result<String, serde_json::Error> {
56        let inner = serde_json::to_vec(&self.0)?;
57        Ok(base64ct::Base64UrlUnpadded::encode_string(&inner))
58    }
59}
60
61impl<T> From<T> for Base64JSON<T> {
62    fn from(value: T) -> Self {
63        Base64JSON(value)
64    }
65}
66
67impl<T> fmt::AcmeFormat for Base64JSON<T>
68where
69    T: Serialize,
70{
71    fn fmt<W: fmt::Write>(&self, f: &mut IndentWriter<'_, W>) -> fmt::Result {
72        write!(f, "base64url(")?;
73        f.write_json(&self.0)?;
74        f.write_str(")")
75    }
76}
77
78struct Base64JSONVisitor<T>(PhantomData<T>);
79
80impl<'de, T> de::Visitor<'de> for Base64JSONVisitor<T>
81where
82    T: de::DeserializeOwned,
83{
84    type Value = Base64JSON<T>;
85
86    fn expecting(&self, formatter: &mut std::fmt::Formatter) -> fmt::Result {
87        formatter.write_str("a base64url encoded type")
88    }
89
90    fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
91    where
92        E: de::Error,
93    {
94        let data = base64ct::Base64UrlUnpadded::decode_vec(v)
95            .map_err(|_| E::invalid_value(de::Unexpected::Str(v), &"invalid base64url encoding"))?;
96
97        let data = serde_json::from_slice(&data)
98            .map_err(|err| E::custom(format!("invalid JSON: {err}")))?;
99        Ok(Base64JSON(data))
100    }
101}
102
103impl<'de, T> de::Deserialize<'de> for Base64JSON<T>
104where
105    T: de::DeserializeOwned,
106{
107    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
108    where
109        D: serde::Deserializer<'de>,
110    {
111        deserializer.deserialize_str(Base64JSONVisitor(PhantomData))
112    }
113}
114
115impl<T> ser::Serialize for Base64JSON<T>
116where
117    T: ser::Serialize,
118{
119    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
120    where
121        S: serde::Serializer,
122    {
123        use serde::ser::Error;
124        let inner = self
125            .serialized_value()
126            .map_err(|err| S::Error::custom(format!("Error producing inner JSON: {err}")))?;
127        serializer.serialize_str(&inner)
128    }
129}