1use std::fmt::{Display, Formatter};
2use std::time::SystemTime;
3
4use indexmap::IndexSet;
5
6use crate::components::params::FieldParameter;
7use crate::components::{Derive, HttpComponent, NameType, TargetField, ToComponent};
8use crate::errors::{HttpComponentError, SignatureParamsError};
9use crate::sign::{ExchangeRecord, SignatureInput, SignerKey};
10
11pub const SIGNATURE_PARAMS: &str = "@signature-params";
12
13#[derive(Debug, Clone)]
14pub struct SignatureParams {
15 covered: IndexSet<TargetField>,
16 created: Option<u64>,
17 gen_created: bool,
18 expires: Option<u64>,
19 algorithm: Option<String>,
20 key_id: Option<String>,
21 nonce: Option<String>,
22 tag: Option<String>,
23}
24
25#[derive(Debug)]
26pub struct KeyPropertyLoadedSignatureParams<'a> {
27 origin: &'a SignatureParams,
28 algorithm: Option<String>,
29 key_id: Option<String>,
30}
31
32impl SignatureParams {
33 pub fn to_component(&self) -> HttpComponent {
36 HttpComponent {
37 id: format!("\"{SIGNATURE_PARAMS}\""),
38 value: Some(self.to_string()),
39 }
40 }
41
42 pub fn request_to_component<B>(
43 &self,
44 request: &http::Request<B>,
45 ) -> Result<IndexSet<HttpComponent>, HttpComponentError> {
46 let mut components = self
47 .covered
48 .iter()
49 .map(|covered| request.to_component(covered))
50 .collect::<Result<IndexSet<_>, HttpComponentError>>()?;
51
52 components.insert(self.to_component());
54
55 Ok(components)
56 }
57
58 pub fn response_to_component<B>(
59 &self,
60 response: &http::Response<B>,
61 ) -> Result<IndexSet<HttpComponent>, HttpComponentError> {
62 let mut components = self
63 .covered
64 .iter()
65 .map(|covered| response.to_component(covered))
66 .collect::<Result<IndexSet<_>, HttpComponentError>>()?;
67
68 components.insert(self.to_component());
70
71 Ok(components)
72 }
73
74 pub fn record_to_component<Req, Res>(
75 &self,
76 record: &ExchangeRecord<Req, Res>,
77 ) -> Result<IndexSet<HttpComponent>, HttpComponentError> {
78 let mut components = self
79 .covered
80 .iter()
81 .map(|covered| record.to_component(covered))
82 .collect::<Result<IndexSet<_>, HttpComponentError>>()?;
83
84 components.insert(self.to_component());
86
87 Ok(components)
88 }
89
90 pub fn load_signer_key<S: SignerKey>(&self, key: &S) -> KeyPropertyLoadedSignatureParams {
91 KeyPropertyLoadedSignatureParams {
92 origin: self,
93 algorithm: Some(S::ALGORITHM.to_string()),
94 key_id: Some(key.key_id().to_string()),
95 }
96 }
97}
98
99impl KeyPropertyLoadedSignatureParams<'_> {
100 pub fn to_component(&self) -> HttpComponent {
101 HttpComponent {
102 id: format!("\"{SIGNATURE_PARAMS}\""),
103 value: Some(self.to_string()),
104 }
105 }
106
107 pub fn request_to_component<B>(
108 &self,
109 request: &http::Request<B>,
110 ) -> Result<IndexSet<HttpComponent>, HttpComponentError> {
111 let mut components = self
112 .origin
113 .covered
114 .iter()
115 .map(|target| request.to_component(target))
116 .collect::<Result<IndexSet<_>, HttpComponentError>>()?;
117
118 components.insert(self.to_component());
120
121 Ok(components)
122 }
123
124 pub fn response_to_component<B>(
125 &self,
126 response: &http::Response<B>,
127 ) -> Result<IndexSet<HttpComponent>, HttpComponentError> {
128 let mut components = self
129 .origin
130 .covered
131 .iter()
132 .map(|target| response.to_component(target))
133 .collect::<Result<IndexSet<_>, HttpComponentError>>()?;
134
135 components.insert(self.to_component());
137
138 Ok(components)
139 }
140
141 pub fn record_to_component<Req, Res>(
142 &self,
143 record: &ExchangeRecord<Req, Res>,
144 ) -> Result<IndexSet<HttpComponent>, HttpComponentError> {
145 let mut components = self
146 .origin
147 .covered
148 .iter()
149 .map(|target| record.to_component(target))
150 .collect::<Result<IndexSet<_>, HttpComponentError>>()?;
151
152 components.insert(self.to_component());
154
155 Ok(components)
156 }
157}
158
159impl SignatureParams {
160 pub fn builder() -> Builder {
161 Builder::default()
162 }
163}
164
165impl From<SignatureInput> for SignatureParams {
166 fn from(value: SignatureInput) -> Self {
167 Self {
168 covered: value.covered,
169 created: value.created,
170 gen_created: false,
171 expires: value.expires,
172 algorithm: value.algorithm,
173 key_id: value.key_id,
174 nonce: value.nonce,
175 tag: value.tag,
176 }
177 }
178}
179
180impl Display for SignatureParams {
181 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
183 let covered = self.covered.iter().fold(String::new(), |acc, id| {
184 if acc.is_empty() {
185 format!("{id}")
186 } else {
187 format!("{acc} {id}")
188 }
189 });
190
191 let at = SystemTime::now()
192 .duration_since(std::time::UNIX_EPOCH)
193 .ok()
194 .map(|d| d.as_secs())
195 .unwrap_or(0);
196
197 let mut base = format!("({})", covered);
198 if self.gen_created {
199 base += &format!(";created={at}")
200 } else if let Some(created) = self.created {
201 base += &format!(";created={created}");
202 }
203
204 if let Some(expires) = self.expires {
205 let expires_at = at + expires;
206 base += &format!(";expires={expires_at}");
207 }
208
209 if let Some(algorithm) = &self.algorithm {
210 base += &format!(";alg=\"{algorithm}\"");
211 }
212
213 if let Some(key_id) = &self.key_id {
214 base += &format!(";keyid=\"{key_id}\"");
215 }
216
217 if let Some(nonce) = &self.nonce {
218 base += &format!(";nonce=\"{nonce}\"");
219 }
220
221 if let Some(tag) = &self.tag {
222 base += &format!(";tag=\"{tag}\"");
223 }
224
225 write!(f, "{}", base)
226 }
227}
228
229impl Display for KeyPropertyLoadedSignatureParams<'_> {
230 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
232 let mut origin = format!("{}", self.origin);
233 if self.origin.algorithm.is_none() {
234 if let Some(algorithm) = &self.algorithm {
235 origin += &format!(";alg=\"{algorithm}\"");
236 }
237 }
238 if self.origin.key_id.is_none() {
239 if let Some(key_id) = &self.key_id {
240 origin += &format!(";keyid=\"{key_id}\"");
241 }
242 }
243 write!(f, "{}", origin)
244 }
245}
246
247pub struct Builder {
248 builder: Result<SignatureParams, SignatureParamsError>,
249}
250
251impl Builder {
253 pub fn add_derive(self, derive: Derive, params: FieldParameter) -> Self {
261 self.and_then(|mut sign_params| {
262 sign_params
263 .covered
264 .insert(TargetField::new(derive.into(), params)?);
265 Ok(sign_params)
266 })
267 }
268
269 pub fn add_header<H>(self, header: H, params: FieldParameter) -> Self
275 where
276 H: TryInto<http::HeaderName>,
277 H::Error: Into<http::Error>,
278 {
279 self.and_then(|mut sign_params| {
280 let header = header.try_into().map_err(Into::into)?;
281 sign_params
282 .covered
283 .insert(TargetField::new(NameType::from(header), params)?);
284 Ok(sign_params)
285 })
286 }
287
288 pub fn set_expires(self, duration_unix: impl Into<u64>) -> Self {
293 self.and_then(|mut sign_params| {
294 sign_params.expires = Some(duration_unix.into());
295 Ok(sign_params)
296 })
297 }
298
299 pub fn set_algorithm(self, algorithm: impl Into<String>) -> Self {
303 self.and_then(|mut sign_params| {
304 sign_params.algorithm = Some(algorithm.into());
305 Ok(sign_params)
306 })
307 }
308
309 pub fn set_key_id(self, key_id: impl Into<String>) -> Self {
313 self.and_then(|mut sign_params| {
314 sign_params.key_id = Some(key_id.into());
315 Ok(sign_params)
316 })
317 }
318
319 pub fn set_nonce(self, nonce: impl Into<String>) -> Self {
323 self.and_then(|mut sign_params| {
324 sign_params.nonce = Some(nonce.into());
325 Ok(sign_params)
326 })
327 }
328
329 pub fn set_tag(self, tag: impl Into<String>) -> Self {
334 self.and_then(|mut sign_params| {
335 sign_params.tag = Some(tag.into());
336 Ok(sign_params)
337 })
338 }
339
340 pub fn gen_created(self) -> Self {
346 self.and_then(|mut sign_params| {
347 sign_params.gen_created = true;
348 Ok(sign_params)
349 })
350 }
351
352 pub fn build(self) -> Result<SignatureParams, SignatureParamsError> {
353 self.builder
354 }
355
356 fn and_then<F>(self, f: F) -> Self
357 where
358 F: FnOnce(SignatureParams) -> Result<SignatureParams, SignatureParamsError>,
359 {
360 Self {
361 builder: self.builder.and_then(f),
362 }
363 }
364}
365
366impl Default for Builder {
367 fn default() -> Self {
368 Self {
369 builder: Ok(SignatureParams {
370 covered: IndexSet::new(),
371 created: None,
372 gen_created: false,
373 expires: None,
374 algorithm: None,
375 key_id: None,
376 nonce: None,
377 tag: None,
378 }),
379 }
380 }
381}