openmls/messages/
external_proposals.rs

1//! External Proposals
2//!
3//! Contains the types and methods to build external proposal to add/remove a client from a MLS group
4//!
5//! `ReInit` is not yet implemented
6
7use crate::{
8    binary_tree::LeafNodeIndex,
9    extensions::{Extensions, SenderExtensionIndex},
10    framing::{mls_auth_content::AuthenticatedContent, MlsMessageOut, PublicMessage},
11    group::{
12        errors::{CreateGroupContextExtProposalError, ProposeRemoveMemberError},
13        mls_group::errors::ProposeAddMemberError,
14        GroupEpoch, GroupId,
15    },
16    key_packages::KeyPackage,
17    messages::{AddProposal, Proposal},
18    storage::{OpenMlsProvider, StorageProvider},
19};
20use openmls_traits::signatures::Signer;
21
22use super::proposals::{GroupContextExtensionProposal, RemoveProposal};
23
24/// External Add Proposal where sender is [NewMemberProposal](crate::prelude::Sender::NewMemberProposal). A client
25/// outside the group can request joining the group. This proposal should then be committed by a
26/// group member. Note that this is unconstrained i.e. it works for any [MLS group](crate::group::MlsGroup).
27/// This is not the case for the same external proposal with a [Preconfigured sender](crate::prelude::Sender::External)
28pub struct JoinProposal;
29
30/// External Proposal where sender is [External](crate::prelude::Sender::External). A party
31/// outside the group can request to add or remove a member to the group. This proposal should then
32/// be committed by a group member. The sender must be pre configured within the group through the [crate::extensions::ExternalSendersExtension]
33pub struct ExternalProposal;
34
35impl JoinProposal {
36    /// Creates an external Add proposal. For clients requesting to be added to a group. This
37    /// proposal will have to be committed later by a group member.
38    ///
39    /// # Arguments
40    /// * `key_package` - of the joiner
41    /// * `group_id` - unique group identifier of the group to join
42    /// * `epoch` - group's epoch
43    /// * `signer` - of the sender to sign the message
44    #[allow(clippy::new_ret_no_self)]
45    pub fn new<Storage: StorageProvider>(
46        key_package: KeyPackage,
47        group_id: GroupId,
48        epoch: GroupEpoch,
49        signer: &impl Signer,
50    ) -> Result<MlsMessageOut, ProposeAddMemberError<Storage::Error>> {
51        AuthenticatedContent::new_join_proposal(
52            Proposal::Add(AddProposal { key_package }),
53            group_id,
54            epoch,
55            signer,
56        )
57        .map(PublicMessage::from)
58        .map(MlsMessageOut::from)
59        .map_err(ProposeAddMemberError::from)
60    }
61}
62
63impl ExternalProposal {
64    /// Creates an external GroupContextExtensions proposal. For delivery services requesting to update the group context extensions.
65    /// This proposal will have to be committed later by a group member.
66    ///
67    /// # Arguments
68    /// * `extensions` - a new set of extensions for the group context
69    /// * `group_id` - unique group identifier of the group to join
70    /// * `epoch` - group's epoch
71    /// * `signer` - of the sender to sign the message
72    /// * `sender` - index of the sender of the proposal (in the [crate::extensions::ExternalSendersExtension] array
73    ///   from the Group Context)
74    pub fn new_group_context_extensions<Provider: OpenMlsProvider>(
75        extensions: Extensions,
76        group_id: GroupId,
77        epoch: GroupEpoch,
78        signer: &impl Signer,
79        sender_index: SenderExtensionIndex,
80    ) -> Result<MlsMessageOut, CreateGroupContextExtProposalError<Provider::StorageError>> {
81        let proposal = GroupContextExtensionProposal::new(extensions);
82
83        AuthenticatedContent::new_external_proposal(
84            Proposal::GroupContextExtensions(proposal),
85            group_id,
86            epoch,
87            signer,
88            sender_index,
89        )
90        .map(PublicMessage::from)
91        .map(MlsMessageOut::from)
92        .map_err(CreateGroupContextExtProposalError::from)
93    }
94    /// Creates an external Remove proposal. For delivery services requesting to remove a client.
95    /// This proposal will have to be committed later by a group member.
96    ///
97    /// # Arguments
98    /// * `removed` - index of the client to remove
99    /// * `group_id` - unique group identifier of the group to join
100    /// * `epoch` - group's epoch
101    /// * `signer` - of the sender to sign the message
102    /// * `sender` - index of the sender of the proposal (in the [crate::extensions::ExternalSendersExtension] array
103    ///   from the Group Context)
104    pub fn new_remove<Provider: OpenMlsProvider>(
105        removed: LeafNodeIndex,
106        group_id: GroupId,
107        epoch: GroupEpoch,
108        signer: &impl Signer,
109        sender_index: SenderExtensionIndex,
110    ) -> Result<MlsMessageOut, ProposeRemoveMemberError<Provider::StorageError>> {
111        AuthenticatedContent::new_external_proposal(
112            Proposal::Remove(RemoveProposal { removed }),
113            group_id,
114            epoch,
115            signer,
116            sender_index,
117        )
118        .map(PublicMessage::from)
119        .map(MlsMessageOut::from)
120        .map_err(ProposeRemoveMemberError::from)
121    }
122
123    /// Creates an external Add proposal. For delivery services requesting to add a client.
124    /// This proposal will have to be committed later by a group member.
125    ///
126    /// # Arguments
127    /// * `key_package` - key package of the client to add
128    /// * `group_id` - unique group identifier of the group to join
129    /// * `epoch` - group's epoch
130    /// * `signer` - of the sender to sign the message
131    /// * `sender` - index of the sender of the proposal (in the [crate::extensions::ExternalSendersExtension] array
132    ///   from the Group Context)
133    pub fn new_add<Provider: OpenMlsProvider>(
134        key_package: KeyPackage,
135        group_id: GroupId,
136        epoch: GroupEpoch,
137        signer: &impl Signer,
138        sender_index: SenderExtensionIndex,
139    ) -> Result<MlsMessageOut, ProposeAddMemberError<Provider::StorageError>> {
140        AuthenticatedContent::new_external_proposal(
141            Proposal::Add(AddProposal { key_package }),
142            group_id,
143            epoch,
144            signer,
145            sender_index,
146        )
147        .map(PublicMessage::from)
148        .map(MlsMessageOut::from)
149        .map_err(ProposeAddMemberError::from)
150    }
151}