ingress-core 0.1.5

Core request, identity, and event types for Gatewarden.
Documentation
use chrono::{DateTime, Utc};
use http::{HeaderMap, Method};
use serde::{Deserialize, Serialize};
use std::net::IpAddr;

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum GatewayKind {
    Caddy,
    Nginx,
    Traefik,
    Unknown,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GatewayMetadata {
    pub kind: GatewayKind,
    pub adapter_version: String,
    pub raw_forwarded_for: Option<String>,
}

impl GatewayMetadata {
    pub fn new(kind: GatewayKind, adapter_version: impl Into<String>) -> Self {
        Self {
            kind,
            adapter_version: adapter_version.into(),
            raw_forwarded_for: None,
        }
    }
}

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AuthContext {
    pub is_authenticated: bool,
    pub subject_id: Option<String>,
    pub email: Option<String>,
    pub groups: Vec<String>,
    pub provider: Option<String>,
}

#[derive(Debug, Clone)]
pub struct RequestContext {
    pub request_id: String,
    pub received_at: DateTime<Utc>,
    pub method: Method,
    pub path: String,
    pub normalized_path: String,
    pub query: Option<String>,
    pub headers: HeaderMap,
    pub client_ip: IpAddr,
    pub scheme: String,
    pub host: String,
    pub user_agent: Option<String>,
    pub auth: AuthContext,
    pub gateway: GatewayKind,
}

pub type CanonicalRequestContext = RequestContext;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum DecisionAction {
    Allow,
    Block,
    RateLimit,
    Shadow,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RateLimitStatus {
    pub remaining: u32,
    pub reset_at_unix: i64,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Decision {
    pub action: DecisionAction,
    pub reason_codes: Vec<String>,
    pub matched_rule_ids: Vec<String>,
    pub rate_limit_status: Option<RateLimitStatus>,
}

impl Decision {
    pub fn allow(reason: impl Into<String>) -> Self {
        Self {
            action: DecisionAction::Allow,
            reason_codes: vec![reason.into()],
            matched_rule_ids: Vec::new(),
            rate_limit_status: None,
        }
    }

    pub fn block(reason: impl Into<String>, rule_id: impl Into<String>) -> Self {
        Self {
            action: DecisionAction::Block,
            reason_codes: vec![reason.into()],
            matched_rule_ids: vec![rule_id.into()],
            rate_limit_status: None,
        }
    }

    pub fn shadow(reason: impl Into<String>, rule_id: impl Into<String>) -> Self {
        Self {
            action: DecisionAction::Shadow,
            reason_codes: vec![reason.into()],
            matched_rule_ids: vec![rule_id.into()],
            rate_limit_status: None,
        }
    }

    pub fn rate_limit(
        reason: impl Into<String>,
        rule_id: impl Into<String>,
        remaining: u32,
        reset_at_unix: i64,
    ) -> Self {
        Self {
            action: DecisionAction::RateLimit,
            reason_codes: vec![reason.into()],
            matched_rule_ids: vec![rule_id.into()],
            rate_limit_status: Some(RateLimitStatus {
                remaining,
                reset_at_unix,
            }),
        }
    }
}