1use chrono::{DateTime, Utc};
2use http::{HeaderMap, Method};
3use serde::{Deserialize, Serialize};
4use std::net::IpAddr;
5
6#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
7pub enum GatewayKind {
8 Caddy,
9 Nginx,
10 Traefik,
11 Unknown,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct GatewayMetadata {
16 pub kind: GatewayKind,
17 pub adapter_version: String,
18 pub raw_forwarded_for: Option<String>,
19}
20
21impl GatewayMetadata {
22 pub fn new(kind: GatewayKind, adapter_version: impl Into<String>) -> Self {
23 Self {
24 kind,
25 adapter_version: adapter_version.into(),
26 raw_forwarded_for: None,
27 }
28 }
29}
30
31#[derive(Debug, Clone, Default, Serialize, Deserialize)]
32pub struct AuthContext {
33 pub is_authenticated: bool,
34 pub subject_id: Option<String>,
35 pub email: Option<String>,
36 pub groups: Vec<String>,
37 pub provider: Option<String>,
38}
39
40#[derive(Debug, Clone)]
41pub struct RequestContext {
42 pub request_id: String,
43 pub received_at: DateTime<Utc>,
44 pub method: Method,
45 pub path: String,
46 pub normalized_path: String,
47 pub query: Option<String>,
48 pub headers: HeaderMap,
49 pub client_ip: IpAddr,
50 pub scheme: String,
51 pub host: String,
52 pub user_agent: Option<String>,
53 pub auth: AuthContext,
54 pub gateway: GatewayKind,
55}
56
57pub type CanonicalRequestContext = RequestContext;
58
59#[derive(Debug, Clone, PartialEq, Eq)]
60pub enum DecisionAction {
61 Allow,
62 Block,
63 RateLimit,
64 Shadow,
65}
66
67#[derive(Debug, Clone, PartialEq, Eq)]
68pub struct RateLimitStatus {
69 pub remaining: u32,
70 pub reset_at_unix: i64,
71}
72
73#[derive(Debug, Clone, PartialEq, Eq)]
74pub struct Decision {
75 pub action: DecisionAction,
76 pub reason_codes: Vec<String>,
77 pub matched_rule_ids: Vec<String>,
78 pub rate_limit_status: Option<RateLimitStatus>,
79}
80
81impl Decision {
82 pub fn allow(reason: impl Into<String>) -> Self {
83 Self {
84 action: DecisionAction::Allow,
85 reason_codes: vec![reason.into()],
86 matched_rule_ids: Vec::new(),
87 rate_limit_status: None,
88 }
89 }
90
91 pub fn block(reason: impl Into<String>, rule_id: impl Into<String>) -> Self {
92 Self {
93 action: DecisionAction::Block,
94 reason_codes: vec![reason.into()],
95 matched_rule_ids: vec![rule_id.into()],
96 rate_limit_status: None,
97 }
98 }
99
100 pub fn shadow(reason: impl Into<String>, rule_id: impl Into<String>) -> Self {
101 Self {
102 action: DecisionAction::Shadow,
103 reason_codes: vec![reason.into()],
104 matched_rule_ids: vec![rule_id.into()],
105 rate_limit_status: None,
106 }
107 }
108
109 pub fn rate_limit(
110 reason: impl Into<String>,
111 rule_id: impl Into<String>,
112 remaining: u32,
113 reset_at_unix: i64,
114 ) -> Self {
115 Self {
116 action: DecisionAction::RateLimit,
117 reason_codes: vec![reason.into()],
118 matched_rule_ids: vec![rule_id.into()],
119 rate_limit_status: Some(RateLimitStatus {
120 remaining,
121 reset_at_unix,
122 }),
123 }
124 }
125}