openmls/skip_validation.rs
1//! This module contains helpers for skipping validation. It is built such that setting the flag to
2//! disable validation can only by set when the "test-utils" feature is enabled.
3//! This module is used in two places, and they use different parts of it.
4//! Code that performs validation and wants to check whether a check is disabled only uses the
5//! [`is_disabled`] submodule. It contains getter functions that read the current state of the
6//! flag.
7//! Test code that disables checks uses the code in the [`checks`] submodule. It contains a module
8//! for each check that can be disabled, and a getter for a handle, protected by a [`Mutex`]. This
9//! is done because the flag state is shared between tests, and tests that set and unset the same
10//! checks are not safe to run concurrently.
11//! For example, a test could cann [`checks::confirmation_tag::handle`] to get a handle to disable
12//! and re-enable the validation of confirmation tags.
13
14pub(crate) mod is_disabled {
15 use super::checks::*;
16
17 pub(crate) fn confirmation_tag() -> bool {
18 confirmation_tag::FLAG.load(core::sync::atomic::Ordering::Relaxed)
19 }
20
21 pub(crate) fn leaf_node_lifetime() -> bool {
22 leaf_node_lifetime::FLAG.load(core::sync::atomic::Ordering::Relaxed)
23 }
24}
25
26#[cfg(test)]
27use std::sync::atomic::AtomicBool;
28
29/// Contains a reference to a flag. Provides convenience functions to set and clear the flag.
30#[cfg(test)]
31#[derive(Clone, Copy, Debug)]
32pub struct SkipValidationHandle {
33 // we keep this field so we can see which handle this is when printing it. we don't need it otherwise
34 #[allow(dead_code)]
35 name: &'static str,
36 flag: &'static AtomicBool,
37}
38
39/// Contains the flags and functions that return handles to control them.
40pub(crate) mod checks {
41 /// Disables validation of the confirmation_tag.
42 pub(crate) mod confirmation_tag {
43 use std::sync::atomic::AtomicBool;
44
45 /// A way of disabling verification and validation of confirmation tags.
46 pub(in crate::skip_validation) static FLAG: AtomicBool = AtomicBool::new(false);
47
48 #[cfg(test)]
49 pub(crate) use lock::handle;
50
51 #[cfg(test)]
52 mod lock {
53 use super::FLAG;
54 use crate::skip_validation::SkipValidationHandle;
55 use once_cell::sync::Lazy;
56 use std::sync::{Mutex, MutexGuard};
57
58 /// The name of the check that can be skipped here
59 const NAME: &str = "confirmation_tag";
60
61 /// A mutex needed to run tests that use this flag sequentially
62 static MUTEX: Lazy<Mutex<SkipValidationHandle>> =
63 Lazy::new(|| Mutex::new(SkipValidationHandle::new_confirmation_tag_handle()));
64
65 /// Takes the mutex and returns the control handle to the validation skipper
66 pub(crate) fn handle() -> MutexGuard<'static, SkipValidationHandle> {
67 MUTEX.lock().unwrap_or_else(|e| {
68 panic!("error taking skip-validation mutex for '{NAME}': {e}")
69 })
70 }
71
72 impl SkipValidationHandle {
73 pub fn new_confirmation_tag_handle() -> Self {
74 Self {
75 name: NAME,
76 flag: &FLAG,
77 }
78 }
79 }
80 }
81 }
82
83 /// Disables validation of leaf node lifetimes
84 pub(crate) mod leaf_node_lifetime {
85 use std::sync::atomic::AtomicBool;
86
87 /// A way of disabling verification and validation of leaf node lifetimes.
88 pub(in crate::skip_validation) static FLAG: AtomicBool = AtomicBool::new(false);
89
90 #[cfg(test)]
91 pub(crate) use lock::handle;
92
93 #[cfg(test)]
94 mod lock {
95 use super::FLAG;
96 use crate::skip_validation::SkipValidationHandle;
97 use once_cell::sync::Lazy;
98 use std::sync::{Mutex, MutexGuard};
99
100 /// The name of the check that can be skipped here
101 const NAME: &str = "leaf_node_lifetime";
102
103 /// A mutex needed to run tests that use this flag sequentially
104 static MUTEX: Lazy<Mutex<SkipValidationHandle>> =
105 Lazy::new(|| Mutex::new(SkipValidationHandle::new_leaf_node_lifetime_handle()));
106
107 /// Takes the mutex and returns the control handle to the validation skipper
108 pub(crate) fn handle() -> MutexGuard<'static, SkipValidationHandle> {
109 MUTEX.lock().unwrap_or_else(|e| {
110 panic!("error taking skip-validation mutex for '{NAME}': {e}")
111 })
112 }
113
114 impl SkipValidationHandle {
115 pub fn new_leaf_node_lifetime_handle() -> Self {
116 Self {
117 name: NAME,
118 flag: &FLAG,
119 }
120 }
121 }
122 }
123 }
124}
125
126#[cfg(test)]
127impl SkipValidationHandle {
128 /// Disables validation for the check controlled by this handle
129 pub fn disable_validation(self) {
130 self.flag.store(true, core::sync::atomic::Ordering::Relaxed);
131 }
132
133 /// Enables validation for the check controlled by this handle
134 pub fn enable_validation(self) {
135 self.flag
136 .store(false, core::sync::atomic::Ordering::Relaxed);
137 }
138
139 /// Runs function `f` with validation disabled
140 pub fn with_disabled<R, F: FnMut() -> R>(self, mut f: F) -> R {
141 self.disable_validation();
142 let r = f();
143 self.enable_validation();
144 r
145 }
146}