use crate::core::types::Resource;
const UFW_GUARD: &str = "\
if ! command -v ufw >/dev/null 2>&1; then\n \
echo 'FORJAR_WARN: ufw not found - skipping network resource (no firewall)'\n \
exit 0\n\
fi";
pub fn check_script(resource: &Resource) -> String {
let port = resource.port.as_deref().unwrap_or("0");
let protocol = resource.protocol.as_deref().unwrap_or("tcp");
let action = resource.action.as_deref().unwrap_or("allow");
format!(
"{UFW_GUARD}\nufw status numbered 2>/dev/null | grep -q '{action}.*{port}/{protocol}' && echo 'exists:{port}' || echo 'missing:{port}'"
)
}
pub fn apply_script(resource: &Resource) -> String {
let port = resource.port.as_deref().unwrap_or("0");
let protocol = resource.protocol.as_deref().unwrap_or("tcp");
let action = resource.action.as_deref().unwrap_or("allow");
let state = resource.state.as_deref().unwrap_or("present");
let mut lines = vec![
"set -euo pipefail".to_string(),
UFW_GUARD.to_string(),
"SUDO=\"\"".to_string(),
"[ \"$(id -u)\" -ne 0 ] && SUDO=\"sudo\"".to_string(),
"$SUDO ufw --force enable".to_string(),
];
match state {
"absent" => {
let mut rule_parts = vec![];
if let Some(ref from) = resource.from_addr {
rule_parts.push(format!("from '{from}'"));
}
rule_parts.push(format!("to any port '{port}' proto '{protocol}'"));
lines.push(format!(
"$SUDO ufw delete {} {} || true",
action,
rule_parts.join(" ")
));
}
_ => {
let mut rule_parts = vec![];
if let Some(ref from) = resource.from_addr {
rule_parts.push(format!("from '{from}'"));
}
rule_parts.push(format!("to any port '{port}' proto '{protocol}'"));
if let Some(ref comment) = resource.name {
lines.push(format!(
"$SUDO ufw {} {} comment '{}'",
action,
rule_parts.join(" "),
comment
));
} else {
lines.push(format!("$SUDO ufw {} {}", action, rule_parts.join(" ")));
}
}
}
lines.join("\n")
}
pub fn state_query_script(resource: &Resource) -> String {
let port = resource.port.as_deref().unwrap_or("0");
format!(
"{UFW_GUARD}\nufw status verbose 2>/dev/null | grep '{port}' || echo 'rule=MISSING:{port}'"
)
}