1use std::collections::BTreeMap;23use anyhow::Result;4use log::*;56use crate::{7 command::ssh_command,8 nix::{NixEval, HOSTS_ATTRIBUTE},9};1011use serde::{Deserialize, Serialize};1213use super::db::DbData;1415pub fn list_hosts() -> Result<Vec<String>> {16 Ok(NixEval::new(HOSTS_ATTRIBUTE.into())17 .apply("builtins.attrNames".into())18 .run_json()?)19}2021#[derive(Serialize, Deserialize, Default)]22pub struct KeyDb {23 host_keys: BTreeMap<String, String>,24}25impl DbData for KeyDb {26 const DB_NAME: &'static str = "keys";27}2829impl KeyDb {30 pub fn fetch_key(&mut self, host: &str) -> Result<()> {31 info!("Fetching key for {}", host);32 let key = ssh_command(host, &["cat", "/etc/ssh/ssh_host_ed25519_key.pub"])?33 .as_str()?34 .trim()35 .to_owned();36 self.host_keys.insert(host.to_owned(), key);37 Ok(())38 }3940 pub fn ensure_key_loaded(&mut self, host: &str, force: bool) -> Result<()> {41 if !self.host_keys.contains_key(host) || force {42 self.fetch_key(host)?;43 }44 Ok(())45 }4647 pub fn get_host_key(&self, host: &str) -> Result<String> {48 Ok(self49 .host_keys50 .get(host)51 .ok_or_else(|| anyhow::anyhow!("no host key for {}", host))?52 .to_owned())53 }5455 pub fn has_key(&self, key: &str) -> bool {56 self.host_keys.contains_key(key)57 }5859 pub fn remove_key(&mut self, host: &str) {60 self.host_keys.remove(host);61 }62}