1use alloc::borrow::ToOwned;
4use alloc::boxed::Box;
5use alloc::vec::Vec;
6use core::error::Error;
7use core::fmt;
8use core::marker::PhantomData;
9
10use crate::tokens::SealedToken;
11use crate::{PasetoError, version};
12
13pub trait WriteBytes {
15 fn write(&mut self, slice: &[u8]);
17}
18
19impl<W: WriteBytes> WriteBytes for &mut W {
20 fn write(&mut self, slice: &[u8]) {
21 W::write(self, slice);
22 }
23}
24
25impl WriteBytes for Vec<u8> {
26 fn write(&mut self, slice: &[u8]) {
27 self.extend_from_slice(slice)
28 }
29}
30
31pub trait Payload: Sized {
33 const SUFFIX: &'static str;
37
38 fn encode(self, writer: impl WriteBytes) -> Result<(), Box<dyn Error + Send + Sync>>;
40
41 fn decode(payload: &[u8]) -> Result<Self, Box<dyn Error + Send + Sync>>;
43}
44
45pub trait Footer: Sized {
51 fn encode(&self, writer: impl WriteBytes) -> Result<(), Box<dyn Error + Send + Sync>>;
53
54 fn decode(footer: &[u8]) -> Result<Self, Box<dyn Error + Send + Sync>>;
56}
57
58impl Footer for Vec<u8> {
59 fn encode(&self, mut writer: impl WriteBytes) -> Result<(), Box<dyn Error + Send + Sync>> {
60 writer.write(self);
61 Ok(())
62 }
63
64 fn decode(footer: &[u8]) -> Result<Self, Box<dyn Error + Send + Sync>> {
65 Ok(footer.to_owned())
66 }
67}
68
69impl Footer for () {
70 fn encode(&self, _: impl WriteBytes) -> Result<(), Box<dyn Error + Send + Sync>> {
71 Ok(())
72 }
73
74 fn decode(footer: &[u8]) -> Result<Self, Box<dyn Error + Send + Sync>> {
75 match footer {
76 [] => Ok(()),
77 x => Err(format!("unexpected footer {x:?}").into()),
78 }
79 }
80}
81
82impl<V: version::Version, P: version::Purpose, M: Payload, F> fmt::Display
83 for SealedToken<V, P, M, F>
84{
85 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86 f.write_str(V::HEADER)?;
87 f.write_str(M::SUFFIX)?;
88 f.write_str(P::HEADER)?;
89 crate::base64::write_to_fmt(&self.payload, f)?;
90
91 if !self.encoded_footer.is_empty() {
92 f.write_str(".")?;
93 crate::base64::write_to_fmt(&self.encoded_footer, f)?;
94 }
95
96 Ok(())
97 }
98}
99
100impl<V: version::Version, P: version::Purpose, M: Payload, F: Footer> core::str::FromStr
101 for SealedToken<V, P, M, F>
102{
103 type Err = PasetoError;
104
105 fn from_str(s: &str) -> Result<Self, Self::Err> {
106 let s = s.strip_prefix(V::HEADER).ok_or(PasetoError::InvalidToken)?;
107 let s = s.strip_prefix(M::SUFFIX).ok_or(PasetoError::InvalidToken)?;
108 let s = s.strip_prefix(P::HEADER).ok_or(PasetoError::InvalidToken)?;
109
110 let (payload, footer) = match s.split_once('.') {
111 Some((payload, footer)) => (payload, Some(footer)),
112 None => (s, None),
113 };
114
115 let payload = crate::base64::decode_vec(payload)?.into_boxed_slice();
116 let encoded_footer = footer
117 .map(crate::base64::decode_vec)
118 .transpose()?
119 .unwrap_or_default()
120 .into_boxed_slice();
121 let footer = F::decode(&encoded_footer).map_err(PasetoError::PayloadError)?;
122
123 Ok(Self {
124 payload,
125 encoded_footer,
126 footer,
127 _message: PhantomData,
128 _version: PhantomData,
129 _purpose: PhantomData,
130 })
131 }
132}
133
134macro_rules! serde_str {
135 (
136 impl<$($ident:ident),*> $ty:ty
137 $(where
138 $($path:path: $bound:path,)*
139 )?
140 {
141 fn expecting() { $expecting:expr }
142 }
143 ) => {
144 #[cfg(feature = "serde")]
145 impl<$($ident),*> serde_core::Serialize for $ty
146 $(where
147 $($path: $bound,)*
148 )?
149 {
150 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
151 where
152 S: serde_core::Serializer,
153 {
154 serializer.collect_str(self)
155 }
156 }
157
158 #[cfg(feature = "serde")]
159 impl<'de, $($ident),*> serde_core::Deserialize<'de> for $ty
160 $(where
161 $($path: $bound,)*
162 )?
163 {
164 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
165 where
166 D: serde_core::Deserializer<'de>,
167 {
168 struct Visitor<$($ident),*>(core::marker::PhantomData<($($ident,)*)>);
169 impl<'de, $($ident),*> serde_core::de::Visitor<'de> for Visitor<$($ident),*>
170 $(where
171 $($path: $bound,)*
172 )?
173 {
174 type Value = $ty;
175
176 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
177 formatter.write_fmt($expecting)
178 }
179
180 fn visit_str<Err>(self, v: &str) -> Result<Self::Value, Err>
181 where
182 Err: serde_core::de::Error,
183 {
184 v.parse().map_err(Err::custom)
185 }
186 }
187 deserializer.deserialize_str(Visitor(core::marker::PhantomData))
188 }
189 }
190 };
191}
192
193serde_str!(
194 impl<V, P, M, F> SealedToken<V, P, M, F>
195 where
196 V: version::Version,
197 P: version::Purpose,
198 M: Payload,
199 F: Footer,
200 {
201 fn expecting() {
202 format_args!("a \"{}{}\" paseto", V::HEADER, P::HEADER)
203 }
204 }
205);