use actix_web::{HttpResponse, web}; use serde::{Deserialize, Serialize}; use crate::api::response::{ApiErrorResponse, ApiResponse}; use crate::error::AppError; use crate::service::AppService; use crate::session::Session; #[derive(Debug, Clone, Deserialize, Serialize, utoipa::ToSchema)] pub struct Regenerate2FABackupCodesRequest { /// Current account password encrypted with the session RSA public key. pub password: String, } #[derive(Debug, Clone, Serialize, utoipa::ToSchema)] pub struct Regenerate2FABackupCodesResponse { /// Newly generated one-time backup codes. Old backup codes become invalid. pub backup_codes: Vec, } #[utoipa::path( post, path = "/api/v1/auth/2fa/backup-codes/regenerate", tag = "Auth", operation_id = "authRegenerateTwoFactorBackupCodes", summary = "Regenerate 2FA backup codes", description = "After verifying the current password, generate a new set of backup codes for a user with 2FA enabled and replace the old backup codes. password must be encrypted with the current session RSA public key. Backup codes are returned in plaintext only once in this response; clients must prompt users to store them securely.", request_body( content = Regenerate2FABackupCodesRequest, description = "The current account password encrypted with RSA.", content_type = "application/json" ), responses( (status = 200, description = "Backup codes have been regenerated; old backup codes are immediately invalidated.", body = ApiResponse), (status = 400, description = "2FA is not enabled, the password is incorrect, or RSA decryption failed.", body = ApiErrorResponse), (status = 401, description = "The current session is not authenticated.", body = ApiErrorResponse), (status = 500, description = "Database write or backup code hashing failed.", body = ApiErrorResponse) ) )] pub async fn handle( service: web::Data, session: Session, params: web::Json, ) -> Result { let backup_codes = service .auth .auth_2fa_regenerate_backup_codes(&session, params.into_inner().password) .await?; Ok( HttpResponse::Ok().json(ApiResponse::new(Regenerate2FABackupCodesResponse { backup_codes, })), ) }