summaryrefslogtreecommitdiff
path: root/src/services/authorization.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/services/authorization.rs')
-rw-r--r--src/services/authorization.rs50
1 files changed, 50 insertions, 0 deletions
diff --git a/src/services/authorization.rs b/src/services/authorization.rs
new file mode 100644
index 0000000..b9d57ae
--- /dev/null
+++ b/src/services/authorization.rs
@@ -0,0 +1,50 @@
+use base64::Engine;
+use raise::yeet;
+use thiserror::Error;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Error)]
+pub enum ParseBasicError {
+ #[error("Basic Authorization is required")]
+ NotBasic,
+ #[error("No credentials were provided for authorization")]
+ NoCredentials,
+ #[error("The credentials provided were not base64")]
+ InvalidBase64,
+ #[error("The decoded base64 credentials were not UTF-8")]
+ NotUtf8,
+ #[error("A colon (:) must be used to delimit the username and password")]
+ NoColon,
+}
+
+/// Returns a username and a password from a Basic authorization header
+pub fn parse_basic(value: &str) -> Result<(Box<str>, Box<str>), ParseBasicError> {
+ if !value.starts_with("Basic") {
+ yeet!(ParseBasicError::NotBasic);
+ }
+
+ let value: String = value
+ .chars()
+ .skip(5)
+ .skip_while(|ch| ch.is_whitespace())
+ .collect();
+
+ if value.is_empty() {
+ yeet!(ParseBasicError::NoCredentials);
+ }
+
+ let Ok(bytes) = base64::engine::general_purpose::STANDARD.decode(value) else {
+ yeet!(ParseBasicError::InvalidBase64)
+ };
+
+ let Ok(value) = String::from_utf8(bytes) else {
+ yeet!(ParseBasicError::NotUtf8)
+ };
+
+ let mut parts = value.split(':');
+ let username = parts.next().unwrap();
+ let Some(password) = parts.next() else {
+ yeet!(ParseBasicError::NoColon)
+ };
+
+ Ok((Box::from(username), Box::from(password)))
+}