http_msgsign/sign/
base.rs1use 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}