1#[cfg(any(not(feature = "virtual-clients-draft"), feature = "test-utils", test))]
2use commit_builder::CommitMessageBundle;
3use errors::ProposeSelfUpdateError;
4#[cfg(any(not(feature = "virtual-clients-draft"), feature = "test-utils", test))]
5use errors::SelfUpdateError;
6use openmls_traits::signatures::Signer;
7
8#[cfg(feature = "migration-import")]
9use openmls_traits::storage::StorageProvider as _;
10
11use crate::{credentials::NewSignerBundle, storage::OpenMlsProvider, treesync::LeafNodeParameters};
12
13use super::*;
14
15impl MlsGroup {
16 #[cfg(any(not(feature = "virtual-clients-draft"), feature = "test-utils", test))]
35 pub fn self_update<Provider: OpenMlsProvider>(
36 &mut self,
37 provider: &Provider,
38 signer: &impl Signer,
39 leaf_node_parameters: LeafNodeParameters,
40 ) -> Result<CommitMessageBundle, SelfUpdateError<Provider::StorageError>> {
41 self.is_operational()?;
42
43 let bundle = self
44 .commit_builder()
45 .leaf_node_parameters(leaf_node_parameters)
46 .consume_proposal_store(true)
47 .load_psks(provider.storage())?
48 .build(provider.rand(), provider.crypto(), signer, |_| true)?
49 .stage_commit(provider)?;
50
51 self.reset_aad();
52
53 Ok(bundle)
54 }
55
56 #[cfg(any(not(feature = "virtual-clients-draft"), feature = "test-utils", test))]
80 pub fn self_update_with_new_signer<Provider: OpenMlsProvider, S: Signer>(
81 &mut self,
82 provider: &Provider,
83 old_signer: &impl Signer,
84 new_signer: NewSignerBundle<'_, S>,
85 leaf_node_parameters: LeafNodeParameters,
86 ) -> Result<CommitMessageBundle, SelfUpdateError<Provider::StorageError>> {
87 self.is_operational()?;
88
89 let bundle = self
90 .commit_builder()
91 .leaf_node_parameters(leaf_node_parameters)
92 .consume_proposal_store(true)
93 .load_psks(provider.storage())?
94 .build_with_new_signer(
95 provider.rand(),
96 provider.crypto(),
97 old_signer,
98 new_signer,
99 |_| true,
100 )?
101 .stage_commit(provider)?;
102
103 self.reset_aad();
104
105 Ok(bundle)
106 }
107
108 fn create_self_update_proposal_internal<Provider: OpenMlsProvider, S: Signer>(
112 &mut self,
113 provider: &Provider,
114 old_signer: &impl Signer,
115 new_signer: Option<NewSignerBundle<'_, S>>,
116 mut leaf_node_parameters: LeafNodeParameters,
117 ) -> Result<AuthenticatedContent, ProposeSelfUpdateError<Provider::StorageError>> {
118 self.is_operational()?;
119
120 let mut own_leaf = self
125 .public_group()
126 .leaf(self.own_leaf_index())
127 .ok_or_else(|| LibraryError::custom("The tree is broken. Couldn't find own leaf."))?
128 .clone();
129
130 if let Some(new_signer) = new_signer {
131 if self.ciphersuite().signature_algorithm() != new_signer.signer.signature_scheme() {
132 return Err(ProposeSelfUpdateError::InvalidSignerCiphersuite);
133 }
134
135 if let Some(ln_cred) = leaf_node_parameters.credential_with_key() {
139 if ln_cred != &new_signer.credential_with_key {
140 return Err(ProposeSelfUpdateError::InvalidLeafNodeParameters);
141 }
142 } else {
143 leaf_node_parameters.set_credential_with_key(new_signer.credential_with_key);
144 }
145
146 own_leaf.update(
147 self.ciphersuite(),
148 provider,
149 new_signer.signer,
150 self.group_id().clone(),
151 self.own_leaf_index(),
152 leaf_node_parameters,
153 )?;
154 } else {
155 own_leaf.update(
156 self.ciphersuite(),
157 provider,
158 old_signer,
159 self.group_id().clone(),
160 self.own_leaf_index(),
161 leaf_node_parameters,
162 )?;
163 }
164
165 let leaf_supports_all_extensions = self
168 .public_group()
169 .group_context()
170 .extensions()
171 .iter()
172 .all(|extension| own_leaf.supports_extension(&extension.extension_type()));
173
174 if !leaf_supports_all_extensions {
175 return Err(ProposeSelfUpdateError::UnsupportedGroupContextExtensions);
176 }
177
178 let aad = self.outgoing_authenticated_data()?;
179 let framing_parameters = FramingParameters::new(&aad, self.outgoing_wire_format());
180 let update_proposal =
181 self.create_update_proposal(framing_parameters, own_leaf.clone(), old_signer)?;
182
183 provider
184 .storage()
185 .append_own_leaf_node(self.group_id(), &own_leaf)
186 .map_err(ProposeSelfUpdateError::StorageError)?;
187 self.own_leaf_nodes.push(own_leaf);
188
189 Ok(update_proposal)
190 }
191
192 pub(crate) fn propose_self_update_internal<Provider: OpenMlsProvider, S: Signer>(
193 &mut self,
194 provider: &Provider,
195 old_signer: &impl Signer,
196 new_signer: Option<NewSignerBundle<'_, S>>,
197 leaf_node_parameters: LeafNodeParameters,
198 ) -> Result<(HandshakeFramingOutput, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>>
199 {
200 let update_proposal = self.create_self_update_proposal_internal(
201 provider,
202 old_signer,
203 new_signer,
204 leaf_node_parameters,
205 )?;
206 let proposal = QueuedProposal::from_authenticated_content_by_ref(
207 self.ciphersuite(),
208 provider.crypto(),
209 update_proposal.clone(),
210 )?;
211 let proposal_ref = proposal.proposal_reference();
212 provider
213 .storage()
214 .queue_proposal(self.group_id(), &proposal_ref, &proposal)
215 .map_err(ProposeSelfUpdateError::StorageError)?;
216 self.proposal_store_mut().add(proposal);
217
218 let framing = self.content_to_mls_message(update_proposal, provider)?;
219
220 self.reset_aad();
221 Ok((framing, proposal_ref))
222 }
223
224 #[cfg(any(not(feature = "virtual-clients-draft"), feature = "test-utils", test))]
233 pub fn propose_self_update<Provider: OpenMlsProvider, S: Signer>(
234 &mut self,
235 provider: &Provider,
236 signer: &S,
237 leaf_node_parameters: LeafNodeParameters,
238 ) -> Result<(MlsMessageOut, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>> {
239 let (framing, proposal_ref) = self.propose_self_update_internal(
240 provider,
241 signer,
242 None::<NewSignerBundle<'_, S>>,
243 leaf_node_parameters,
244 )?;
245 Ok((framing.message, proposal_ref))
246 }
247
248 #[cfg(any(not(feature = "virtual-clients-draft"), feature = "test-utils", test))]
268 pub fn propose_self_update_with_new_signer<Provider: OpenMlsProvider, S: Signer>(
269 &mut self,
270 provider: &Provider,
271 old_signer: &impl Signer,
272 new_signer: NewSignerBundle<'_, S>,
273 leaf_node_parameters: LeafNodeParameters,
274 ) -> Result<(MlsMessageOut, ProposalRef), ProposeSelfUpdateError<Provider::StorageError>> {
275 let (framing, proposal_ref) = self.propose_self_update_internal(
276 provider,
277 old_signer,
278 Some(new_signer),
279 leaf_node_parameters,
280 )?;
281 Ok((framing.message, proposal_ref))
282 }
283
284 #[cfg(feature = "virtual-clients-draft")]
293 pub fn propose_self_update_with_new_signer_unconfirmed<Provider: OpenMlsProvider, S: Signer>(
294 &mut self,
295 provider: &Provider,
296 old_signer: &impl Signer,
297 new_signer: NewSignerBundle<'_, S>,
298 leaf_node_parameters: LeafNodeParameters,
299 ) -> Result<
300 (
301 MlsMessageOut,
302 ProposalRef,
303 Option<HandshakeConfirmationData>,
304 ),
305 ProposeSelfUpdateError<Provider::StorageError>,
306 > {
307 let (framing, proposal_ref) = self.propose_self_update_internal(
308 provider,
309 old_signer,
310 Some(new_signer),
311 leaf_node_parameters,
312 )?;
313 Ok((framing.message, proposal_ref, framing.confirmation))
314 }
315}