use actix_web::{HttpResponse, web}; use crate::api::response::{ApiErrorResponse, ApiResponse}; use crate::error::AppError; use crate::service::AppService; use crate::service::auth::captcha::{CaptchaQuery, CaptchaResponse}; use crate::session::Session; #[utoipa::path( get, path = "/api/v1/auth/captcha", tag = "Auth", operation_id = "authGetCaptcha", summary = "Get captcha image", description = "Generate a one-time captcha image and store the plaintext captcha in the current session. Captchas are used for sensitive entry points such as login and sending registration email codes. Set rsa=true to return the current session RSA public key at the same time and reduce frontend initialization requests. The captcha is consumed after either successful or failed validation, so clients must fetch a new one after failure.", params( ("w" = u32, Query, description = "Captcha image width; allowed range is 80..=400.", example = 160), ("h" = u32, Query, description = "Captcha image height; allowed range is 30..=200.", example = 64), ("dark" = bool, Query, description = "Whether to generate a dark-mode captcha.", example = false), ("rsa" = bool, Query, description = "Whether to include the RSA public key in the response.", example = true) ), responses( (status = 200, description = "Captcha generated successfully. The base64 field is image data that can be used directly as img.src.", body = ApiResponse), (status = 400, description = "Invalid captcha size.", body = ApiErrorResponse), (status = 500, description = "Session write failed or RSA initialization failed.", body = ApiErrorResponse) ) )] pub async fn handle( service: web::Data, session: Session, query: web::Query, ) -> Result { let data = service .auth .auth_captcha(&session, query.into_inner()) .await?; Ok(HttpResponse::Ok().json(ApiResponse::new(data))) }