//! Laden/Erzeugen und Persistieren des Iroh-SecretKeys (Node-Identität). use std::path::Path; use anyhow::{Context, Result}; use data_encoding::HEXLOWER; use iroh::SecretKey; /// Lädt den SecretKey aus `path` oder erzeugt einen neuen und speichert ihn. /// /// Der Key bestimmt die EndpointId (= Public Key = Adresse im Iroh-Netz). Persistenz /// ist wichtig, damit der Serving Host nach einem Neustart unter derselben Adresse /// erreichbar bleibt. pub fn load_or_create_secret_key(path: &Path) -> Result { if path.exists() { let hex = std::fs::read_to_string(path) .with_context(|| format!("Key-Datei lesen: {}", path.display()))?; let bytes = HEXLOWER .decode(hex.trim().as_bytes()) .context("Key-Datei ist kein gültiges Hex")?; let arr: [u8; 32] = bytes .as_slice() .try_into() .context("Key-Datei hat nicht 32 Bytes")?; Ok(SecretKey::from_bytes(&arr)) } else { let secret_key = SecretKey::generate(); let hex = HEXLOWER.encode(&secret_key.to_bytes()); write_secret(path, &hex) .with_context(|| format!("Key-Datei schreiben: {}", path.display()))?; Ok(secret_key) } } #[cfg(unix)] fn write_secret(path: &Path, hex: &str) -> Result<()> { use std::io::Write; use std::os::unix::fs::OpenOptionsExt; if let Some(parent) = path.parent() { if !parent.as_os_str().is_empty() { std::fs::create_dir_all(parent)?; } } let mut f = std::fs::OpenOptions::new() .write(true) .create_new(true) .mode(0o600) .open(path)?; f.write_all(hex.as_bytes())?; Ok(()) } #[cfg(not(unix))] fn write_secret(path: &Path, hex: &str) -> Result<()> { if let Some(parent) = path.parent() { if !parent.as_os_str().is_empty() { std::fs::create_dir_all(parent)?; } } std::fs::write(path, hex)?; Ok(()) }