1use crate::bindings::vtx::api::auth_types::UserContext;
2use crate::error::{VtxError, VtxResult};
3
4pub struct AuthRequest<'a> {
9 headers: &'a [(String, String)],
10}
11
12impl<'a> AuthRequest<'a> {
13 pub fn new(headers: &'a [(String, String)]) -> Self {
15 Self { headers }
16 }
17
18 pub fn header(&self, key: &str) -> Option<&str> {
20 let search_key = key.to_lowercase();
21 for (k, v) in self.headers {
22 if k.to_lowercase() == search_key {
23 return Some(v.as_str());
24 }
25 }
26 None
27 }
28
29 pub fn require_header(&self, key: &str) -> VtxResult<&str> {
34 self.header(key).ok_or_else(|| {
35 VtxError::AuthDenied(401)
38 })
39 }
40
41 pub fn bearer_token(&self) -> Option<&str> {
45 let val = self.header("Authorization")?;
46 if val.starts_with("Bearer ") || val.starts_with("bearer ") {
47 Some(&val[7..])
48 } else {
49 None
50 }
51 }
52
53 pub fn require_bearer_token(&self) -> VtxResult<&str> {
58 self.bearer_token().ok_or_else(|| VtxError::AuthDenied(401))
59 }
60
61 pub fn basic_auth(&self) -> Option<&str> {
63 let val = self.header("Authorization")?;
64 if val.starts_with("Basic ") || val.starts_with("basic ") {
65 Some(&val[6..])
66 } else {
67 None
68 }
69 }
70}
71
72pub struct UserBuilder {
77 user_id: String,
78 username: String,
79 groups: Vec<String>,
80 metadata: serde_json::Map<String, serde_json::Value>,
81}
82
83impl UserBuilder {
84 pub fn new(id: impl Into<String>, name: impl Into<String>) -> Self {
88 Self {
89 user_id: id.into(),
90 username: name.into(),
91 groups: Vec::new(),
92 metadata: serde_json::Map::new(),
93 }
94 }
95
96 pub fn group(mut self, group: impl Into<String>) -> Self {
98 self.groups.push(group.into());
99 self
100 }
101
102 pub fn meta<V: serde::Serialize>(mut self, key: &str, value: V) -> Self {
106 if let Ok(val) = serde_json::to_value(value) {
107 self.metadata.insert(key.to_string(), val);
108 }
109 self
110 }
111
112 pub fn build(self) -> UserContext {
116 UserContext {
117 user_id: self.user_id,
118 username: self.username,
119 groups: self.groups,
120 metadata: serde_json::to_string(&self.metadata).unwrap_or_else(|_| "{}".to_string()),
121 }
122 }
123}
124
125pub trait IntoAuthResult {
131 fn into_auth_result(self) -> Result<UserContext, u16>;
132}
133
134impl IntoAuthResult for VtxResult<UserContext> {
135 fn into_auth_result(self) -> Result<UserContext, u16> {
136 match self {
137 Ok(ctx) => Ok(ctx),
138 Err(e) => {
139 let status_code = match e {
141 VtxError::AuthDenied(code) => code,
142 VtxError::PermissionDenied(_) => 403,
143 VtxError::NotFound(_) => 404,
144 VtxError::DatabaseError(_)
146 | VtxError::SerializationError(_)
147 | VtxError::Internal(_) => 500,
148 };
149 Err(status_code)
150 }
151 }
152 }
153}