Skip to main content

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