pubky-homeserver 0.12.0

A Pubky homeserver implementation.
Documentation
use axum::http::{header, HeaderMap};

use crate::client_server::auth::grant::crypto::session_token::SessionBearer;

pub(crate) enum BearerTokenExtraction {
    Present(SessionBearer),
    InvalidBearer,
    NonBearer,
    Missing,
}

impl BearerTokenExtraction {
    pub(crate) fn has_bearer_scheme(&self) -> bool {
        matches!(self, Self::Present(_) | Self::InvalidBearer)
    }
}

pub(crate) fn extract_bearer_token(headers: &HeaderMap) -> BearerTokenExtraction {
    let Some(value) = headers.get(header::AUTHORIZATION) else {
        return BearerTokenExtraction::Missing;
    };

    let Some(raw_token) = value.as_bytes().strip_prefix(b"Bearer ") else {
        return BearerTokenExtraction::NonBearer;
    };
    let Ok(raw_token) = std::str::from_utf8(raw_token) else {
        return BearerTokenExtraction::InvalidBearer;
    };

    match SessionBearer::parse(raw_token) {
        Ok(bearer) => BearerTokenExtraction::Present(bearer),
        Err(_) => BearerTokenExtraction::InvalidBearer,
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use axum::http::HeaderValue;

    const UNKNOWN_WELL_FORMED_BEARER: &str = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG";

    fn headers(value: HeaderValue) -> HeaderMap {
        let mut headers = HeaderMap::new();
        headers.insert(header::AUTHORIZATION, value);
        headers
    }

    fn extraction_name(actual: &BearerTokenExtraction) -> &'static str {
        match actual {
            BearerTokenExtraction::Present(_) => "present",
            BearerTokenExtraction::InvalidBearer => "invalid_bearer",
            BearerTokenExtraction::NonBearer => "non_bearer",
            BearerTokenExtraction::Missing => "missing",
        }
    }

    #[test]
    fn extract_bearer_token_classifies_authorization_header() {
        let cases = [
            (HeaderMap::new(), "missing", false),
            (
                headers(HeaderValue::from_static("Basic dXNlcjpwYXNz")),
                "non_bearer",
                false,
            ),
            (
                headers(HeaderValue::from_static("Bearer ")),
                "invalid_bearer",
                true,
            ),
            (
                headers(HeaderValue::from_bytes(b"Bearer \xff").expect("valid header bytes")),
                "invalid_bearer",
                true,
            ),
            (
                headers(
                    HeaderValue::from_str(&format!("Bearer {UNKNOWN_WELL_FORMED_BEARER}"))
                        .expect("valid header"),
                ),
                "present",
                true,
            ),
        ];

        for (headers, expected, has_bearer_scheme) in cases {
            let actual = extract_bearer_token(&headers);
            assert_eq!(extraction_name(&actual), expected);
            assert_eq!(actual.has_bearer_scheme(), has_bearer_scheme);
        }
    }
}