Skip to main content

macula_rust/record/
station_authorization.rs

1//! Station authorizations (0x13, macula-station#63): a realm's statement,
2//! signed by its realm key, that a station serves the realm under a hostname
3//! and roles, for a window of at most 30 minutes. It is stored under the realm
4//! id and the station's node_id, where the realm's tombstone of it lands once
5//! it is revoked.
6
7use crate::cbor::Value;
8
9use super::{id_field, malformed, text_field, Record, RecordError, RecordType};
10
11/// A station authorization's payload: the realm and station, the hostname and
12/// roles, its window, and the attestation key a station must prove when
13/// `attestation_required`.
14#[derive(Debug, Clone, Default, PartialEq, Eq)]
15pub struct StationAuthorization {
16    pub realm_id: [u8; 32],
17    pub station_node: [u8; 32],
18    pub hostname: String,
19    pub roles: Vec<String>,
20    pub valid_from: u64,
21    pub valid_until: u64,
22    pub attestation_key_id: Option<[u8; 32]>,
23    pub attestation_required: bool,
24}
25
26/// Reads a station authorization's payload, as macula_record's
27/// read_station_authorization/1 does.
28pub fn read_station_authorization(r: &Record) -> Result<StationAuthorization, RecordError> {
29    if r.record_type != RecordType::STATION_AUTHORIZATION {
30        return Err(malformed("not a station authorization"));
31    }
32    let p = &r.payload;
33    let uint = |name: &str| match p.get(name) {
34        Some(Value::Int(n)) => u64::try_from(*n).unwrap_or(0),
35        _ => 0,
36    };
37    let roles = match p.get("roles") {
38        Some(Value::List(roles)) => roles
39            .iter()
40            .filter_map(|r| match r {
41                Value::Text(t) => Some(t.clone()),
42                _ => None,
43            })
44            .collect(),
45        _ => Vec::new(),
46    };
47    Ok(StationAuthorization {
48        realm_id: id_field(p, "realm_id"),
49        station_node: id_field(p, "station_node"),
50        hostname: text_field(p, "hostname"),
51        roles,
52        valid_from: uint("valid_from"),
53        valid_until: uint("valid_until"),
54        attestation_key_id: p
55            .get("attestation_key_id")
56            .map(|_| id_field(p, "attestation_key_id")),
57        attestation_required: p.get("attestation_required") == Some(&Value::Int(1)),
58    })
59}