decide_core/
evaluator.rs

1use crate::types::{DecideError, Resource, RoleMap, User};
2use crate::utils::{evaluate_condition, log_debug};
3use std::fs::{self};
4
5// Core class
6pub struct Decide {
7    roles: RoleMap,
8}
9
10impl Decide {
11    // General constructor
12    pub fn new (roles: RoleMap) -> Self {
13        Self {
14            roles,
15        }
16    }
17
18    // Create from a custom JSON config file
19    pub fn from_file (path: &str) -> Result<Self, Box<dyn std::error::Error>> {
20        let content = fs::read_to_string(path)?;
21        let roles: RoleMap = serde_json::from_str(&content)?;
22        Ok(Self::new(roles))
23    }
24
25    // Create from default JSON config file
26    pub fn default () -> Result<Self, Box<dyn std::error::Error>> {
27        Self::from_file("decide.config.json")
28    }
29
30    pub fn can (&self, user: &User, action: &str, resource: &Resource) -> Result<bool, DecideError> {
31        for role_name in &user.roles {
32            if let Some(role) = self.roles.get(role_name) {
33                for pmsn in &role.permissions {
34                    if pmsn.action != action {
35                        continue;
36                    }
37
38                    match &pmsn.condition {
39                        Some(expr) => {
40                            let passed = evaluate_condition(expr, user, resource);
41                            log_debug(&format!(
42                                "Action '{}', condition '{}' -> {}",
43                                action, expr, passed
44                            ));
45                            if passed {
46                                return Ok(true);
47                            }
48                        }
49                        None => {
50                            log_debug(&format!("Action '{}': No condition, allowing.", action));
51                            return Ok(true);
52                        }
53                    }
54                }
55            } else {
56                return Err(DecideError::MissingRole(role_name.clone()));
57            }
58        }
59
60        Ok(false)
61    }
62}
63