Skip to main content

coven_keys/keys/
master_key_staging.rs

1use std::sync::{Arc, Mutex};
2
3use crate::encryption::MasterKeyring;
4
5use super::{KeyError, MasterKeyCustody, MasterKeyError};
6
7enum StagedMasterKeyState {
8    Proposed(MasterKeyring),
9    Committed,
10    RolledBack,
11}
12
13/// A generated master key retained in memory until cloud setup commits.
14pub struct StagedMasterKeyCustody {
15    destination: Arc<dyn MasterKeyCustody>,
16    state: Mutex<StagedMasterKeyState>,
17}
18
19impl StagedMasterKeyCustody {
20    pub fn new(
21        destination: Arc<dyn MasterKeyCustody>,
22        proposed: MasterKeyring,
23    ) -> Result<Arc<Self>, MasterKeyError> {
24        if destination.unlock()?.is_some() {
25            return Err(MasterKeyError::AlreadyEstablished);
26        }
27        Ok(Arc::new(Self {
28            destination,
29            state: Mutex::new(StagedMasterKeyState::Proposed(proposed)),
30        }))
31    }
32
33    pub fn commit(&self) -> Result<(), KeyError> {
34        let mut state = self.state.lock().expect("lock staged master key");
35        match &*state {
36            StagedMasterKeyState::Proposed(keyring) => {
37                self.destination.persist(keyring)?;
38                *state = StagedMasterKeyState::Committed;
39                Ok(())
40            }
41            StagedMasterKeyState::Committed => Ok(()),
42            StagedMasterKeyState::RolledBack => Err(KeyError::MasterKeySetupRolledBack {
43                operation: "commit",
44            }),
45        }
46    }
47
48    pub fn rollback(&self) -> Result<(), KeyError> {
49        let mut state = self.state.lock().expect("lock staged master key");
50        match &*state {
51            StagedMasterKeyState::Proposed(_) => {
52                *state = StagedMasterKeyState::RolledBack;
53                Ok(())
54            }
55            StagedMasterKeyState::Committed => {
56                self.destination.forget()?;
57                *state = StagedMasterKeyState::RolledBack;
58                Ok(())
59            }
60            StagedMasterKeyState::RolledBack => Ok(()),
61        }
62    }
63}
64
65impl MasterKeyCustody for StagedMasterKeyCustody {
66    fn unlock(&self) -> Result<Option<MasterKeyring>, KeyError> {
67        let state = self.state.lock().expect("lock staged master key");
68        match &*state {
69            StagedMasterKeyState::Proposed(keyring) => Ok(Some(keyring.clone())),
70            StagedMasterKeyState::Committed => self.destination.unlock(),
71            StagedMasterKeyState::RolledBack => Err(KeyError::MasterKeySetupRolledBack {
72                operation: "unlock",
73            }),
74        }
75    }
76
77    fn persist(&self, keyring: &MasterKeyring) -> Result<(), KeyError> {
78        let mut state = self.state.lock().expect("lock staged master key");
79        match &mut *state {
80            StagedMasterKeyState::Proposed(proposed) => {
81                *proposed = keyring.clone();
82                Ok(())
83            }
84            StagedMasterKeyState::Committed => self.destination.persist(keyring),
85            StagedMasterKeyState::RolledBack => Err(KeyError::MasterKeySetupRolledBack {
86                operation: "persist",
87            }),
88        }
89    }
90
91    fn forget(&self) -> Result<(), KeyError> {
92        self.rollback()
93    }
94}
95
96#[cfg(test)]
97#[path = "master_key_staging_tests.rs"]
98mod tests;