openmls/group/mls_group/config.rs
1//! Configuration module for [`MlsGroup`] configurations.
2//!
3//! ## Building an MlsGroupCreateConfig
4//! The [`MlsGroupCreateConfigBuilder`] makes it easy to build configurations for the
5//! [`MlsGroup`].
6//!
7//! ```
8//! use openmls::prelude::*;
9//!
10//! let group_config = MlsGroupCreateConfig::builder()
11//! .use_ratchet_tree_extension(true)
12//! .build();
13//! ```
14//!
15//! See [`MlsGroupCreateConfigBuilder`](MlsGroupCreateConfigBuilder#implementations) for
16//! all options that can be configured.
17//!
18//! ### Wire format policies
19//! Only some combination of possible wire formats are valid within OpenMLS.
20//! The [`WIRE_FORMAT_POLICIES`] lists all valid options that can be set.
21//!
22//! ```
23//! use openmls::prelude::*;
24//!
25//! let group_config = MlsGroupCreateConfig::builder()
26//! .wire_format_policy(MIXED_CIPHERTEXT_WIRE_FORMAT_POLICY)
27//! .build();
28//! ```
29
30#[cfg(not(target_arch = "wasm32"))]
31use std::time::SystemTime;
32#[cfg(target_arch = "wasm32")]
33use web_time::SystemTime;
34
35use super::*;
36use crate::{
37 extensions::Extensions,
38 key_packages::Lifetime,
39 tree::sender_ratchet::SenderRatchetConfiguration,
40 treesync::{errors::LeafNodeValidationError, node::leaf_node::Capabilities},
41};
42use serde::{Deserialize, Serialize};
43
44/// Configures the automatic deletion of past epoch secrets.
45///
46/// **WARNING**
47///
48/// Policies other than `MaxEpochs(0)` enable the storage of message secrets from past epochs.
49/// It is a trade-off between functionality and forward secrecy and should only be enabled
50/// if the Delivery Service cannot guarantee that application messages will be sent in
51/// the same epoch in which they were generated. The number for `max_epochs` should be
52/// as low as possible.
53///
54/// If the MaxEpochs policy is set to MaxEpochs(usize::MAX), if will be returned
55/// as KeepAll after deserialization due to backwards compatibility constraints.
56#[derive(Clone, Debug, PartialEq, Eq)]
57pub enum PastEpochDeletionPolicy {
58 /// Keep at most `n` past epoch secrets.
59 MaxEpochs(usize),
60 /// Keep all past epoch secrets.
61 ///
62 /// NOTE: The application is responsible for deleting past epoch secrets when
63 /// `KeepAll` is set. Past epoch secrets can be deleted manually using:
64 /// - [`MlsGroup::delete_past_epoch_secrets()`]
65 KeepAll,
66}
67
68impl Default for PastEpochDeletionPolicy {
69 fn default() -> Self {
70 Self::MaxEpochs(0)
71 }
72}
73
74impl Serialize for PastEpochDeletionPolicy {
75 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
76 where
77 S: serde::Serializer,
78 {
79 let usize = match self {
80 Self::MaxEpochs(epochs) => *epochs,
81 Self::KeepAll => usize::MAX,
82 };
83 serializer.serialize_u64(usize as u64)
84 }
85}
86
87impl<'de> Deserialize<'de> for PastEpochDeletionPolicy {
88 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
89 where
90 D: serde::Deserializer<'de>,
91 {
92 let epochs = u64::deserialize(deserializer)?;
93 let epochs = usize::try_from(epochs).map_err(serde::de::Error::custom)?;
94 if epochs == usize::MAX {
95 Ok(Self::KeepAll)
96 } else {
97 Ok(Self::MaxEpochs(epochs))
98 }
99 }
100}
101
102/// The input to [`MlsGroup::delete_past_epoch_secrets()`].
103///
104/// This struct can be used for manual deletion of past epoch secrets by the application.
105///
106/// An [`MlsGroup`] also applies automatic deletion of past epoch secrets by default.
107///
108/// For more information, see [`PastEpochDeletionPolicy`] and [`MlsGroup::set_past_epoch_deletion_policy()`].
109///
110/// These methods can be used by the application to set up time-based deletion schedules:
111/// - [`PastEpochDeletion::before_timestamp()`]
112/// - [`PastEpochDeletion::older_than_duration()`]
113///
114/// **NOTE**: Epoch secrets that were created using `openmls=0.8.1` or earlier will not yet include a timestamp.
115/// After migration, these may not always be deleted by applying a time-based [`PastEpochDeletion`]. Only if a new secret that does include a timestamp is added later, and it matches the time-based condition in the [`PastEpochDeletion`], all earlier past epoch secrets without timestamps will be deleted, as well. However, otherwise, past epoch secrets without timestamps will not be affected by applying time-based [`PastEpochDeletion`]s.
116///
117/// To manually delete all past epoch secrets without timestamps, see:
118/// [`PastEpochDeletion::delete_all_without_timestamps()`]
119pub struct PastEpochDeletion {
120 pub(crate) config: Option<PastEpochDeletionTimeConfig>,
121 pub(crate) max_past_epochs: Option<usize>,
122}
123
124/// A duration or timestamp before which to delete past epoch secrets.
125pub(crate) enum PastEpochDeletionTimeConfig {
126 OlderThanDuration(std::time::Duration),
127 BeforeTimestamp(SystemTime),
128 DeleteAllWithoutTimestamp,
129}
130
131impl PastEpochDeletion {
132 /// Delete all past epoch secrets older than a provided duration.
133 pub fn older_than_duration(duration: std::time::Duration) -> Self {
134 Self {
135 config: Some(PastEpochDeletionTimeConfig::OlderThanDuration(duration)),
136 max_past_epochs: None,
137 }
138 }
139
140 /// Delete all past epoch secrets before a provided timestamp.
141 pub fn before_timestamp(timestamp: SystemTime) -> Self {
142 Self {
143 config: Some(PastEpochDeletionTimeConfig::BeforeTimestamp(timestamp)),
144 max_past_epochs: None,
145 }
146 }
147
148 /// Delete all past epoch secrets without timestamps.
149 ///
150 /// NOTE: This will delete all past epoch secrets having the legacy
151 /// format that does not include a timestamp.
152 pub fn delete_all_without_timestamps() -> Self {
153 Self {
154 config: Some(PastEpochDeletionTimeConfig::DeleteAllWithoutTimestamp),
155 max_past_epochs: None,
156 }
157 }
158
159 /// Delete all past epoch secrets.
160 pub fn delete_all() -> Self {
161 Self {
162 config: None,
163 max_past_epochs: None,
164 }
165 }
166
167 /// Set the number of `max_past_epochs` that should be kept, at most.
168 pub fn max_past_epochs(mut self, max_past_epochs: usize) -> Self {
169 self.max_past_epochs = Some(max_past_epochs);
170 self
171 }
172}
173
174impl PastEpochDeletionPolicy {
175 pub(crate) fn max_epochs(&self) -> Option<usize> {
176 match self {
177 Self::MaxEpochs(epochs) => Some(*epochs),
178 Self::KeepAll => None,
179 }
180 }
181}
182
183/// The [`MlsGroupJoinConfig`] contains all configuration parameters that are
184/// relevant to group operation at runtime. It is used to configure the group's
185/// behaviour when joining an existing group. To configure a newly created
186/// group, use [`MlsGroupCreateConfig`].
187#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
188pub struct MlsGroupJoinConfig {
189 /// Defines the wire format policy for outgoing and incoming handshake messages.
190 /// Application are always encrypted regardless.
191 pub(crate) wire_format_policy: WireFormatPolicy,
192 /// Size of padding in bytes
193 pub(crate) padding_size: usize,
194 /// Maximum number of past epochs for which application messages
195 /// can be decrypted. The default is 0.
196 #[serde(alias = "max_past_epochs")]
197 // alias for backwards compatibility after renaming field
198 pub(crate) past_epoch_deletion_policy: PastEpochDeletionPolicy,
199 /// Number of resumption secrets to keep
200 pub(crate) number_of_resumption_psks: usize,
201 /// Flag to indicate the Ratchet Tree Extension should be used
202 pub(crate) use_ratchet_tree_extension: bool,
203 /// Sender ratchet configuration
204 pub(crate) sender_ratchet_configuration: SenderRatchetConfiguration,
205}
206
207impl MlsGroupJoinConfig {
208 /// Returns a builder for [`MlsGroupJoinConfig`].
209 pub fn builder() -> MlsGroupJoinConfigBuilder {
210 MlsGroupJoinConfigBuilder::new()
211 }
212
213 /// Returns the wire format policy set in this [`MlsGroupJoinConfig`].
214 pub fn wire_format_policy(&self) -> WireFormatPolicy {
215 self.wire_format_policy
216 }
217
218 /// Returns the padding size set in this [`MlsGroupJoinConfig`].
219 pub fn padding_size(&self) -> usize {
220 self.padding_size
221 }
222
223 /// Returns the [`SenderRatchetConfiguration`] set in this [`MlsGroupJoinConfig`].
224 pub fn sender_ratchet_configuration(&self) -> &SenderRatchetConfiguration {
225 &self.sender_ratchet_configuration
226 }
227
228 /// Returns the max past epochs configured in this [`MlsGroupJoinConfig`]
229 pub(crate) fn max_past_epochs(&self) -> Option<usize> {
230 self.past_epoch_deletion_policy.max_epochs()
231 }
232
233 pub(crate) fn past_epoch_deletion_policy(&self) -> &PastEpochDeletionPolicy {
234 &self.past_epoch_deletion_policy
235 }
236}
237
238/// Specifies configuration for the creation of an [`MlsGroup`]. Refer to the
239/// [User Manual](https://book.openmls.tech/user_manual/group_config.html) for
240/// more information about the different configuration values.
241#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
242pub struct MlsGroupCreateConfig {
243 /// Capabilities advertised in the creator's leaf node
244 pub(crate) capabilities: Capabilities,
245 /// Lifetime of the own leaf node
246 pub(crate) lifetime: Lifetime,
247 /// Ciphersuite and protocol version
248 pub(crate) ciphersuite: Ciphersuite,
249 /// Configuration parameters relevant to group operation at runtime
250 pub(crate) join_config: MlsGroupJoinConfig,
251 /// List of initial group context extensions
252 pub(crate) group_context_extensions: Extensions<GroupContext>,
253 /// List of initial leaf node extensions
254 pub(crate) leaf_node_extensions: Extensions<LeafNode>,
255}
256
257impl Default for MlsGroupCreateConfig {
258 fn default() -> Self {
259 Self {
260 capabilities: Capabilities::default(),
261 lifetime: Lifetime::default(),
262 ciphersuite: Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519,
263 join_config: MlsGroupJoinConfig::default(),
264 group_context_extensions: Extensions::default(),
265 leaf_node_extensions: Extensions::default(),
266 }
267 }
268}
269
270/// Builder struct for an [`MlsGroupJoinConfig`].
271#[derive(Default)]
272pub struct MlsGroupJoinConfigBuilder {
273 join_config: MlsGroupJoinConfig,
274}
275
276impl MlsGroupJoinConfigBuilder {
277 /// Creates a new builder with default values.
278 fn new() -> Self {
279 Self {
280 join_config: MlsGroupJoinConfig::default(),
281 }
282 }
283
284 /// Sets the `wire_format` property of the [`MlsGroupJoinConfig`].
285 pub fn wire_format_policy(mut self, wire_format_policy: WireFormatPolicy) -> Self {
286 self.join_config.wire_format_policy = wire_format_policy;
287 self
288 }
289
290 /// Sets the `padding_size` property of the [`MlsGroupJoinConfig`].
291 pub fn padding_size(mut self, padding_size: usize) -> Self {
292 self.join_config.padding_size = padding_size;
293 self
294 }
295
296 /// Sets the `max_past_epochs` property of the [`MlsGroupJoinConfig`].
297 ///
298 /// This method overrides the policy set by [`Self::set_past_epoch_deletion_policy()`],
299 /// and is equivalent to setting the past epoch deletion policy to
300 /// `PastEpochDeletionPolicy::MaxEpochs(max_past_epochs)`.
301 ///
302 /// **WARNING**
303 ///
304 /// This feature enables the storage of message secrets from past epochs.
305 /// It is a trade-off between functionality and forward secrecy and should only be enabled
306 /// if the Delivery Service cannot guarantee that application messages will be sent in
307 /// the same epoch in which they were generated. The number for `max_epochs` should be
308 /// as low as possible.
309 pub fn max_past_epochs(mut self, max_past_epochs: usize) -> Self {
310 self.join_config.past_epoch_deletion_policy =
311 PastEpochDeletionPolicy::MaxEpochs(max_past_epochs);
312 self
313 }
314
315 /// Set the policy for deleting past epoch secrets.
316 ///
317 /// By default, storage of past epoch secrets is disabled.
318 ///
319 /// This method overrides the configuration set by [`Self::max_past_epochs()`].
320 ///
321 /// **WARNING**
322 ///
323 /// This feature enables the storage of message secrets from past epochs.
324 /// It is a trade-off between functionality and forward secrecy and should only be enabled
325 /// if the Delivery Service cannot guarantee that application messages will be sent in
326 /// the same epoch in which they were generated. The number for `max_epochs` should be
327 /// as low as possible.
328 pub fn set_past_epoch_deletion_policy(mut self, policy: PastEpochDeletionPolicy) -> Self {
329 self.join_config.past_epoch_deletion_policy = policy;
330 self
331 }
332
333 /// Sets the `number_of_resumption_psks` property of the [`MlsGroupJoinConfig`].
334 pub fn number_of_resumption_psks(mut self, number_of_resumption_psks: usize) -> Self {
335 self.join_config.number_of_resumption_psks = number_of_resumption_psks;
336 self
337 }
338
339 /// Sets the `use_ratchet_tree_extension` property of the [`MlsGroupJoinConfig`].
340 pub fn use_ratchet_tree_extension(mut self, use_ratchet_tree_extension: bool) -> Self {
341 self.join_config.use_ratchet_tree_extension = use_ratchet_tree_extension;
342 self
343 }
344
345 /// Sets the `sender_ratchet_configuration` property of the [`MlsGroupJoinConfig`].
346 pub fn sender_ratchet_configuration(
347 mut self,
348 sender_ratchet_configuration: SenderRatchetConfiguration,
349 ) -> Self {
350 self.join_config.sender_ratchet_configuration = sender_ratchet_configuration;
351 self
352 }
353
354 /// Finalizes the builder and returns an [`MlsGroupJoinConfig`].
355 pub fn build(self) -> MlsGroupJoinConfig {
356 self.join_config
357 }
358}
359
360impl MlsGroupCreateConfig {
361 /// Returns a builder for [`MlsGroupCreateConfig`]
362 pub fn builder() -> MlsGroupCreateConfigBuilder {
363 MlsGroupCreateConfigBuilder::new()
364 }
365
366 /// Returns the [`MlsGroupCreateConfig`] wire format policy.
367 pub fn wire_format_policy(&self) -> WireFormatPolicy {
368 self.join_config.wire_format_policy
369 }
370
371 /// Returns the [`MlsGroupCreateConfig`] padding size.
372 pub fn padding_size(&self) -> usize {
373 self.join_config.padding_size
374 }
375
376 /// Returns the [`MlsGroupCreateConfig`] max past epochs.
377 pub fn max_past_epochs(&self) -> Option<usize> {
378 self.join_config.max_past_epochs()
379 }
380
381 /// Returns the [`MlsGroupCreateConfig`] number of resumption psks.
382 pub fn number_of_resumption_psks(&self) -> usize {
383 self.join_config.number_of_resumption_psks
384 }
385
386 /// Returns the [`MlsGroupCreateConfig`] boolean flag that indicates whether ratchet_tree_extension should be used.
387 pub fn use_ratchet_tree_extension(&self) -> bool {
388 self.join_config.use_ratchet_tree_extension
389 }
390
391 /// Returns the [`MlsGroupCreateConfig`] sender ratchet configuration.
392 pub fn sender_ratchet_configuration(&self) -> &SenderRatchetConfiguration {
393 &self.join_config.sender_ratchet_configuration
394 }
395
396 /// Returns the [`Extensions`] set as the initial group context.
397 /// This does not contain the initial group context extensions
398 /// added from builder calls to `external_senders` or `required_capabilities`.
399 pub fn group_context_extensions(&self) -> &Extensions<GroupContext> {
400 &self.group_context_extensions
401 }
402
403 /// Returns the [`MlsGroupCreateConfig`] lifetime configuration.
404 pub fn lifetime(&self) -> &Lifetime {
405 &self.lifetime
406 }
407
408 /// Returns the [`Ciphersuite`].
409 pub fn ciphersuite(&self) -> Ciphersuite {
410 self.ciphersuite
411 }
412
413 #[cfg(any(feature = "test-utils", test))]
414 pub fn test_default(ciphersuite: Ciphersuite) -> Self {
415 Self::builder()
416 .wire_format_policy(WireFormatPolicy::new(
417 OutgoingWireFormatPolicy::AlwaysPlaintext,
418 IncomingWireFormatPolicy::Mixed,
419 ))
420 .ciphersuite(ciphersuite)
421 .build()
422 }
423
424 /// Returns the [`MlsGroupJoinConfig`] of groups created with this create config.
425 pub fn join_config(&self) -> &MlsGroupJoinConfig {
426 &self.join_config
427 }
428}
429
430/// Builder for an [`MlsGroupCreateConfig`].
431#[derive(Default, Debug)]
432pub struct MlsGroupCreateConfigBuilder {
433 config: MlsGroupCreateConfig,
434}
435
436impl MlsGroupCreateConfigBuilder {
437 /// Creates a new builder with default values.
438 fn new() -> Self {
439 MlsGroupCreateConfigBuilder {
440 config: MlsGroupCreateConfig::default(),
441 }
442 }
443
444 /// Sets the `wire_format` property of the MlsGroupCreateConfig.
445 pub fn wire_format_policy(mut self, wire_format_policy: WireFormatPolicy) -> Self {
446 self.config.join_config.wire_format_policy = wire_format_policy;
447 self
448 }
449
450 /// Sets the `padding_size` property of the MlsGroupCreateConfig.
451 pub fn padding_size(mut self, padding_size: usize) -> Self {
452 self.config.join_config.padding_size = padding_size;
453 self
454 }
455
456 /// Sets the `max_past_epochs` property of the MlsGroupCreateConfig.
457 /// This allows application messages from previous epochs to be decrypted.
458 ///
459 /// This method overrides the policy set by [`Self::set_past_epoch_deletion_policy()`],
460 /// and is equivalent to setting the past epoch deletion policy to
461 /// `PastEpochDeletionPolicy::MaxEpochs(max_past_epochs)`.
462 ///
463 /// **WARNING**
464 ///
465 /// This feature enables the storage of message secrets from past epochs.
466 /// It is a trade-off between functionality and forward secrecy and should only be enabled
467 /// if the Delivery Service cannot guarantee that application messages will be sent in
468 /// the same epoch in which they were generated. The number for `max_epochs` should be
469 /// as low as possible.
470 pub fn max_past_epochs(mut self, max_past_epochs: usize) -> Self {
471 self.config.join_config.past_epoch_deletion_policy =
472 PastEpochDeletionPolicy::MaxEpochs(max_past_epochs);
473 self
474 }
475
476 /// Set the policy for deleting past epoch secrets.
477 ///
478 /// By default, storage of past epoch secrets is disabled.
479 ///
480 /// This method overrides the configuration set by [`Self::max_past_epochs()`].
481 ///
482 /// **WARNING**
483 ///
484 /// This feature enables the storage of message secrets from past epochs.
485 /// It is a trade-off between functionality and forward secrecy and should only be enabled
486 /// if the Delivery Service cannot guarantee that application messages will be sent in
487 /// the same epoch in which they were generated. The number for `max_epochs` should be
488 /// as low as possible.
489 pub fn set_past_epoch_deletion_policy(mut self, policy: PastEpochDeletionPolicy) -> Self {
490 self.config.join_config.past_epoch_deletion_policy = policy;
491 self
492 }
493
494 /// Sets the `number_of_resumption_psks` property of the MlsGroupCreateConfig.
495 pub fn number_of_resumption_psks(mut self, number_of_resumption_psks: usize) -> Self {
496 self.config.join_config.number_of_resumption_psks = number_of_resumption_psks;
497 self
498 }
499
500 /// Sets the `use_ratchet_tree_extension` property of the MlsGroupCreateConfig.
501 pub fn use_ratchet_tree_extension(mut self, use_ratchet_tree_extension: bool) -> Self {
502 self.config.join_config.use_ratchet_tree_extension = use_ratchet_tree_extension;
503 self
504 }
505
506 /// Sets the `capabilities` of the group creator's leaf node.
507 pub fn capabilities(mut self, capabilities: Capabilities) -> Self {
508 self.config.capabilities = capabilities;
509 self
510 }
511
512 /// Sets the `sender_ratchet_configuration` property of the MlsGroupCreateConfig.
513 /// See [`SenderRatchetConfiguration`] for more information.
514 pub fn sender_ratchet_configuration(
515 mut self,
516 sender_ratchet_configuration: SenderRatchetConfiguration,
517 ) -> Self {
518 self.config.join_config.sender_ratchet_configuration = sender_ratchet_configuration;
519 self
520 }
521
522 /// Sets the `lifetime` property of the MlsGroupCreateConfig.
523 pub fn lifetime(mut self, lifetime: Lifetime) -> Self {
524 self.config.lifetime = lifetime;
525 self
526 }
527
528 /// Sets the `ciphersuite` property of the MlsGroupCreateConfig.
529 pub fn ciphersuite(mut self, ciphersuite: Ciphersuite) -> Self {
530 self.config.ciphersuite = ciphersuite;
531 self
532 }
533
534 /// Sets initial group context extensions.
535 pub fn with_group_context_extensions(mut self, extensions: Extensions<GroupContext>) -> Self {
536 self.config.group_context_extensions = extensions;
537 self
538 }
539
540 /// Sets extensions of the group creator's [`LeafNode`].
541 ///
542 /// Returns an error if the extension types are not valid in a leaf node.
543 pub fn with_leaf_node_extensions(
544 mut self,
545 extensions: Extensions<LeafNode>,
546 ) -> Result<Self, LeafNodeValidationError> {
547 // Make sure that the extension type is supported in this context.
548 // This means that the leaf node needs to have support listed in the
549 // the capabilities (https://validation.openmls.tech/#valn0107).
550 if !self.config.capabilities.contains_extensions(&extensions) {
551 return Err(LeafNodeValidationError::ExtensionsNotInCapabilities);
552 }
553
554 // Note that the extensions have already been checked to be allowed here.
555 self.config.leaf_node_extensions = extensions;
556 Ok(self)
557 }
558
559 /// Finalizes the builder and returns an [`MlsGroupCreateConfig`].
560 pub fn build(self) -> MlsGroupCreateConfig {
561 self.config
562 }
563}
564
565/// Defines what wire format is acceptable for incoming handshake messages.
566/// Note that application messages must always be encrypted.
567#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
568pub enum IncomingWireFormatPolicy {
569 /// Handshake messages must always be PrivateMessage
570 AlwaysCiphertext,
571 /// Handshake messages must always be PublicMessage
572 AlwaysPlaintext,
573 /// Handshake messages can either be PrivateMessage or PublicMessage
574 Mixed,
575}
576
577impl IncomingWireFormatPolicy {
578 pub(crate) fn is_compatible_with(&self, wire_format: WireFormat) -> bool {
579 match self {
580 IncomingWireFormatPolicy::AlwaysCiphertext => wire_format == WireFormat::PrivateMessage,
581 IncomingWireFormatPolicy::AlwaysPlaintext => wire_format == WireFormat::PublicMessage,
582 IncomingWireFormatPolicy::Mixed => {
583 wire_format == WireFormat::PrivateMessage
584 || wire_format == WireFormat::PublicMessage
585 }
586 }
587 }
588}
589
590/// Defines what wire format should be used for outgoing handshake messages.
591/// Note that application messages must always be encrypted.
592#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
593pub enum OutgoingWireFormatPolicy {
594 /// Handshake messages must always be PrivateMessage
595 AlwaysCiphertext,
596 /// Handshake messages must always be PublicMessage
597 AlwaysPlaintext,
598}
599
600/// Defines what wire format is desired for outgoing handshake messages.
601/// Note that application messages must always be encrypted.
602#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
603pub struct WireFormatPolicy {
604 outgoing: OutgoingWireFormatPolicy,
605 incoming: IncomingWireFormatPolicy,
606}
607
608impl WireFormatPolicy {
609 /// Creates a new wire format policy from an [`OutgoingWireFormatPolicy`]
610 /// and an [`IncomingWireFormatPolicy`].
611 #[cfg(any(feature = "test-utils", test))]
612 pub(crate) fn new(
613 outgoing: OutgoingWireFormatPolicy,
614 incoming: IncomingWireFormatPolicy,
615 ) -> Self {
616 Self { outgoing, incoming }
617 }
618
619 /// Returns a reference to the wire format policy's outgoing wire format policy.
620 pub fn outgoing(&self) -> OutgoingWireFormatPolicy {
621 self.outgoing
622 }
623
624 /// Returns a reference to the wire format policy's incoming wire format policy.
625 pub fn incoming(&self) -> IncomingWireFormatPolicy {
626 self.incoming
627 }
628}
629
630impl Default for WireFormatPolicy {
631 fn default() -> Self {
632 PURE_CIPHERTEXT_WIRE_FORMAT_POLICY
633 }
634}
635
636impl From<OutgoingWireFormatPolicy> for WireFormat {
637 fn from(outgoing: OutgoingWireFormatPolicy) -> Self {
638 match outgoing {
639 OutgoingWireFormatPolicy::AlwaysCiphertext => WireFormat::PrivateMessage,
640 OutgoingWireFormatPolicy::AlwaysPlaintext => WireFormat::PublicMessage,
641 }
642 }
643}
644
645/// All valid wire format policy combinations.
646/// - [`PURE_PLAINTEXT_WIRE_FORMAT_POLICY`]
647/// - [`PURE_CIPHERTEXT_WIRE_FORMAT_POLICY`]
648/// - [`MIXED_PLAINTEXT_WIRE_FORMAT_POLICY`]
649/// - [`MIXED_CIPHERTEXT_WIRE_FORMAT_POLICY`]
650pub const WIRE_FORMAT_POLICIES: [WireFormatPolicy; 4] = [
651 PURE_PLAINTEXT_WIRE_FORMAT_POLICY,
652 PURE_CIPHERTEXT_WIRE_FORMAT_POLICY,
653 MIXED_PLAINTEXT_WIRE_FORMAT_POLICY,
654 MIXED_CIPHERTEXT_WIRE_FORMAT_POLICY,
655];
656
657/// Incoming and outgoing wire formats are always plaintext.
658pub const PURE_PLAINTEXT_WIRE_FORMAT_POLICY: WireFormatPolicy = WireFormatPolicy {
659 outgoing: OutgoingWireFormatPolicy::AlwaysPlaintext,
660 incoming: IncomingWireFormatPolicy::AlwaysPlaintext,
661};
662
663/// Incoming and outgoing wire formats are always ciphertext.
664pub const PURE_CIPHERTEXT_WIRE_FORMAT_POLICY: WireFormatPolicy = WireFormatPolicy {
665 outgoing: OutgoingWireFormatPolicy::AlwaysCiphertext,
666 incoming: IncomingWireFormatPolicy::AlwaysCiphertext,
667};
668
669/// Incoming wire formats can be mixed while outgoing wire formats are always
670/// plaintext.
671pub const MIXED_PLAINTEXT_WIRE_FORMAT_POLICY: WireFormatPolicy = WireFormatPolicy {
672 outgoing: OutgoingWireFormatPolicy::AlwaysPlaintext,
673 incoming: IncomingWireFormatPolicy::Mixed,
674};
675
676/// Incoming wire formats can be mixed while outgoing wire formats are always
677/// ciphertext.
678pub const MIXED_CIPHERTEXT_WIRE_FORMAT_POLICY: WireFormatPolicy = WireFormatPolicy {
679 outgoing: OutgoingWireFormatPolicy::AlwaysCiphertext,
680 incoming: IncomingWireFormatPolicy::Mixed,
681};