mirror of
				https://github.com/dani-garcia/vaultwarden.git
				synced 2025-10-31 10:18:19 +02:00 
			
		
		
		
	web-client now request email 2fa (#5871)
This commit is contained in:
		| @@ -17,7 +17,7 @@ use crate::{ | ||||
|         push::register_push_device, | ||||
|         ApiResult, EmptyResult, JsonResult, | ||||
|     }, | ||||
|     auth::{generate_organization_api_key_login_claims, ClientHeaders, ClientIp}, | ||||
|     auth::{generate_organization_api_key_login_claims, ClientHeaders, ClientIp, ClientVersion}, | ||||
|     db::{models::*, DbConn}, | ||||
|     error::MapResult, | ||||
|     mail, util, CONFIG, | ||||
| @@ -28,7 +28,12 @@ pub fn routes() -> Vec<Route> { | ||||
| } | ||||
|  | ||||
| #[post("/connect/token", data = "<data>")] | ||||
| async fn login(data: Form<ConnectData>, client_header: ClientHeaders, mut conn: DbConn) -> JsonResult { | ||||
| async fn login( | ||||
|     data: Form<ConnectData>, | ||||
|     client_header: ClientHeaders, | ||||
|     client_version: Option<ClientVersion>, | ||||
|     mut conn: DbConn, | ||||
| ) -> JsonResult { | ||||
|     let data: ConnectData = data.into_inner(); | ||||
|  | ||||
|     let mut user_id: Option<UserId> = None; | ||||
| @@ -48,7 +53,7 @@ async fn login(data: Form<ConnectData>, client_header: ClientHeaders, mut conn: | ||||
|             _check_is_some(&data.device_name, "device_name cannot be blank")?; | ||||
|             _check_is_some(&data.device_type, "device_type cannot be blank")?; | ||||
|  | ||||
|             _password_login(data, &mut user_id, &mut conn, &client_header.ip).await | ||||
|             _password_login(data, &mut user_id, &mut conn, &client_header.ip, &client_version).await | ||||
|         } | ||||
|         "client_credentials" => { | ||||
|             _check_is_some(&data.client_id, "client_id cannot be blank")?; | ||||
| @@ -144,6 +149,7 @@ async fn _password_login( | ||||
|     user_id: &mut Option<UserId>, | ||||
|     conn: &mut DbConn, | ||||
|     ip: &ClientIp, | ||||
|     client_version: &Option<ClientVersion>, | ||||
| ) -> JsonResult { | ||||
|     // Validate scope | ||||
|     let scope = data.scope.as_ref().unwrap(); | ||||
| @@ -262,7 +268,7 @@ async fn _password_login( | ||||
|  | ||||
|     let (mut device, new_device) = get_device(&data, conn, &user).await; | ||||
|  | ||||
|     let twofactor_token = twofactor_auth(&user, &data, &mut device, ip, conn).await?; | ||||
|     let twofactor_token = twofactor_auth(&user, &data, &mut device, ip, client_version, conn).await?; | ||||
|  | ||||
|     if CONFIG.mail_enabled() && new_device { | ||||
|         if let Err(e) = mail::send_new_device_logged_in(&user.email, &ip.ip.to_string(), &now, &device).await { | ||||
| @@ -520,6 +526,7 @@ async fn twofactor_auth( | ||||
|     data: &ConnectData, | ||||
|     device: &mut Device, | ||||
|     ip: &ClientIp, | ||||
|     client_version: &Option<ClientVersion>, | ||||
|     conn: &mut DbConn, | ||||
| ) -> ApiResult<Option<String>> { | ||||
|     let twofactors = TwoFactor::find_by_user(&user.uuid, conn).await; | ||||
| @@ -538,7 +545,10 @@ async fn twofactor_auth( | ||||
|     let twofactor_code = match data.two_factor_token { | ||||
|         Some(ref code) => code, | ||||
|         None => { | ||||
|             err_json!(_json_err_twofactor(&twofactor_ids, &user.uuid, data, conn).await?, "2FA token not provided") | ||||
|             err_json!( | ||||
|                 _json_err_twofactor(&twofactor_ids, &user.uuid, data, client_version, conn).await?, | ||||
|                 "2FA token not provided" | ||||
|             ) | ||||
|         } | ||||
|     }; | ||||
|  | ||||
| @@ -585,7 +595,7 @@ async fn twofactor_auth( | ||||
|                 } | ||||
|                 _ => { | ||||
|                     err_json!( | ||||
|                         _json_err_twofactor(&twofactor_ids, &user.uuid, data, conn).await?, | ||||
|                         _json_err_twofactor(&twofactor_ids, &user.uuid, data, client_version, conn).await?, | ||||
|                         "2FA Remember token not provided" | ||||
|                     ) | ||||
|                 } | ||||
| @@ -617,6 +627,7 @@ async fn _json_err_twofactor( | ||||
|     providers: &[i32], | ||||
|     user_id: &UserId, | ||||
|     data: &ConnectData, | ||||
|     client_version: &Option<ClientVersion>, | ||||
|     conn: &mut DbConn, | ||||
| ) -> ApiResult<Value> { | ||||
|     let mut result = json!({ | ||||
| @@ -689,8 +700,16 @@ async fn _json_err_twofactor( | ||||
|                     err!("No twofactor email registered") | ||||
|                 }; | ||||
|  | ||||
|                 // Send email immediately if email is the only 2FA option | ||||
|                 if providers.len() == 1 { | ||||
|                 // Starting with version 2025.5.0 the client will call `/api/two-factor/send-email-login`. | ||||
|                 let disabled_send = if let Some(cv) = client_version { | ||||
|                     let ver_match = semver::VersionReq::parse(">=2025.5.0").unwrap(); | ||||
|                     ver_match.matches(&cv.0) | ||||
|                 } else { | ||||
|                     false | ||||
|                 }; | ||||
|  | ||||
|                 // Send email immediately if email is the only 2FA option. | ||||
|                 if providers.len() == 1 && !disabled_send { | ||||
|                     email::send_token(user_id, conn).await? | ||||
|                 } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user