mls_spec/
group.rs

1use crate::{
2    SensitiveBytes,
3    credential::Credential,
4    crypto::SignaturePublicKey,
5    defs::{CredentialType, ExtensionType, ProposalType},
6};
7
8pub mod commits;
9pub mod extensions;
10pub mod group_info;
11pub mod proposals;
12pub mod welcome;
13
14pub type HashReference = SensitiveBytes;
15pub type ProposalRef = HashReference;
16pub type KeyPackageRef = HashReference;
17
18pub type GroupId = Vec<u8>;
19pub type GroupIdRef<'a> = &'a [u8];
20
21#[derive(
22    Debug,
23    Clone,
24    Copy,
25    PartialEq,
26    Eq,
27    Hash,
28    tls_codec::TlsSerialize,
29    tls_codec::TlsDeserialize,
30    tls_codec::TlsSize,
31)]
32#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
33pub struct KeyPackageLifetime {
34    pub not_before: u64,
35    pub not_after: u64,
36}
37
38impl KeyPackageLifetime {
39    // 14h wiggle room for non-NTP-synced clients
40    pub const LIFETIME_WIGGLE_ROOM: u64 = 50_400;
41    #[cfg(not(feature = "test-vectors"))]
42    // 3 months (93 days)
43    pub const MAX_LEAF_NODE_ACCEPTABLE_RANGE: u64 = 8_035_200;
44    #[cfg(feature = "test-vectors")]
45    pub const MAX_LEAF_NODE_ACCEPTABLE_RANGE: u64 = u64::MAX - Self::LIFETIME_WIGGLE_ROOM;
46
47    /// Validate if the range presented by `not_before` and `not_after` is within an acceptable range
48    /// This is currently statically configured to be 3 months as per the spec recommendation
49    // TODO: Make it configurable by providing overriding values
50    pub fn validate_range(&self) -> bool {
51        if self.not_after < self.not_before {
52            return false;
53        }
54
55        let kp_range = self.not_after.saturating_sub(self.not_before);
56        let acceptable_range =
57            Self::MAX_LEAF_NODE_ACCEPTABLE_RANGE.saturating_add(Self::LIFETIME_WIGGLE_ROOM);
58        kp_range <= acceptable_range
59    }
60
61    /// Validate if the [KeyPackageLifetime]'s bounds are around now
62    pub fn validate_expiration(&self) -> bool {
63        let now = now();
64        self.not_before < now && now < self.not_after
65    }
66}
67
68#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
69fn now() -> u64 {
70    let val = js_sys::Date::now();
71    std::time::Duration::from_millis(val as u64).as_secs()
72}
73
74#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
75fn now() -> u64 {
76    let now = std::time::SystemTime::now();
77    now.duration_since(std::time::SystemTime::UNIX_EPOCH)
78        .expect("System clock is before UNIX_EPOCH")
79        .as_secs()
80}
81
82impl Default for KeyPackageLifetime {
83    fn default() -> Self {
84        let now = now();
85        let not_before = now.saturating_sub(Self::LIFETIME_WIGGLE_ROOM);
86        let not_after = now.saturating_add(Self::MAX_LEAF_NODE_ACCEPTABLE_RANGE);
87        Self {
88            not_before,
89            not_after,
90        }
91    }
92}
93
94#[derive(
95    Debug,
96    Clone,
97    PartialEq,
98    Eq,
99    Hash,
100    tls_codec::TlsSerialize,
101    tls_codec::TlsDeserialize,
102    tls_codec::TlsSize,
103)]
104#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
105pub struct ExternalSender {
106    pub signature_key: SignaturePublicKey,
107    pub credential: Credential,
108}
109
110#[derive(
111    Debug,
112    Clone,
113    Default,
114    PartialEq,
115    Eq,
116    Hash,
117    tls_codec::TlsSerialize,
118    tls_codec::TlsDeserialize,
119    tls_codec::TlsSize,
120)]
121#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
122pub struct RequiredCapabilities {
123    pub extension_types: Vec<ExtensionType>,
124    pub proposal_types: Vec<ProposalType>,
125    pub credential_types: Vec<CredentialType>,
126}