identity.rs
1 use alloc::string::String as AllocString; 2 use ed25519_dalek::SigningKey; 3 use esp_hal::rng::Rng; 4 5 use crate::{config::app, filesystems::sd}; 6 7 pub fn ssh_user() -> &'static str { 8 app::SSH_USER 9 } 10 11 pub fn hostname() -> &'static str { 12 app::HOSTNAME 13 } 14 15 pub fn home_dir() -> AllocString { 16 let mut home = AllocString::from("/home/"); 17 home.push_str(ssh_user()); 18 home 19 } 20 21 fn join_path(base_path: &str, path_segment: &str) -> AllocString { 22 if path_segment.starts_with('/') { 23 AllocString::from(path_segment) 24 } else { 25 let mut path = AllocString::from(base_path); 26 if !path.ends_with('/') { 27 path.push('/'); 28 } 29 path.push_str(path_segment); 30 path 31 } 32 } 33 34 fn home_dir_name_upper() -> AllocString { 35 let mut upper = AllocString::new(); 36 for character in ssh_user().chars() { 37 upper.push(character.to_ascii_uppercase()); 38 } 39 upper 40 } 41 42 pub fn ensure_home_hierarchy() { 43 let _ = sd::create_directory("HOME"); 44 let home = home_dir(); 45 let _ = sd::mkdir_at("/home", &home_dir_name_upper()); 46 let _ = sd::mkdir_at(home.as_str(), ".SSH"); 47 let _ = sd::mkdir_at(home.as_str(), ".CACHE"); 48 let _ = sd::mkdir_at(home.as_str(), ".LOCAL"); 49 50 let ssh_dir = join_path(home.as_str(), ".ssh"); 51 if sd::read_file_at::<64>(ssh_dir.as_str(), "AUTH_KEY").is_err() { 52 let _ = sd::touch_at(ssh_dir.as_str(), "AUTH_KEY"); 53 } 54 55 if sd::read_file_at::<64>(home.as_str(), ".MSHRC").is_err() { 56 let _ = sd::write_file_at(home.as_str(), ".MSHRC", b"microfetch\n"); 57 } 58 } 59 60 pub fn load_or_generate_host_key() -> [u8; 32] { 61 let home = home_dir(); 62 let ssh_dir = join_path(home.as_str(), ".ssh"); 63 64 if let Ok(contents) = sd::read_file_at::<32>(ssh_dir.as_str(), app::SSH_HOST_KEY_FILE) { 65 if contents.len() == 32 { 66 let mut key = [0u8; 32]; 67 key.copy_from_slice(contents.as_slice()); 68 return key; 69 } 70 } 71 72 let rng = Rng::new(); 73 let mut key = [0u8; 32]; 74 for chunk in key.chunks_mut(4) { 75 let random = rng.random(); 76 let bytes = random.to_le_bytes(); 77 chunk.copy_from_slice(&bytes[..chunk.len()]); 78 } 79 80 let _ = sd::write_file_at(ssh_dir.as_str(), app::SSH_HOST_KEY_FILE, &key); 81 defmt::info!("generated new SSH host key"); 82 key 83 } 84 85 pub fn signing_key() -> SigningKey { 86 SigningKey::from_bytes(&load_or_generate_host_key()) 87 }