use std::sync::Arc;
use axum::Json;
use axum::http::{HeaderMap, StatusCode};
use axum::response::{IntoResponse, Response};
use serde::Serialize;
use sqlx::{Pool, Sqlite};
use crate::auth::AuthContext;
use crate::moderation::policy::StrikePolicy;
#[derive(Clone)]
pub(super) struct PublicState {
pub pool: Pool<Sqlite>,
pub auth: Arc<AuthContext>,
pub strike_policy: Arc<StrikePolicy>,
pub service_did: String,
}
#[derive(Debug)]
pub(super) enum PublicError {
AuthenticationRequired,
SubjectNotFound,
Internal,
}
#[derive(Serialize)]
struct ErrorBody {
error: &'static str,
message: &'static str,
}
impl IntoResponse for PublicError {
fn into_response(self) -> Response {
let (status, body) = match self {
PublicError::AuthenticationRequired => (
StatusCode::UNAUTHORIZED,
ErrorBody {
error: "AuthenticationRequired",
message: "authentication required",
},
),
PublicError::SubjectNotFound => (
StatusCode::NOT_FOUND,
ErrorBody {
error: "SubjectNotFound",
message: "no actions recorded for caller",
},
),
PublicError::Internal => (
StatusCode::INTERNAL_SERVER_ERROR,
ErrorBody {
error: "InternalServerError",
message: "service temporarily unavailable",
},
),
};
(status, Json(body)).into_response()
}
}
pub(super) async fn verify_caller(
state: &PublicState,
headers: &HeaderMap,
lxm: &str,
) -> Result<String, PublicError> {
let token = headers
.get("authorization")
.and_then(|h| h.to_str().ok())
.and_then(|s| s.strip_prefix("Bearer "))
.ok_or(PublicError::AuthenticationRequired)?;
let caller = state
.auth
.verify_service_auth(token, lxm)
.await
.map_err(|_| PublicError::AuthenticationRequired)?;
Ok(caller.iss)
}