use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RemoteCred {
pub host: String,
pub user: String,
#[serde(default)]
pub password: Option<String>,
#[serde(default = "default_port")]
pub port: u64,
#[serde(default)]
pub key: Option<String>,
}
fn default_port() -> u64 {
22
}
fn store_path() -> PathBuf {
dirs_next::home_dir()
.unwrap_or_default()
.join(".aegis")
.join("remotes.json")
}
pub fn load_all() -> HashMap<String, RemoteCred> {
std::fs::read_to_string(store_path())
.ok()
.and_then(|c| serde_json::from_str(&c).ok())
.unwrap_or_default()
}
pub fn get(name: &str) -> Option<RemoteCred> {
load_all().get(name).cloned()
}
pub fn list_names() -> Vec<String> {
let mut v: Vec<String> = load_all().into_keys().collect();
v.sort();
v
}
pub fn save(name: &str, cred: RemoteCred) -> anyhow::Result<()> {
let mut all = load_all();
all.insert(name.to_string(), cred);
let path = store_path();
if let Some(p) = path.parent() {
std::fs::create_dir_all(p)?;
}
std::fs::write(&path, serde_json::to_string_pretty(&all)?)?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let _ = std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o600));
}
Ok(())
}
pub fn remove(name: &str) -> anyhow::Result<bool> {
let mut all = load_all();
let existed = all.remove(name).is_some();
if existed {
std::fs::write(store_path(), serde_json::to_string_pretty(&all)?)?;
}
Ok(existed)
}
pub fn all_passwords() -> Vec<String> {
load_all()
.into_values()
.filter_map(|c| c.password)
.filter(|p| p.len() >= 4)
.collect()
}