Files
komp_ac/web/src/services/mod.rs
2026-08-04 17:20:58 +02:00

38 lines
1.3 KiB
Rust

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<T>(
headers: &HeaderMap,
message: T,
) -> Result<Request<T>, 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<Response> {
headers
.get("sec-fetch-site")
.is_some_and(|value| value == "cross-site")
.then(|| (StatusCode::FORBIDDEN, "Cross-site form submission rejected").into_response())
}