coil-runtime 0.1.1

HTTP runtime and request handling for the Coil framework.
Documentation
use super::*;
use std::sync::{Arc, Mutex};

#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct LiveAuthorizationCheck {
    pub subject: coil_auth::DefaultSubject,
    pub capability: coil_auth::Capability,
    pub object: coil_auth::Entity,
}

#[derive(Debug, Clone, Default)]
pub(crate) struct StaticLiveRouteCapabilityAuthorizer {
    allowed: Vec<LiveAuthorizationCheck>,
    checks: Arc<Mutex<Vec<LiveAuthorizationCheck>>>,
}

impl StaticLiveRouteCapabilityAuthorizer {
    pub(crate) fn new() -> Self {
        Self::default()
    }

    pub(crate) fn allowing(
        mut self,
        subject: coil_auth::DefaultSubject,
        capability: coil_auth::Capability,
        object: coil_auth::Entity,
    ) -> Self {
        self.allowed.push(LiveAuthorizationCheck {
            subject,
            capability,
            object,
        });
        self
    }

    pub(crate) fn checks(&self) -> Vec<LiveAuthorizationCheck> {
        self.checks
            .lock()
            .expect("static live authorizer mutex poisoned")
            .clone()
    }
}

#[derive(Debug, Clone, Default)]
pub(crate) struct StaticLiveAuthExplainer {
    response: Option<coil_auth::CapabilityExplanation>,
    requests: Arc<Mutex<Vec<LiveAuthExplainRequest>>>,
}

impl StaticLiveAuthExplainer {
    pub(crate) fn new(response: coil_auth::CapabilityExplanation) -> Self {
        Self {
            response: Some(response),
            requests: Arc::new(Mutex::new(Vec::new())),
        }
    }

    pub(crate) fn requests(&self) -> Vec<LiveAuthExplainRequest> {
        self.requests
            .lock()
            .expect("static live explainer mutex poisoned")
            .clone()
    }
}

impl LiveAuthExplainer for StaticLiveAuthExplainer {
    fn explain_capability<'a>(
        &'a self,
        request: &'a LiveAuthExplainRequest,
    ) -> AuthExplainFuture<'a> {
        let response = self.response.clone().expect("static response must be set");
        Box::pin(async move {
            self.requests
                .lock()
                .expect("static live explainer mutex poisoned")
                .push(request.clone());
            Ok(response)
        })
    }
}

impl LiveRouteCapabilityAuthorizer for StaticLiveRouteCapabilityAuthorizer {
    fn check_capability<'a>(
        &'a self,
        subject: &'a coil_auth::DefaultSubject,
        capability: coil_auth::Capability,
        object: &'a coil_auth::Entity,
    ) -> RouteAuthorizationFuture<'a> {
        Box::pin(async move {
            let check = LiveAuthorizationCheck {
                subject: subject.clone(),
                capability,
                object: object.clone(),
            };
            self.checks
                .lock()
                .expect("static live authorizer mutex poisoned")
                .push(check.clone());
            Ok(self.allowed.iter().any(|allowed| allowed == &check))
        })
    }
}