feat(auth): add comprehensive authentication system with 2FA support
- Add new auth module with captcha, login, logout, register, and email verification endpoints - Implement two-factor authentication with TOTP enable, disable, verify, and backup codes regeneration - Create RSA public key endpoint for secure password encryption - Add user profile management with get current user and email retrieval - Integrate OpenAPI documentation for all authentication endpoints - Implement password reset functionality with email verification flow - Add comprehensive API response structures with proper error handling - Configure all auth routes under /api/v1/auth scope with proper tagging
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
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<String>,
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/api/v1/auth/2fa/backup-codes/regenerate",
|
||||
tag = "Auth / 2FA",
|
||||
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<Regenerate2FABackupCodesResponse>),
|
||||
(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<AppService>,
|
||||
session: Session,
|
||||
params: web::Json<Regenerate2FABackupCodesRequest>,
|
||||
) -> Result<HttpResponse, AppError> {
|
||||
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,
|
||||
})),
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user