http_signature_normalization/
create.rs1use crate::{
3 unix_timestamp, ALGORITHM_FIELD, ALGORITHM_VALUE, CREATED_FIELD, EXPIRES_FIELD, HEADERS_FIELD,
4 KEY_ID_FIELD, SIGNATURE_FIELD,
5};
6use std::time::SystemTime;
7
8#[derive(Debug)]
9pub struct Signed {
13 signature: String,
14 sig_headers: Vec<String>,
15 created: Option<SystemTime>,
16 expires: Option<SystemTime>,
17 key_id: String,
18}
19
20#[derive(Debug)]
21pub struct Unsigned {
26 pub(crate) signing_string: String,
27 pub(crate) sig_headers: Vec<String>,
28 pub(crate) created: Option<SystemTime>,
29 pub(crate) expires: Option<SystemTime>,
30}
31
32impl Signed {
33 pub fn signature_header(self) -> String {
37 self.into_header()
38 }
39
40 pub fn authorization_header(self) -> String {
44 format!("Signature {}", self.into_header())
45 }
46
47 fn into_header(self) -> String {
48 let mapped = self.created.and_then(|c| self.expires.map(|e| (c, e)));
49 let header_parts = if let Some((created, expires)) = mapped {
50 vec![
51 (KEY_ID_FIELD, self.key_id),
52 (ALGORITHM_FIELD, ALGORITHM_VALUE.to_owned()),
53 (CREATED_FIELD, unix_timestamp(created).to_string()),
54 (EXPIRES_FIELD, unix_timestamp(expires).to_string()),
55 (HEADERS_FIELD, self.sig_headers.join(" ")),
56 (SIGNATURE_FIELD, self.signature),
57 ]
58 } else {
59 vec![
60 (KEY_ID_FIELD, self.key_id),
61 (ALGORITHM_FIELD, ALGORITHM_VALUE.to_owned()),
62 (HEADERS_FIELD, self.sig_headers.join(" ")),
63 (SIGNATURE_FIELD, self.signature),
64 ]
65 };
66
67 header_parts
68 .iter()
69 .map(|(k, v)| format!("{}=\"{}\"", k, v))
70 .collect::<Vec<_>>()
71 .join(",")
72 }
73}
74
75impl Unsigned {
76 pub fn sign<F, E>(self, key_id: String, f: F) -> Result<Signed, E>
81 where
82 F: FnOnce(&str) -> Result<String, E>,
83 {
84 (f)(&self.signing_string).map(|signature| Signed {
85 signature,
86 sig_headers: self.sig_headers,
87 created: self.created,
88 expires: self.expires,
89 key_id,
90 })
91 }
92}