use crate::AuthService; use crate::errors::AuthResult; use crate::events::{Labels, label}; use crate::session::Session; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; pub const SESSION_CHALLENGE: &str = "challenge"; #[derive(Clone, Debug, Deserialize, Serialize, ToSchema)] pub struct ChallengeResponse { pub context: String, pub difficulty: u32, pub issued_at: u64, pub expires_at: u64, } #[derive(Clone, Debug, Deserialize, Serialize, ToSchema)] pub struct PowProofRequest { pub nonce: u64, pub payload: Vec, } impl AuthService { #[tracing::instrument(skip_all, fields(request_id = %request_id, client_ip = ?session.client_ip().ok().flatten()))] pub async fn challenge( &self, session: Session, request_id: String, ) -> AuthResult { let response = crate::pow::store::issue(&session, self.pow()).await?; self.emit_labeled( label::AUTH_CHALLENGE_CREATE, Labels::new() .with_opt(label::USER_ID, session.user_id().ok().flatten()) .with(label::REQUEST_ID, &request_id), &response, Some(request_id.as_str()), ) .await; Ok(response) } #[tracing::instrument(skip_all, fields(request_id = %request_id, client_ip = ?session.client_ip().ok().flatten()))] pub async fn challenge_verify_pow( &self, session: Session, proof: &PowProofRequest, expected_payload: &[u8], request_id: String, ) -> AuthResult<()> { crate::pow::store::verify(&session, self.cache(), proof, expected_payload).await?; self.emit_labeled( label::AUTH_CHALLENGE_USED, Labels::new() .with_opt(label::USER_ID, session.user_id().ok().flatten()) .with(label::REQUEST_ID, &request_id), serde_json::json!({ "user_id": session.user_id().ok().flatten(), }), Some(request_id.as_str()), ) .await; Ok(()) } }