myc

Self-custodial remote signer for Radroots apps
git clone https://radroots.dev/git/myc.git
Log | Files | Refs | README | LICENSE

myc_repo_local_identity_bootstrap.rs (2759B)


      1 #![forbid(unsafe_code)]
      2 
      3 use std::env;
      4 use std::path::{Path, PathBuf};
      5 use std::process::ExitCode;
      6 
      7 use myc::identity_files::{load_encrypted_identity, store_encrypted_identity};
      8 use radroots_identity::RadrootsIdentity;
      9 use radroots_runtime_paths::{
     10     RadrootsPathOverrides, RadrootsPathProfile, RadrootsPathResolver, RadrootsRuntimeNamespace,
     11 };
     12 
     13 fn main() -> ExitCode {
     14     match run() {
     15         Ok(()) => ExitCode::SUCCESS,
     16         Err(err) => {
     17             eprintln!("{err}");
     18             ExitCode::from(1)
     19         }
     20     }
     21 }
     22 
     23 fn run() -> Result<(), String> {
     24     let runtime_root = runtime_root_from_args()?;
     25     let resolved = resolve_runtime_paths(&runtime_root)?;
     26 
     27     ensure_identity(&resolved.signer_identity_path)?;
     28     ensure_identity(&resolved.user_identity_path)?;
     29 
     30     println!(
     31         "ok bootstrap-myc-repo-local-identities {}",
     32         runtime_root.display()
     33     );
     34     Ok(())
     35 }
     36 
     37 fn runtime_root_from_args() -> Result<PathBuf, String> {
     38     let mut args = env::args_os();
     39     let _ = args.next();
     40     let Some(runtime_root) = args.next() else {
     41         return Err("usage: myc_repo_local_identity_bootstrap <runtime-root>".to_owned());
     42     };
     43     if args.next().is_some() {
     44         return Err("usage: myc_repo_local_identity_bootstrap <runtime-root>".to_owned());
     45     }
     46     Ok(PathBuf::from(runtime_root))
     47 }
     48 
     49 struct MycRuntimePaths {
     50     signer_identity_path: PathBuf,
     51     user_identity_path: PathBuf,
     52 }
     53 
     54 fn resolve_runtime_paths(runtime_root: &Path) -> Result<MycRuntimePaths, String> {
     55     let base_paths = RadrootsPathResolver::current()
     56         .resolve(
     57             RadrootsPathProfile::RepoLocal,
     58             &RadrootsPathOverrides::repo_local(runtime_root),
     59         )
     60         .map_err(|err| format!("resolve repo_local runtime roots: {err}"))?;
     61     let myc_namespace = RadrootsRuntimeNamespace::service("myc")
     62         .map_err(|err| format!("resolve myc namespace: {err}"))?;
     63     let myc_paths = base_paths.namespaced(&myc_namespace);
     64     Ok(MycRuntimePaths {
     65         signer_identity_path: myc_paths.secrets.join("signer-identity.json"),
     66         user_identity_path: myc_paths.secrets.join("user-identity.json"),
     67     })
     68 }
     69 
     70 fn ensure_identity(path: &Path) -> Result<(), String> {
     71     if path.is_file() {
     72         load_encrypted_identity(path)
     73             .map_err(|err| format!("load encrypted identity {}: {err}", path.display()))?;
     74         return Ok(());
     75     }
     76 
     77     if let Some(parent) = path.parent() {
     78         std::fs::create_dir_all(parent)
     79             .map_err(|err| format!("create identity dir {}: {err}", parent.display()))?;
     80     }
     81     let identity = RadrootsIdentity::generate();
     82     store_encrypted_identity(path, &identity)
     83         .map_err(|err| format!("store encrypted identity {}: {err}", path.display()))?;
     84     Ok(())
     85 }