decide-core 0.1.0

A fast, lightweight permission engine for Rust and TypeScript with condition support.
Documentation
use rhai::{Engine, Scope};
use rhai::Dynamic;
use crate::types::{User, Resource};
use std::fs::OpenOptions;
use std::io::Write;

pub fn log_debug(msg: &str) {
    let mut file = OpenOptions::new()
        .create(true)
        .append(true)
        .open("/tmp/decide-debug.log")
        .unwrap();
    writeln!(file, "{}", msg).unwrap();
}

pub fn evaluate_condition(expr: &str, user: &User, resource: &Resource) -> bool {
    // Create engine and scope
    let engine = Engine::new();
    let mut scope = Scope::new();

    // Exposing fields for user to use in conditions
    scope.push("user_id", Dynamic::from(user.id.clone()));
    scope.push("user_roles", Dynamic::from_array(
        user.roles.iter().map(|r| Dynamic::from(r.clone())).collect()
    ));
    scope.push("resource_owner", Dynamic::from(resource.owner_id.clone()));
    scope.push("resource_name", Dynamic::from(resource.resource_name.clone()));
    scope.push("resource_type", Dynamic::from(resource.resource_type.clone()));

    // Logging to file
    let debug_expr = format!(
        "DEBUG | expr: `{}`, user_id: `{}`, resource_owner: `{}`",
        expr, user.id, resource.owner_id
    );
    log_debug(&debug_expr);

    match engine.eval_with_scope::<bool>(&mut scope, expr) {
        Ok(result) => result,
        Err(e) => {
            // Logging to file
            let msg = format!(
                "⚠️ Rhai error while evaluating: {}\nExpr: {}\nuser_id: {}, resource_owner: {}",
                e, expr, user.id, resource.owner_id
            );
            log_debug(&msg);

            // Return value
            false
        }
    }
}