radrootsd

JSON-RPC bridge for Radroots event publishing
git clone https://radroots.dev/git/radrootsd.git
Log | Files | Refs | README | LICENSE

identity_storage.rs (2870B)


      1 use std::path::{Path, PathBuf};
      2 
      3 use anyhow::Result;
      4 use radroots_identity::{IdentityError, RadrootsIdentity, RadrootsIdentityFile};
      5 
      6 const RADROOTSD_IDENTITY_KEY_SLOT: &str = "radrootsd_identity";
      7 
      8 #[cfg(test)]
      9 pub fn encrypted_identity_key_path(path: impl AsRef<Path>) -> PathBuf {
     10     radroots_runtime::local_wrapping_key_path(path)
     11 }
     12 
     13 pub fn load_service_identity(
     14     path: Option<&Path>,
     15     allow_generate: bool,
     16 ) -> Result<RadrootsIdentity> {
     17     let path = resolved_identity_path(path);
     18     if path.exists() {
     19         return load_encrypted_identity(&path);
     20     }
     21     if !allow_generate {
     22         return Err(IdentityError::GenerationNotAllowed(path).into());
     23     }
     24 
     25     let identity = RadrootsIdentity::generate();
     26     store_encrypted_identity(&path, &identity)?;
     27     Ok(identity)
     28 }
     29 
     30 pub fn store_encrypted_identity(path: impl AsRef<Path>, identity: &RadrootsIdentity) -> Result<()> {
     31     let payload = serde_json::to_vec(&identity.to_file())?;
     32     radroots_runtime::seal_local_secret_file(path, RADROOTSD_IDENTITY_KEY_SLOT, &payload)?;
     33     Ok(())
     34 }
     35 
     36 pub fn load_encrypted_identity(path: impl AsRef<Path>) -> Result<RadrootsIdentity> {
     37     let payload = radroots_runtime::open_local_secret_file(path, RADROOTSD_IDENTITY_KEY_SLOT)?;
     38     let file: RadrootsIdentityFile = serde_json::from_slice(&payload)?;
     39     Ok(RadrootsIdentity::try_from(file)?)
     40 }
     41 
     42 fn resolved_identity_path(path: Option<&Path>) -> PathBuf {
     43     path.map(Path::to_path_buf).unwrap_or_else(|| {
     44         crate::app::paths::default_identity_path_for_process()
     45             .expect("resolve canonical radrootsd identity path")
     46     })
     47 }
     48 
     49 #[cfg(test)]
     50 mod tests {
     51     use super::{encrypted_identity_key_path, load_service_identity};
     52 
     53     #[test]
     54     fn load_service_identity_generates_encrypted_identity_artifacts() {
     55         let temp = tempfile::tempdir().expect("tempdir");
     56         let path = temp.path().join("radrootsd-identity.secret.json");
     57 
     58         let generated =
     59             load_service_identity(Some(&path), true).expect("generate encrypted identity");
     60         let loaded = load_service_identity(Some(&path), false).expect("load encrypted identity");
     61 
     62         assert_eq!(generated.id(), loaded.id());
     63         assert!(path.is_file());
     64         assert!(encrypted_identity_key_path(&path).is_file());
     65     }
     66 
     67     #[test]
     68     fn load_service_identity_fails_when_wrapping_key_is_missing() {
     69         let temp = tempfile::tempdir().expect("tempdir");
     70         let path = temp.path().join("radrootsd-identity.secret.json");
     71         let _ = load_service_identity(Some(&path), true).expect("generate encrypted identity");
     72         std::fs::remove_file(encrypted_identity_key_path(&path)).expect("remove wrapping key");
     73 
     74         let err = load_service_identity(Some(&path), false)
     75             .expect_err("missing wrapping key should fail");
     76         assert!(err.to_string().contains("identity"));
     77     }
     78 }