Skip to main content

http_msgsign/sign/
base.rs

1use std::fmt::Display;
2
3use http::HeaderMap;
4use indexmap::IndexSet;
5
6use crate::base64::Base64EncodedString;
7use crate::components::HttpComponent;
8use crate::errors::{HttpComponentError, VerificationError};
9use crate::sign::{ExchangeRecord, SignatureParams, SignerKey, VerifierKey};
10
11#[derive(Debug)]
12pub struct SignatureBase<'a> {
13    params: &'a SignatureParams,
14    covered: IndexSet<HttpComponent>,
15}
16
17impl<'a> SignatureBase<'a> {
18    pub fn from_request<B>(
19        request: &http::Request<B>,
20        params: &'a SignatureParams,
21    ) -> Result<Self, HttpComponentError> {
22        Ok(Self {
23            params,
24            covered: params.request_to_component(request)?,
25        })
26    }
27
28    pub fn from_request_with_signer_key<B>(
29        request: &http::Request<B>,
30        params: &'a SignatureParams,
31        key: &impl SignerKey,
32    ) -> Result<Self, HttpComponentError> {
33        Ok(Self {
34            params,
35            covered: params.load_signer_key(key).request_to_component(request)?,
36        })
37    }
38
39    pub fn from_response<B>(
40        response: &http::Response<B>,
41        params: &'a SignatureParams,
42    ) -> Result<Self, HttpComponentError> {
43        Ok(Self {
44            params,
45            covered: params.response_to_component(response)?,
46        })
47    }
48
49    pub fn from_response_with_signer_key<B>(
50        response: &http::Response<B>,
51        params: &'a SignatureParams,
52        key: &impl SignerKey,
53    ) -> Result<Self, HttpComponentError> {
54        Ok(Self {
55            params,
56            covered: params
57                .load_signer_key(key)
58                .response_to_component(response)?,
59        })
60    }
61
62    pub fn from_exchange_record<Req, Res>(
63        exchange_record: &ExchangeRecord<Req, Res>,
64        params: &'a SignatureParams,
65    ) -> Result<Self, HttpComponentError> {
66        Ok(Self {
67            params,
68            covered: params.record_to_component(exchange_record)?,
69        })
70    }
71
72    pub fn from_exchange_record_with_signer_key<Req, Res>(
73        exchange_record: &ExchangeRecord<Req, Res>,
74        params: &'a SignatureParams,
75        key: &impl SignerKey,
76    ) -> Result<Self, HttpComponentError> {
77        Ok(Self {
78            params,
79            covered: params
80                .load_signer_key(key)
81                .record_to_component(exchange_record)?,
82        })
83    }
84
85    pub fn into_header<S: SignerKey>(self, key: &S, label: &str) -> HeaderMap {
86        let loaded = self.params.load_signer_key(key);
87        let mut header = HeaderMap::new();
88        header.insert(
89            crate::sign::header::SIGNATURE_INPUT,
90            format!("{}={}", label, loaded).parse().unwrap(),
91        );
92        header.insert(
93            crate::sign::header::SIGNATURE,
94            format!("{}={}", label, self.sign_base(key).to_sfv())
95                .parse()
96                .unwrap(),
97        );
98        header
99    }
100
101    fn sign_base(&self, signer: &impl SignerKey) -> Base64EncodedString {
102        Base64EncodedString::new(signer.sign(self.to_string().as_bytes()))
103    }
104
105    pub fn verify(
106        &self,
107        verifier: &impl VerifierKey,
108        signature: &[u8],
109    ) -> Result<(), VerificationError> {
110        verifier.verify(self.to_string().as_bytes(), signature)
111    }
112}
113
114impl Display for SignatureBase<'_> {
115    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116        let Some(sign_base) = self
117            .covered
118            .iter()
119            .map(|component| component.to_string())
120            .reduce(|mut acc, next| {
121                acc += &format!("\n{next}");
122                acc
123            })
124        else {
125            unreachable!(
126                "There should always be @signature-params. In other words, there should never be an empty string."
127            )
128        };
129        write!(f, "{}", sign_base)
130    }
131}