http_msgsign/sign/
input.rs1use 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 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 _ => { }
78 }
79 }
80 Ok(())
81 }
82}