1use crate::bindings::vtx::api::auth_types::UserContext;
4use crate::error::{VtxError, VtxResult};
5
6pub struct AuthRequest<'a> {
11 headers: &'a [(String, String)],
12}
13
14impl<'a> AuthRequest<'a> {
15 pub fn new(headers: &'a [(String, String)]) -> Self {
17 Self { headers }
18 }
19
20 pub fn header(&self, key: &str) -> Option<&str> {
22 let search_key = key.to_lowercase();
23 for (k, v) in self.headers {
24 if k.to_lowercase() == search_key {
25 return Some(v.as_str());
26 }
27 }
28 None
29 }
30
31 pub fn require_header(&self, key: &str) -> VtxResult<&str> {
36 self.header(key).ok_or_else(|| {
37 VtxError::AuthDenied(401)
40 })
41 }
42
43 pub fn bearer_token(&self) -> Option<&str> {
47 let val = self.header("Authorization")?;
48 if val.starts_with("Bearer ") || val.starts_with("bearer ") {
49 Some(&val[7..])
50 } else {
51 None
52 }
53 }
54
55 pub fn require_bearer_token(&self) -> VtxResult<&str> {
60 self.bearer_token().ok_or_else(|| VtxError::AuthDenied(401))
61 }
62
63 pub fn basic_auth(&self) -> Option<&str> {
65 let val = self.header("Authorization")?;
66 if val.starts_with("Basic ") || val.starts_with("basic ") {
67 Some(&val[6..])
68 } else {
69 None
70 }
71 }
72}
73
74pub struct UserBuilder {
79 user_id: String,
80 username: String,
81 groups: Vec<String>,
82 metadata: serde_json::Map<String, serde_json::Value>,
83}
84
85impl UserBuilder {
86 pub fn new(id: impl Into<String>, name: impl Into<String>) -> Self {
90 Self {
91 user_id: id.into(),
92 username: name.into(),
93 groups: Vec::new(),
94 metadata: serde_json::Map::new(),
95 }
96 }
97
98 pub fn group(mut self, group: impl Into<String>) -> Self {
100 self.groups.push(group.into());
101 self
102 }
103
104 pub fn meta<V: serde::Serialize>(mut self, key: &str, value: V) -> Self {
108 if let Ok(val) = serde_json::to_value(value) {
109 self.metadata.insert(key.to_string(), val);
110 }
111 self
112 }
113
114 pub fn build(self) -> UserContext {
118 UserContext {
119 user_id: self.user_id,
120 username: self.username,
121 groups: self.groups,
122 metadata: serde_json::to_string(&self.metadata).unwrap_or_else(|_| "{}".to_string()),
123 }
124 }
125}
126
127pub trait IntoAuthResult {
133 fn into_auth_result(self) -> Result<UserContext, u16>;
134}
135
136impl IntoAuthResult for VtxResult<UserContext> {
137 fn into_auth_result(self) -> Result<UserContext, u16> {
138 match self {
139 Ok(ctx) => Ok(ctx),
140 Err(e) => {
141 let status_code = match e {
143 VtxError::AuthDenied(code) => code,
144 VtxError::PermissionDenied(_) => 403,
145 VtxError::NotFound(_) => 404,
146 VtxError::DatabaseError(_)
148 | VtxError::SerializationError(_)
149 | VtxError::Internal(_) => 500,
150 };
151 Err(status_code)
152 }
153 }
154 }
155}