Skip to main content

pubhubs/servers/auths/
keys.rs

1//! Attribute keys code
2use super::server::*;
3
4use std::collections::HashMap;
5use std::rc::Rc;
6
7use actix_web::web;
8
9use crate::{
10    api::{self},
11    attr, handle, phcrypto,
12};
13
14impl App {
15    /// Implements [`api::auths::AttrKeysEP`].
16    pub async fn handle_attr_keys(
17        app: Rc<Self>,
18        reqs: web::Json<HashMap<handle::Handle, api::auths::AttrKeyReq>>,
19    ) -> api::Result<api::auths::AttrKeysResp> {
20        let running_state = &app.running_state_or_please_retry()?;
21
22        let reqs = reqs.into_inner();
23
24        let mut resp: HashMap<handle::Handle, api::auths::AttrKeyResp> =
25            HashMap::with_capacity(reqs.len());
26
27        let now = api::NumericDate::now();
28
29        for (handle, req) in reqs.into_iter() {
30            let attr: attr::Attr = match req
31                .attr
32                .open(&running_state.attr_signing_key, None) // TODO: constellation 
33                {
34                    Err(api::OpenError::OtherConstellation(..))
35                            | Err(api::OpenError::InvalidSignature)
36                            | Err(api::OpenError::Expired) => {
37                        return Ok(api::auths::AttrKeysResp::RetryWithNewAttr(handle));
38                            }
39                    Err(api::OpenError::OtherwiseInvalid) => {
40                        return Err(api::ErrorCode::BadRequest);
41                    }
42                    Err(api::OpenError::InternalError) => {
43                        return Err(api::ErrorCode::InternalError);
44                    }
45                    Ok(attr) => attr
46                };
47
48            if attr.not_identifying {
49                log::debug!(
50                    "attribute key denied for non-identifying attribute {value} of type {attr_type}",
51                    value = attr.value,
52                    attr_type = attr.attr_type
53                );
54                return Err(api::ErrorCode::BadRequest);
55            }
56
57            let timestamps: Vec<api::NumericDate> = if let Some(timestamp) = req.timestamp {
58                if timestamp > now {
59                    log::warn!(
60                        "future attribute key requested for attribute {value} of type {attr_type}",
61                        value = attr.value,
62                        attr_type = attr.attr_type
63                    );
64                    return Err(api::ErrorCode::BadRequest);
65                }
66
67                vec![timestamp, now]
68            } else {
69                vec![now]
70            };
71
72            let mut attr_keys: Vec<Vec<u8>> =
73                phcrypto::auths_attr_keys(attr, app.attr_key_secret.as_slice(), timestamps);
74
75            let latest_key: Vec<u8> = attr_keys.pop().unwrap();
76            let old_key: Option<Vec<u8>> = attr_keys.pop();
77
78            assert!(attr_keys.is_empty());
79
80            resp.insert(
81                handle.clone(),
82                api::auths::AttrKeyResp {
83                    latest_key: (serde_bytes::ByteBuf::from(latest_key).into(), now),
84                    old_key: old_key.map(|old_key| serde_bytes::ByteBuf::from(old_key).into()),
85                },
86            )
87            .map_or(Ok(()), |_| {
88                log::debug!("double handle in attribute keys request: {handle}");
89                Err(api::ErrorCode::BadRequest)
90            })?;
91        }
92
93        Ok(api::auths::AttrKeysResp::Success(resp))
94    }
95}