Files
narlblog/backend/src/auth.rs
T

50 lines
1.5 KiB
Rust

use crate::error::AppError;
use axum::http::HeaderMap;
use subtle::ConstantTimeEq;
use tracing::warn;
const COOKIE_NAME: &str = "admin";
fn extract_token(headers: &HeaderMap) -> Option<String> {
if let Some(auth) = headers.get("Authorization").and_then(|h| h.to_str().ok()) {
if let Some(token) = auth.strip_prefix("Bearer ") {
return Some(token.to_string());
}
}
if let Some(cookie_header) = headers.get("Cookie").and_then(|h| h.to_str().ok()) {
for part in cookie_header.split(';') {
let part = part.trim();
if let Some(value) = part.strip_prefix(&format!("{}=", COOKIE_NAME)) {
return Some(value.to_string());
}
}
}
None
}
fn token_matches(provided: &str, expected: &str) -> bool {
let a = provided.as_bytes();
let b = expected.as_bytes();
if a.len() != b.len() {
// Still do a constant-time compare to make timing uniform on the same-length path.
let _ = a.ct_eq(a);
return false;
}
a.ct_eq(b).into()
}
pub fn is_authed(headers: &HeaderMap, admin_token: &str) -> bool {
match extract_token(headers) {
Some(t) => token_matches(&t, admin_token),
None => false,
}
}
pub fn check_auth(headers: &HeaderMap, admin_token: &str) -> Result<(), AppError> {
if !is_authed(headers, admin_token) {
warn!("Unauthorized access attempt");
return Err(AppError::Unauthorized);
}
Ok(())
}