/ firmware / src / services / identity.rs
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  }