summaryrefslogtreecommitdiff
path: root/src/services/authorization.rs
blob: b9d57ae7e7c8ed7003ea732426a691a85139ea27 (plain)
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)))
}