use axum::{ http::{HeaderMap, StatusCode}, response::{IntoResponse, Response}, }; use tonic::{Request, metadata::MetadataValue}; #[derive(Debug)] pub(crate) enum AuthenticationError { Missing, Invalid, } pub(crate) fn authenticated_request( headers: &HeaderMap, message: T, ) -> Result, AuthenticationError> { let token = crate::cookie_value(headers, "analytics_token") .ok_or(AuthenticationError::Missing)?; let value = MetadataValue::try_from(format!("Bearer {token}")) .map_err(|_| AuthenticationError::Invalid)?; let mut request = Request::new(message); request.metadata_mut().insert("authorization", value); Ok(request) } /// Refuses a form POST that another site made the browser send. /// /// The session cookie is `SameSite=Strict`, so a cross-site post arrives /// without it and fails on authentication anyway; this turns that into a plain /// refusal instead of a redirect to the login page, and covers every /// state-changing endpoint the same way. pub(crate) fn reject_cross_site(headers: &HeaderMap) -> Option { headers .get("sec-fetch-site") .is_some_and(|value| value == "cross-site") .then(|| (StatusCode::FORBIDDEN, "Cross-site form submission rejected").into_response()) }