mirror of
https://github.com/dani-garcia/vaultwarden.git
synced 2026-01-26 19:16:21 +02:00
fix email as 2fa with auth requests (#6736)
* fix email as 2fa with auth requests * increase expiry time of auth_requests to 15 minutes
This commit is contained in:
@@ -7,10 +7,10 @@ use crate::{
|
||||
core::{log_user_event, two_factor::_generate_recover_code},
|
||||
EmptyResult, JsonResult, PasswordOrOtpData,
|
||||
},
|
||||
auth::Headers,
|
||||
auth::{ClientHeaders, Headers},
|
||||
crypto,
|
||||
db::{
|
||||
models::{DeviceId, EventType, TwoFactor, TwoFactorType, User, UserId},
|
||||
models::{AuthRequest, AuthRequestId, DeviceId, EventType, TwoFactor, TwoFactorType, User, UserId},
|
||||
DbConn,
|
||||
},
|
||||
error::{Error, MapResult},
|
||||
@@ -30,12 +30,14 @@ struct SendEmailLoginData {
|
||||
email: Option<String>,
|
||||
#[serde(alias = "MasterPasswordHash")]
|
||||
master_password_hash: Option<String>,
|
||||
auth_request_id: Option<AuthRequestId>,
|
||||
auth_request_access_code: Option<String>,
|
||||
}
|
||||
|
||||
/// User is trying to login and wants to use email 2FA.
|
||||
/// Does not require Bearer token
|
||||
#[post("/two-factor/send-email-login", data = "<data>")] // JsonResult
|
||||
async fn send_email_login(data: Json<SendEmailLoginData>, conn: DbConn) -> EmptyResult {
|
||||
async fn send_email_login(data: Json<SendEmailLoginData>, client_headers: ClientHeaders, conn: DbConn) -> EmptyResult {
|
||||
let data: SendEmailLoginData = data.into_inner();
|
||||
|
||||
if !CONFIG._enable_email_2fa() {
|
||||
@@ -47,18 +49,41 @@ async fn send_email_login(data: Json<SendEmailLoginData>, conn: DbConn) -> Empty
|
||||
Some(email) if !email.is_empty() => Some(email),
|
||||
_ => None,
|
||||
};
|
||||
let user = if let Some(email) = email {
|
||||
let Some(master_password_hash) = &data.master_password_hash else {
|
||||
err!("No password hash has been submitted.")
|
||||
};
|
||||
let master_password_hash = match &data.master_password_hash {
|
||||
Some(password_hash) if !password_hash.is_empty() => Some(password_hash),
|
||||
_ => None,
|
||||
};
|
||||
let auth_request_id = match &data.auth_request_id {
|
||||
Some(auth_request_id) if !auth_request_id.is_empty() => Some(auth_request_id),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let user = if let Some(email) = email {
|
||||
let Some(user) = User::find_by_mail(email, &conn).await else {
|
||||
err!("Username or password is incorrect. Try again.")
|
||||
};
|
||||
|
||||
// Check password
|
||||
if !user.check_valid_password(master_password_hash) {
|
||||
err!("Username or password is incorrect. Try again.")
|
||||
if let Some(master_password_hash) = master_password_hash {
|
||||
// Check password
|
||||
if !user.check_valid_password(master_password_hash) {
|
||||
err!("Username or password is incorrect. Try again.")
|
||||
}
|
||||
} else if let Some(auth_request_id) = auth_request_id {
|
||||
let Some(auth_request) = AuthRequest::find_by_uuid(auth_request_id, &conn).await else {
|
||||
err!("AuthRequest doesn't exist", "User not found")
|
||||
};
|
||||
let Some(code) = &data.auth_request_access_code else {
|
||||
err!("no auth request access code")
|
||||
};
|
||||
|
||||
if auth_request.device_type != client_headers.device_type
|
||||
|| auth_request.request_ip != client_headers.ip.ip.to_string()
|
||||
|| !auth_request.check_access_code(code)
|
||||
{
|
||||
err!("AuthRequest doesn't exist", "Invalid device, IP or code")
|
||||
}
|
||||
} else {
|
||||
err!("No password hash has been submitted.")
|
||||
}
|
||||
|
||||
user
|
||||
|
||||
@@ -177,7 +177,9 @@ impl AuthRequest {
|
||||
}
|
||||
|
||||
pub async fn purge_expired_auth_requests(conn: &DbConn) {
|
||||
let expiry_time = Utc::now().naive_utc() - chrono::TimeDelta::try_minutes(5).unwrap(); //after 5 minutes, clients reject the request
|
||||
// delete auth requests older than 15 minutes which is functionally equivalent to upstream:
|
||||
// https://github.com/bitwarden/server/blob/f8ee2270409f7a13125cd414c450740af605a175/src/Sql/dbo/Auth/Stored%20Procedures/AuthRequest_DeleteIfExpired.sql
|
||||
let expiry_time = Utc::now().naive_utc() - chrono::TimeDelta::try_minutes(15).unwrap();
|
||||
for auth_request in Self::find_created_before(&expiry_time, conn).await {
|
||||
auth_request.delete(conn).await.ok();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user