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}