1 // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 2 // Copyright by contributors to this project. 3 // SPDX-License-Identifier: (Apache-2.0 OR MIT) 4 5 use alloc::vec; 6 use alloc::vec::Vec; 7 use mls_rs_codec::{MlsDecode, MlsEncode, MlsSize}; 8 9 use crate::{ 10 crypto::CipherSuite, 11 extension::{ExtensionList, ExtensionType}, 12 identity::{CredentialType, SigningIdentity}, 13 protocol_version::ProtocolVersion, 14 }; 15 16 use super::ProposalType; 17 18 #[derive(Clone, PartialEq, Eq, Debug, MlsSize, MlsEncode, MlsDecode)] 19 #[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] 20 #[cfg_attr( 21 all(feature = "ffi", not(test)), 22 safer_ffi_gen::ffi_type(clone, opaque) 23 )] 24 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] 25 /// Capabilities of a MLS client 26 pub struct Capabilities { 27 pub protocol_versions: Vec<ProtocolVersion>, 28 pub cipher_suites: Vec<CipherSuite>, 29 pub extensions: Vec<ExtensionType>, 30 pub proposals: Vec<ProposalType>, 31 pub credentials: Vec<CredentialType>, 32 } 33 34 #[cfg_attr(all(feature = "ffi", not(test)), safer_ffi_gen::safer_ffi_gen)] 35 impl Capabilities { 36 /// Supported protocol versions 37 #[cfg(feature = "ffi")] protocol_versions(&self) -> &[ProtocolVersion]38 pub fn protocol_versions(&self) -> &[ProtocolVersion] { 39 &self.protocol_versions 40 } 41 42 /// Supported ciphersuites 43 #[cfg(feature = "ffi")] cipher_suites(&self) -> &[CipherSuite]44 pub fn cipher_suites(&self) -> &[CipherSuite] { 45 &self.cipher_suites 46 } 47 48 /// Supported extensions 49 #[cfg(feature = "ffi")] extensions(&self) -> &[ExtensionType]50 pub fn extensions(&self) -> &[ExtensionType] { 51 &self.extensions 52 } 53 54 /// Supported proposals 55 #[cfg(feature = "ffi")] proposals(&self) -> &[ProposalType]56 pub fn proposals(&self) -> &[ProposalType] { 57 &self.proposals 58 } 59 60 /// Supported credentials 61 #[cfg(feature = "ffi")] credentials(&self) -> &[CredentialType]62 pub fn credentials(&self) -> &[CredentialType] { 63 &self.credentials 64 } 65 66 /// Canonical form sorted(mut self) -> Self67 pub fn sorted(mut self) -> Self { 68 self.protocol_versions.sort(); 69 self.cipher_suites.sort(); 70 self.extensions.sort(); 71 self.proposals.sort(); 72 self.credentials.sort(); 73 74 self 75 } 76 } 77 78 impl Default for Capabilities { default() -> Self79 fn default() -> Self { 80 use crate::identity::BasicCredential; 81 82 Self { 83 protocol_versions: vec![ProtocolVersion::MLS_10], 84 cipher_suites: CipherSuite::all().collect(), 85 extensions: Default::default(), 86 proposals: Default::default(), 87 credentials: vec![BasicCredential::credential_type()], 88 } 89 } 90 } 91 92 /// A member of a MLS group. 93 #[cfg_attr( 94 all(feature = "ffi", not(test)), 95 safer_ffi_gen::ffi_type(clone, opaque) 96 )] 97 #[derive(Debug, Clone, PartialEq, Eq)] 98 #[non_exhaustive] 99 pub struct Member { 100 /// The index of this member within a group. 101 /// 102 /// This value is consistent for all clients and will not change as the 103 /// group evolves. 104 pub index: u32, 105 /// Current identity public key and credential of this member. 106 pub signing_identity: SigningIdentity, 107 /// Current client [Capabilities] of this member. 108 pub capabilities: Capabilities, 109 /// Current leaf node extensions in use by this member. 110 pub extensions: ExtensionList, 111 } 112 113 #[cfg_attr(all(feature = "ffi", not(test)), safer_ffi_gen::safer_ffi_gen)] 114 impl Member { new( index: u32, signing_identity: SigningIdentity, capabilities: Capabilities, extensions: ExtensionList, ) -> Self115 pub fn new( 116 index: u32, 117 signing_identity: SigningIdentity, 118 capabilities: Capabilities, 119 extensions: ExtensionList, 120 ) -> Self { 121 Self { 122 index, 123 signing_identity, 124 capabilities, 125 extensions, 126 } 127 } 128 129 /// The index of this member within a group. 130 /// 131 /// This value is consistent for all clients and will not change as the 132 /// group evolves. 133 #[cfg(feature = "ffi")] index(&self) -> u32134 pub fn index(&self) -> u32 { 135 self.index 136 } 137 138 /// Current identity public key and credential of this member. 139 #[cfg(feature = "ffi")] signing_identity(&self) -> &SigningIdentity140 pub fn signing_identity(&self) -> &SigningIdentity { 141 &self.signing_identity 142 } 143 144 /// Current client [Capabilities] of this member. 145 #[cfg(feature = "ffi")] capabilities(&self) -> &Capabilities146 pub fn capabilities(&self) -> &Capabilities { 147 &self.capabilities 148 } 149 150 /// Current leaf node extensions in use by this member. 151 #[cfg(feature = "ffi")] extensions(&self) -> &ExtensionList152 pub fn extensions(&self) -> &ExtensionList { 153 &self.extensions 154 } 155 } 156 157 #[derive(Clone, Debug, PartialEq)] 158 #[non_exhaustive] 159 #[cfg_attr( 160 all(feature = "ffi", not(test)), 161 safer_ffi_gen::ffi_type(clone, opaque) 162 )] 163 /// Update of a member due to a commit. 164 pub struct MemberUpdate { 165 pub prior: Member, 166 pub new: Member, 167 } 168 169 #[cfg_attr(all(feature = "ffi", not(test)), safer_ffi_gen::safer_ffi_gen)] 170 impl MemberUpdate { 171 /// Create a new member update. new(prior: Member, new: Member) -> MemberUpdate172 pub fn new(prior: Member, new: Member) -> MemberUpdate { 173 MemberUpdate { prior, new } 174 } 175 176 /// The index that was updated. index(&self) -> u32177 pub fn index(&self) -> u32 { 178 self.new.index 179 } 180 181 /// Member state before the update. 182 #[cfg(feature = "ffi")] before_update(&self) -> &Member183 pub fn before_update(&self) -> &Member { 184 &self.prior 185 } 186 187 /// Member state after the update. 188 #[cfg(feature = "ffi")] after_update(&self) -> &Member189 pub fn after_update(&self) -> &Member { 190 &self.new 191 } 192 } 193 194 /// A set of roster updates due to a commit. 195 #[derive(Clone, Debug, PartialEq)] 196 #[non_exhaustive] 197 pub struct RosterUpdate { 198 pub(crate) added: Vec<Member>, 199 pub(crate) removed: Vec<Member>, 200 pub(crate) updated: Vec<MemberUpdate>, 201 } 202 203 impl RosterUpdate { 204 /// Create a new roster update. new( mut added: Vec<Member>, mut removed: Vec<Member>, mut updated: Vec<MemberUpdate>, ) -> RosterUpdate205 pub fn new( 206 mut added: Vec<Member>, 207 mut removed: Vec<Member>, 208 mut updated: Vec<MemberUpdate>, 209 ) -> RosterUpdate { 210 added.sort_by_key(|m| m.index); 211 removed.sort_by_key(|m| m.index); 212 updated.sort_by_key(|u| u.index()); 213 214 RosterUpdate { 215 added, 216 removed, 217 updated, 218 } 219 } 220 /// Members added via this update. added(&self) -> &[Member]221 pub fn added(&self) -> &[Member] { 222 &self.added 223 } 224 225 /// Members removed via this update. removed(&self) -> &[Member]226 pub fn removed(&self) -> &[Member] { 227 &self.removed 228 } 229 230 /// Members updated via this update. updated(&self) -> &[MemberUpdate]231 pub fn updated(&self) -> &[MemberUpdate] { 232 &self.updated 233 } 234 } 235