use axum::extract::{Extension, State}; use crate::error::AuthError; use crate::features::AuthService; use crate::pow::Challenge; use export::data::AppResponseData; /// A freshly issued, client-bound PoW challenge for the caller to solve. #[derive(Debug, Clone, serde::Serialize, utoipa::ToSchema)] pub struct PowChallengeResp { /// The signed challenge to solve (echoed back verbatim in `PowProof`). #[schema(value_type = String)] pub challenge: Challenge, /// How long the challenge remains valid, in seconds. pub ttl_seconds: u64, } #[utoipa::path( get, path = "/auth/pow/challenge", tag = "auth", responses( (status = 200, description = "A fresh PoW challenge bound to this client.", body = AppResponseData), (status = 400, description = "PoW not configured.", body = super::openapi::ErrorBody), (status = 429, description = "Rate limited.", body = super::openapi::ErrorBody), ), )] pub(crate) async fn handler( State(svc): State, Extension(cid): Extension, ) -> Result, AuthError> { let (challenge, ttl) = svc.pow.issue_challenge_bound(&cid.0).await?; Ok(AppResponseData::ok(PowChallengeResp { challenge, ttl_seconds: ttl, })) }