spacegate_kernel/utils/auth/
basic.rs1use std::{convert::Infallible, str::FromStr};
2
3use base64::Engine;
4use hyper::http::HeaderValue;
5
6use crate::{BoxError, BoxResult};
7
8use super::Authorization;
9
10#[derive(Debug, Clone)]
11pub struct Basic {
12 pub username: String,
13 pub password: Option<String>,
14}
15
16impl From<Authorization<Basic>> for Basic {
17 fn from(val: Authorization<Self>) -> Self {
18 val.0
19 }
20}
21
22impl From<Basic> for Authorization<Basic> {
23 fn from(val: Basic) -> Self {
24 Authorization(val)
25 }
26}
27
28impl TryInto<HeaderValue> for &Basic {
29 type Error = BoxError;
30 fn try_into(self) -> Result<HeaderValue, Self::Error> {
31 self.to_header()
32 }
33}
34
35impl TryFrom<HeaderValue> for Basic {
36 type Error = BoxError;
37 fn try_from(header: HeaderValue) -> Result<Self, Self::Error> {
38 if let Ok(header) = header.to_str() {
39 if let Some(base64_auth) = header.strip_prefix("Basic ") {
40 let auth = base64::engine::general_purpose::STANDARD.decode(base64_auth)?;
41 let auth = String::from_utf8(auth)?;
42 return Ok(Basic::infallible_parse(auth.as_str()));
43 } else {
44 Err("auth header value is not a basic auth value".into())
45 }
46 } else {
47 Err("auth header value is not a valid string".into())
48 }
49 }
50}
51
52impl std::fmt::Display for Basic {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 if let Some(password) = &self.password {
55 write!(f, "{}:{}", self.username, password)
56 } else {
57 write!(f, "{}", self.username)
58 }
59 }
60}
61
62impl Basic {
63 pub fn new(username: String, password: Option<String>) -> Self {
64 Self { username, password }
65 }
66 pub fn to_auth_string(&self) -> String {
67 match &self.password {
68 Some(password) => format!("{}:{}", self.username, password),
69 None => self.username.clone(),
70 }
71 }
72 pub fn to_header(&self) -> BoxResult<HeaderValue> {
75 let auth_string = self.to_auth_string();
76 let mut header_str = String::with_capacity(auth_string.len() + 10);
77 header_str.push_str("Basic ");
78 base64::engine::general_purpose::STANDARD.encode_string(auth_string, &mut header_str);
79 let header = HeaderValue::from_maybe_shared(header_str)?;
80 Ok(header)
81 }
82 pub fn infallible_parse(auth: &str) -> Self {
83 if let Some((username, password)) = auth.split_once(':') {
84 Self::new(username.to_string(), Some(password.to_string()))
85 } else {
86 Self::new(auth.to_string(), None)
87 }
88 }
89}
90
91impl FromStr for Basic {
92 type Err = Infallible;
93
94 fn from_str(s: &str) -> Result<Self, Self::Err> {
95 Ok(Basic::infallible_parse(s))
96 }
97}