posemesh_node_registration/
persist.rs

1use anyhow::{anyhow, Result};
2use std::sync::{Mutex, MutexGuard, OnceLock};
3
4#[derive(Default)]
5struct NodeSecretStore {
6    secret: Option<String>,
7}
8
9static NODE_SECRET_STORE: OnceLock<Mutex<NodeSecretStore>> = OnceLock::new();
10
11fn node_secret_store() -> &'static Mutex<NodeSecretStore> {
12    NODE_SECRET_STORE.get_or_init(|| Mutex::new(NodeSecretStore::default()))
13}
14
15fn lock_node_secret_store() -> Result<MutexGuard<'static, NodeSecretStore>> {
16    node_secret_store()
17        .lock()
18        .map_err(|_| anyhow!("node secret store poisoned"))
19}
20
21/// Store node secret bytes in memory.
22pub fn write_node_secret(secret: &str) -> Result<()> {
23    let mut store = lock_node_secret_store()?;
24    store.secret = Some(secret.to_owned());
25    Ok(())
26}
27
28/// Read secret contents. Returns Ok(None) if missing.
29pub fn read_node_secret() -> Result<Option<String>> {
30    let store = lock_node_secret_store()?;
31    Ok(store.secret.clone())
32}
33
34/// Clear any stored secret. Intended for tests.
35pub fn clear_node_secret() -> Result<()> {
36    let mut store = lock_node_secret_store()?;
37    store.secret = None;
38    Ok(())
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    #[test]
46    fn write_and_read_roundtrip() {
47        clear_node_secret().unwrap();
48
49        write_node_secret("first").unwrap();
50        let got = read_node_secret().unwrap();
51        assert_eq!(got.as_deref(), Some("first"));
52
53        write_node_secret("second").unwrap();
54        let got2 = read_node_secret().unwrap();
55        assert_eq!(got2.as_deref(), Some("second"));
56
57        clear_node_secret().unwrap();
58        assert!(read_node_secret().unwrap().is_none());
59    }
60}