use std::path::{Path, PathBuf};
const CERTMESH_DIR: &str = "certmesh";
const CA_SUBDIR: &str = "ca";
const CERTS_DIR: &str = "certs";
const LOGS_DIR: &str = "logs";
const CA_KEY_FILENAME: &str = "ca-key.enc";
const CA_CERT_FILENAME: &str = "ca-cert.pem";
const SLOT_TABLE_FILENAME: &str = "unlock-slots.json";
const AUTH_FILENAME: &str = "auth.json";
const ROSTER_FILENAME: &str = "roster.json";
const MEMBER_STATE_FILENAME: &str = "member.json";
const INVITES_FILENAME: &str = "invites.json";
const MACHINE_BIND_FILENAME: &str = "machine.bind";
const TOTP_THROTTLE_FILENAME: &str = "totp-throttle.json";
const AUDIT_FILENAME: &str = "certmesh-audit.log";
const AUTO_UNLOCK_KEY_FILENAME: &str = "auto-unlock-key";
const ACME_SUBDIR: &str = "acme";
const ACME_ACCOUNTS_FILENAME: &str = "accounts.json";
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CertmeshPaths {
data_dir: PathBuf,
}
impl CertmeshPaths {
pub fn with_data_dir(data_dir: PathBuf) -> Self {
Self { data_dir }
}
pub fn data_dir(&self) -> &Path {
&self.data_dir
}
pub fn certmesh_dir(&self) -> PathBuf {
self.data_dir.join(CERTMESH_DIR)
}
pub fn ca_dir(&self) -> PathBuf {
self.certmesh_dir().join(CA_SUBDIR)
}
pub fn ca_key_path(&self) -> PathBuf {
self.ca_dir().join(CA_KEY_FILENAME)
}
pub fn ca_cert_path(&self) -> PathBuf {
self.ca_dir().join(CA_CERT_FILENAME)
}
pub fn auth_path(&self) -> PathBuf {
self.ca_dir().join(AUTH_FILENAME)
}
pub fn roster_path(&self) -> PathBuf {
self.certmesh_dir().join(ROSTER_FILENAME)
}
pub fn member_state_path(&self) -> PathBuf {
self.certmesh_dir().join(MEMBER_STATE_FILENAME)
}
pub fn invites_path(&self) -> PathBuf {
self.certmesh_dir().join(INVITES_FILENAME)
}
pub fn slot_table_path(&self) -> PathBuf {
self.ca_dir().join(SLOT_TABLE_FILENAME)
}
pub fn machine_bind_path(&self) -> PathBuf {
self.ca_dir().join(MACHINE_BIND_FILENAME)
}
pub fn rate_limiter_path(&self) -> PathBuf {
self.ca_dir().join(TOTP_THROTTLE_FILENAME)
}
pub fn certs_dir(&self) -> PathBuf {
self.data_dir.join(CERTS_DIR)
}
pub fn log_dir(&self) -> PathBuf {
self.data_dir.join(LOGS_DIR)
}
pub fn audit_log_path(&self) -> PathBuf {
self.log_dir().join(AUDIT_FILENAME)
}
pub fn auto_unlock_key_path(&self) -> PathBuf {
self.certmesh_dir().join(AUTO_UNLOCK_KEY_FILENAME)
}
pub fn acme_dir(&self) -> PathBuf {
self.certmesh_dir().join(ACME_SUBDIR)
}
pub fn acme_accounts_path(&self) -> PathBuf {
self.acme_dir().join(ACME_ACCOUNTS_FILENAME)
}
pub fn is_ca_initialized(&self) -> bool {
self.ca_key_path().exists()
}
pub fn has_slot_table(&self) -> bool {
self.slot_table_path().exists()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn default_paths_derive_from_data_dir() {
let paths = CertmeshPaths::with_data_dir(PathBuf::from("/test/root"));
assert_eq!(paths.certmesh_dir(), PathBuf::from("/test/root/certmesh"));
assert_eq!(paths.ca_dir(), PathBuf::from("/test/root/certmesh/ca"));
assert_eq!(
paths.ca_key_path(),
PathBuf::from("/test/root/certmesh/ca/ca-key.enc")
);
assert_eq!(
paths.ca_cert_path(),
PathBuf::from("/test/root/certmesh/ca/ca-cert.pem")
);
assert_eq!(
paths.auth_path(),
PathBuf::from("/test/root/certmesh/ca/auth.json")
);
assert_eq!(
paths.roster_path(),
PathBuf::from("/test/root/certmesh/roster.json")
);
assert_eq!(
paths.invites_path(),
PathBuf::from("/test/root/certmesh/invites.json")
);
assert_eq!(
paths.slot_table_path(),
PathBuf::from("/test/root/certmesh/ca/unlock-slots.json")
);
assert_eq!(paths.certs_dir(), PathBuf::from("/test/root/certs"));
assert_eq!(
paths.audit_log_path(),
PathBuf::from("/test/root/logs/certmesh-audit.log")
);
assert_eq!(
paths.auto_unlock_key_path(),
PathBuf::from("/test/root/certmesh/auto-unlock-key")
);
}
#[test]
fn is_ca_initialized_false_for_nonexistent_dir() {
let paths = CertmeshPaths::with_data_dir(PathBuf::from("/nonexistent/path"));
assert!(!paths.is_ca_initialized());
}
#[test]
fn has_slot_table_false_for_nonexistent_dir() {
let paths = CertmeshPaths::with_data_dir(PathBuf::from("/nonexistent/path"));
assert!(!paths.has_slot_table());
}
}