Skip to main content

http_msgsign/sign/
input.rs

1use std::collections::HashMap;
2
3use indexmap::IndexSet;
4use sfv::{BareItem, Dictionary, InnerList, ListEntry};
5
6use crate::components::TargetField;
7use crate::errors::{InvalidFormat, SignatureInputError};
8
9#[derive(Debug)]
10pub struct InputProfiles(HashMap<String, SignatureInput>);
11
12impl InputProfiles {
13    pub fn get(self, label: &str) -> Option<SignatureInput> {
14        self.0
15            .into_iter()
16            .find(|(key, _)| key.eq(label))
17            .map(|(_, input)| input)
18    }
19}
20
21#[derive(Debug, Default)]
22pub struct SignatureInput {
23    pub(crate) covered: IndexSet<TargetField>,
24    pub(crate) created: Option<u64>,
25    pub(crate) expires: Option<u64>,
26    pub(crate) algorithm: Option<String>,
27    pub(crate) key_id: Option<String>,
28    pub(crate) nonce: Option<String>,
29    pub(crate) tag: Option<String>,
30}
31
32impl SignatureInput {
33    pub fn from_header(header: &http::HeaderMap) -> Result<InputProfiles, SignatureInputError> {
34        let Some(input) = header.get(crate::sign::header::SIGNATURE_INPUT) else {
35            return Err(SignatureInputError::NotExistInHeader);
36        };
37
38        let dictionary = sfv::Parser::new(input.as_bytes())
39            .parse::<Dictionary>()
40            .map_err(InvalidFormat::Dictionary)?;
41
42        let mut profiles: HashMap<String, SignatureInput> = HashMap::new();
43        for (key, entry) in dictionary {
44            let mut input = SignatureInput::default();
45            let ListEntry::InnerList(InnerList { items, params }) = entry else {
46                return Err(InvalidFormat::InnerList)?;
47            };
48
49            let covered = items
50                .into_iter()
51                .map(TargetField::try_from)
52                .collect::<Result<IndexSet<_>, InvalidFormat>>()?;
53
54            input.covered = covered;
55            input.assign_parameters(params)?;
56
57            profiles.insert(key.into(), input);
58        }
59
60        Ok(InputProfiles(profiles))
61    }
62
63    //noinspection SpellCheckingInspection
64    fn assign_parameters(&mut self, params: sfv::Parameters) -> Result<(), SignatureInputError> {
65        for (key, item) in params {
66            match (key.as_str(), item) {
67                ("created", BareItem::Integer(created)) => {
68                    self.created = Some(created.try_into().map_err(InvalidFormat::Integer)?)
69                }
70                ("expires", BareItem::Integer(expires)) => {
71                    self.expires = Some(expires.try_into().map_err(InvalidFormat::Integer)?)
72                }
73                ("alg", BareItem::String(alg)) => self.algorithm = Some(alg.into()),
74                ("keyid", BareItem::String(key_id)) => self.key_id = Some(key_id.into()),
75                ("nonce", BareItem::String(nonce)) => self.nonce = Some(nonce.into()),
76                ("tag", BareItem::String(tag)) => self.tag = Some(tag.into()),
77                _ => { /* No-op ;P */ }
78            }
79        }
80        Ok(())
81    }
82}