mirror of
				https://github.com/dani-garcia/vaultwarden.git
				synced 2025-10-30 17:58:19 +02:00 
			
		
		
		
	register missing push devices at login (#3792)
save the push token of new device even if push notifications are not
enabled and provide a way to register the push device at login
unregister device if there already is a push token saved unless the
new token has already been registered.
also the `unregister_push_device` function used the wrong argument
cf. 08d380900b/src/Core/Services/Implementations/RelayPushRegistrationService.cs (L43)
			
			
This commit is contained in:
		| @@ -413,7 +413,7 @@ async fn deauth_user(uuid: &str, _token: AdminToken, mut conn: DbConn, nt: Notif | ||||
|  | ||||
|     if CONFIG.push_enabled() { | ||||
|         for device in Device::find_push_devices_by_user(&user.uuid, &mut conn).await { | ||||
|             match unregister_push_device(device.uuid).await { | ||||
|             match unregister_push_device(device.push_uuid).await { | ||||
|                 Ok(r) => r, | ||||
|                 Err(e) => error!("Unable to unregister devices from Bitwarden server: {}", e), | ||||
|             }; | ||||
|   | ||||
| @@ -952,26 +952,33 @@ async fn post_device_token(uuid: &str, data: JsonUpcase<PushToken>, headers: Hea | ||||
|  | ||||
| #[put("/devices/identifier/<uuid>/token", data = "<data>")] | ||||
| async fn put_device_token(uuid: &str, data: JsonUpcase<PushToken>, headers: Headers, mut conn: DbConn) -> EmptyResult { | ||||
|     if !CONFIG.push_enabled() { | ||||
|         return Ok(()); | ||||
|     } | ||||
|  | ||||
|     let data = data.into_inner().data; | ||||
|     let token = data.PushToken; | ||||
|  | ||||
|     let mut device = match Device::find_by_uuid_and_user(&headers.device.uuid, &headers.user.uuid, &mut conn).await { | ||||
|         Some(device) => device, | ||||
|         None => err!(format!("Error: device {uuid} should be present before a token can be assigned")), | ||||
|     }; | ||||
|     device.push_token = Some(token); | ||||
|     if device.push_uuid.is_none() { | ||||
|         device.push_uuid = Some(uuid::Uuid::new_v4().to_string()); | ||||
|  | ||||
|     // if the device already has been registered | ||||
|     if device.is_registered() { | ||||
|         // check if the new token is the same as the registered token | ||||
|         if device.push_token.is_some() && device.push_token.unwrap() == token.clone() { | ||||
|             debug!("Device {} is already registered and token is the same", uuid); | ||||
|             return Ok(()); | ||||
|         } else { | ||||
|             // Try to unregister already registered device | ||||
|             let _ = unregister_push_device(device.push_uuid).await; | ||||
|         } | ||||
|         // clear the push_uuid | ||||
|         device.push_uuid = None; | ||||
|     } | ||||
|     device.push_token = Some(token); | ||||
|     if let Err(e) = device.save(&mut conn).await { | ||||
|         err!(format!("An error occurred while trying to save the device push token: {e}")); | ||||
|     } | ||||
|     if let Err(e) = register_push_device(headers.user.uuid, device).await { | ||||
|         err!(format!("An error occurred while proceeding registration of a device: {e}")); | ||||
|     } | ||||
|  | ||||
|     register_push_device(&mut device, &mut conn).await?; | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
| @@ -988,7 +995,7 @@ async fn put_clear_device_token(uuid: &str, mut conn: DbConn) -> EmptyResult { | ||||
|  | ||||
|     if let Some(device) = Device::find_by_uuid(uuid, &mut conn).await { | ||||
|         Device::clear_push_token_by_uuid(uuid, &mut conn).await?; | ||||
|         unregister_push_device(device.uuid).await?; | ||||
|         unregister_push_device(device.push_uuid).await?; | ||||
|     } | ||||
|  | ||||
|     Ok(()) | ||||
|   | ||||
| @@ -14,6 +14,7 @@ use crate::{ | ||||
|             log_user_event, | ||||
|             two_factor::{authenticator, duo, email, enforce_2fa_policy, webauthn, yubikey}, | ||||
|         }, | ||||
|         push::register_push_device, | ||||
|         ApiResult, EmptyResult, JsonResult, JsonUpcase, | ||||
|     }, | ||||
|     auth::{generate_organization_api_key_login_claims, ClientHeaders, ClientIp}, | ||||
| @@ -266,6 +267,9 @@ async fn _password_login( | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // register push device | ||||
|     register_push_device(&mut device, conn).await?; | ||||
|  | ||||
|     // Common | ||||
|     // --- | ||||
|     // Disabled this variable, it was used to generate the JWT | ||||
|   | ||||
| @@ -76,24 +76,35 @@ async fn get_auth_push_token() -> ApiResult<String> { | ||||
|     Ok(push_token.access_token.clone()) | ||||
| } | ||||
|  | ||||
| pub async fn register_push_device(user_uuid: String, device: Device) -> EmptyResult { | ||||
|     if !CONFIG.push_enabled() { | ||||
| pub async fn register_push_device(device: &mut Device, conn: &mut crate::db::DbConn) -> EmptyResult { | ||||
|     if !CONFIG.push_enabled() || !device.is_push_device() || device.is_registered() { | ||||
|         return Ok(()); | ||||
|     } | ||||
|     let auth_push_token = get_auth_push_token().await?; | ||||
|  | ||||
|     if device.push_token.is_none() { | ||||
|         warn!("Skipping the registration of the device {} because the push_token field is empty.", device.uuid); | ||||
|         warn!("To get rid of this message you need to clear the app data and reconnect the device."); | ||||
|         return Ok(()); | ||||
|     } | ||||
|  | ||||
|     debug!("Registering Device {}", device.uuid); | ||||
|  | ||||
|     // generate a random push_uuid so we know the device is registered | ||||
|     device.push_uuid = Some(uuid::Uuid::new_v4().to_string()); | ||||
|  | ||||
|     //Needed to register a device for push to bitwarden : | ||||
|     let data = json!({ | ||||
|         "userId": user_uuid, | ||||
|         "userId": device.user_uuid, | ||||
|         "deviceId": device.push_uuid, | ||||
|         "identifier": device.uuid, | ||||
|         "type": device.atype, | ||||
|         "pushToken": device.push_token | ||||
|     }); | ||||
|  | ||||
|     let auth_push_token = get_auth_push_token().await?; | ||||
|     let auth_header = format!("Bearer {}", &auth_push_token); | ||||
|  | ||||
|     get_reqwest_client() | ||||
|     if let Err(e) = get_reqwest_client() | ||||
|         .post(CONFIG.push_relay_uri() + "/push/register") | ||||
|         .header(CONTENT_TYPE, "application/json") | ||||
|         .header(ACCEPT, "application/json") | ||||
| @@ -101,12 +112,20 @@ pub async fn register_push_device(user_uuid: String, device: Device) -> EmptyRes | ||||
|         .json(&data) | ||||
|         .send() | ||||
|         .await? | ||||
|         .error_for_status()?; | ||||
|         .error_for_status() | ||||
|     { | ||||
|         err!(format!("An error occured while proceeding registration of a device: {e}")); | ||||
|     } | ||||
|  | ||||
|     if let Err(e) = device.save(conn).await { | ||||
|         err!(format!("An error occured while trying to save the (registered) device push uuid: {e}")); | ||||
|     } | ||||
|  | ||||
|     Ok(()) | ||||
| } | ||||
|  | ||||
| pub async fn unregister_push_device(uuid: String) -> EmptyResult { | ||||
|     if !CONFIG.push_enabled() { | ||||
| pub async fn unregister_push_device(push_uuid: Option<String>) -> EmptyResult { | ||||
|     if !CONFIG.push_enabled() || push_uuid.is_none() { | ||||
|         return Ok(()); | ||||
|     } | ||||
|     let auth_push_token = get_auth_push_token().await?; | ||||
| @@ -114,7 +133,7 @@ pub async fn unregister_push_device(uuid: String) -> EmptyResult { | ||||
|     let auth_header = format!("Bearer {}", &auth_push_token); | ||||
|  | ||||
|     match get_reqwest_client() | ||||
|         .delete(CONFIG.push_relay_uri() + "/push/" + &uuid) | ||||
|         .delete(CONFIG.push_relay_uri() + "/push/" + &push_uuid.unwrap()) | ||||
|         .header(AUTHORIZATION, auth_header) | ||||
|         .send() | ||||
|         .await | ||||
|   | ||||
| @@ -113,6 +113,14 @@ impl Device { | ||||
|  | ||||
|         (encode_jwt(&claims), DEFAULT_VALIDITY.num_seconds()) | ||||
|     } | ||||
|  | ||||
|     pub fn is_push_device(&self) -> bool { | ||||
|         matches!(DeviceType::from_i32(self.atype), DeviceType::Android | DeviceType::Ios) | ||||
|     } | ||||
|  | ||||
|     pub fn is_registered(&self) -> bool { | ||||
|         self.push_uuid.is_some() | ||||
|     } | ||||
| } | ||||
|  | ||||
| use crate::db::DbConn; | ||||
| @@ -210,6 +218,7 @@ impl Device { | ||||
|                 .from_db() | ||||
|         }} | ||||
|     } | ||||
|  | ||||
|     pub async fn find_push_devices_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> { | ||||
|         db_run! { conn: { | ||||
|             devices::table | ||||
|   | ||||
		Reference in New Issue
	
	Block a user