use anyhow::{Context, Result};
use std::fs;
use std::path::PathBuf;
pub struct UfwPersistence {
rules_path: PathBuf,
}
impl UfwPersistence {
pub fn new() -> Self {
Self {
rules_path: PathBuf::from("/etc/ufw/user.rules"),
}
}
pub fn save_rules(&self, rules: &[String]) -> Result<()> {
let content = rules.join("\n");
fs::write(&self.rules_path, content)
.context(format!("Failed to write UFW rules to {}", self.rules_path.display()))?;
tracing::info!("UFW rules saved to {}", self.rules_path.display());
Ok(())
}
pub fn load_rules(&self) -> Result<Vec<String>> {
if !self.rules_path.exists() {
return Ok(Vec::new());
}
let content = fs::read_to_string(&self.rules_path)
.context(format!("Failed to read UFW rules from {}", self.rules_path.display()))?;
Ok(content.lines().map(|s| s.to_string()).collect())
}
pub fn backup(&self) -> Result<PathBuf> {
let backup_path = PathBuf::from(format!(
"/etc/ufw/user.rules.bak.{}",
chrono::Utc::now().format("%Y%m%d%H%M%S")
));
if self.rules_path.exists() {
fs::copy(&self.rules_path, &backup_path)
.context("Failed to backup UFW rules")?;
tracing::info!("UFW rules backed up to {}", backup_path.display());
}
Ok(backup_path)
}
}
impl Default for UfwPersistence {
fn default() -> Self {
Self::new()
}
}