use crate::types::{DecideError, Resource, RoleMap, User};
use crate::utils::{evaluate_condition, log_debug};
use std::fs::{self};
pub struct Decide {
roles: RoleMap,
}
impl Decide {
pub fn new (roles: RoleMap) -> Self {
Self {
roles,
}
}
pub fn from_file (path: &str) -> Result<Self, Box<dyn std::error::Error>> {
let content = fs::read_to_string(path)?;
let roles: RoleMap = serde_json::from_str(&content)?;
Ok(Self::new(roles))
}
pub fn default () -> Result<Self, Box<dyn std::error::Error>> {
Self::from_file("decide.config.json")
}
pub fn can (&self, user: &User, action: &str, resource: &Resource) -> Result<bool, DecideError> {
for role_name in &user.roles {
if let Some(role) = self.roles.get(role_name) {
for pmsn in &role.permissions {
if pmsn.action != action {
continue;
}
match &pmsn.condition {
Some(expr) => {
let passed = evaluate_condition(expr, user, resource);
log_debug(&format!(
"Action '{}', condition '{}' -> {}",
action, expr, passed
));
if passed {
return Ok(true);
}
}
None => {
log_debug(&format!("Action '{}': No condition, allowing.", action));
return Ok(true);
}
}
}
} else {
return Err(DecideError::MissingRole(role_name.clone()));
}
}
Ok(false)
}
}