1use commit_builder::CommitMessageBundle;
2use errors::{ProposeSelfUpdateError, SelfUpdateError};
3use openmls_traits::{signatures::Signer, storage::StorageProvider as _};
4
5use crate::{credentials::NewSignerBundle, storage::OpenMlsProvider, treesync::LeafNodeParameters};
6
7use super::*;
8
9impl MlsGroup {
10 pub fn self_update<Provider: OpenMlsProvider>(
24 &mut self,
25 provider: &Provider,
26 signer: &impl Signer,
27 leaf_node_parameters: LeafNodeParameters,
28 ) -> Result<CommitMessageBundle, SelfUpdateError<Provider::StorageError>> {
29 self.is_operational()?;
30
31 let bundle = self
32 .commit_builder()
33 .leaf_node_parameters(leaf_node_parameters)
34 .consume_proposal_store(true)
35 .load_psks(provider.storage())?
36 .build(provider.rand(), provider.crypto(), signer, |_| true)?
37 .stage_commit(provider)?;
38
39 self.reset_aad();
40
41 Ok(bundle)
42 }
43
44 pub fn self_update_with_new_signer<Provider: OpenMlsProvider, S: Signer>(
63 &mut self,
64 provider: &Provider,
65 old_signer: &impl Signer,
66 new_signer: NewSignerBundle<'_, S>,
67 leaf_node_parameters: LeafNodeParameters,
68 ) -> Result<CommitMessageBundle, SelfUpdateError<Provider::StorageError>> {
69 self.is_operational()?;
70
71 let bundle = self
72 .commit_builder()
73 .leaf_node_parameters(leaf_node_parameters)
74 .consume_proposal_store(true)
75 .load_psks(provider.storage())?
76 .build_with_new_signer(
77 provider.rand(),
78 provider.crypto(),
79 old_signer,
80 new_signer,
81 |_| true,
82 )?
83 .stage_commit(provider)?;
84
85 self.reset_aad();
86
87 Ok(bundle)
88 }
89
90 fn create_self_update_proposal_internal<Provider: OpenMlsProvider, S: Signer>(
94 &mut self,
95 provider: &Provider,
96 old_signer: &impl Signer,
97 new_signer: Option<NewSignerBundle<'_, S>>,
98 mut leaf_node_parameters: LeafNodeParameters,
99 ) -> Result<AuthenticatedContent, ProposeSelfUpdateError<Provider::StorageError>> {
100 self.is_operational()?;
101
102 let mut own_leaf = self
107 .public_group()
108 .leaf(self.own_leaf_index())
109 .ok_or_else(|| LibraryError::custom("The tree is broken. Couldn't find own leaf."))?
110 .clone();
111
112 if let Some(new_signer) = new_signer {
113 if self.ciphersuite().signature_algorithm() != new_signer.signer.signature_scheme() {
114 return Err(ProposeSelfUpdateError::InvalidSignerCiphersuite);
115 }
116
117 if let Some(ln_cred) = leaf_node_parameters.credential_with_key() {
121 if ln_cred != &new_signer.credential_with_key {
122 return Err(ProposeSelfUpdateError::InvalidLeafNodeParameters);
123 }
124 } else {
125 leaf_node_parameters.set_credential_with_key(new_signer.credential_with_key);
126 }
127
128 own_leaf.update(
129 self.ciphersuite(),
130 provider,
131 new_signer.signer,
132 self.group_id().clone(),
133 self.own_leaf_index(),
134 leaf_node_parameters,
135 )?;
136 } else {
137 own_leaf.update(
138 self.ciphersuite(),
139 provider,
140 old_signer,
141 self.group_id().clone(),
142 self.own_leaf_index(),
143 leaf_node_parameters,
144 )?;
145 }
146
147 let leaf_supports_all_extensions = self
150 .public_group()
151 .group_context()
152 .extensions()
153 .iter()
154 .all(|extension| own_leaf.supports_extension(&extension.extension_type()));
155
156 if !leaf_supports_all_extensions {
157 return Err(ProposeSelfUpdateError::UnsupportedGroupContextExtensions);
158 }
159
160 let update_proposal =
161 self.create_update_proposal(self.framing_parameters(), own_leaf.clone(), old_signer)?;
162
163 provider
164 .storage()
165 .append_own_leaf_node(self.group_id(), &own_leaf)
166 .map_err(ProposeSelfUpdateError::StorageError)?;
167 self.own_leaf_nodes.push(own_leaf);
168
169 Ok(update_proposal)
170 }
171
172 fn propose_self_update_internal<Provider: OpenMlsProvider, S: Signer>(
173 &mut self,
174 provider: &Provider,
175 old_signer: &impl Signer,
176 new_signer: Option<NewSignerBundle<'_, S>>,
177 leaf_node_parameters: LeafNodeParameters,
178 ) -> Result<(MlsMessageOut, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>> {
179 let update_proposal = self.create_self_update_proposal_internal(
180 provider,
181 old_signer,
182 new_signer,
183 leaf_node_parameters,
184 )?;
185 let proposal = QueuedProposal::from_authenticated_content_by_ref(
186 self.ciphersuite(),
187 provider.crypto(),
188 update_proposal.clone(),
189 )?;
190 let proposal_ref = proposal.proposal_reference();
191 provider
192 .storage()
193 .queue_proposal(self.group_id(), &proposal_ref, &proposal)
194 .map_err(ProposeSelfUpdateError::StorageError)?;
195 self.proposal_store_mut().add(proposal);
196
197 let mls_message = self.content_to_mls_message(update_proposal, provider)?;
198
199 self.reset_aad();
200 Ok((mls_message, proposal_ref))
201 }
202
203 pub fn propose_self_update<Provider: OpenMlsProvider, S: Signer>(
207 &mut self,
208 provider: &Provider,
209 signer: &S,
210 leaf_node_parameters: LeafNodeParameters,
211 ) -> Result<(MlsMessageOut, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>> {
212 self.propose_self_update_internal(
213 provider,
214 signer,
215 None::<NewSignerBundle<'_, S>>,
216 leaf_node_parameters,
217 )
218 }
219
220 pub fn propose_self_update_with_new_signer<Provider: OpenMlsProvider, S: Signer>(
236 &mut self,
237 provider: &Provider,
238 old_signer: &impl Signer,
239 new_signer: NewSignerBundle<'_, S>,
240 leaf_node_parameters: LeafNodeParameters,
241 ) -> Result<(MlsMessageOut, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>> {
242 self.propose_self_update_internal(
243 provider,
244 old_signer,
245 Some(new_signer),
246 leaf_node_parameters,
247 )
248 }
249}