diff --git a/src/api/admin.rs b/src/api/admin.rs index 8cd33e7c..4df77748 100644 --- a/src/api/admin.rs +++ b/src/api/admin.rs @@ -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), }; diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs index 76a82055..91555a55 100644 --- a/src/api/core/accounts.rs +++ b/src/api/core/accounts.rs @@ -952,26 +952,33 @@ async fn post_device_token(uuid: &str, data: JsonUpcase, headers: Hea #[put("/devices/identifier//token", data = "")] async fn put_device_token(uuid: &str, data: JsonUpcase, 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(()) diff --git a/src/api/identity.rs b/src/api/identity.rs index 12becf6b..6f1155bb 100644 --- a/src/api/identity.rs +++ b/src/api/identity.rs @@ -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 diff --git a/src/api/push.rs b/src/api/push.rs index 7497b249..79966c94 100644 --- a/src/api/push.rs +++ b/src/api/push.rs @@ -76,24 +76,35 @@ async fn get_auth_push_token() -> ApiResult { 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) -> 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 diff --git a/src/db/models/device.rs b/src/db/models/device.rs index 00fe0ee6..de612e69 100644 --- a/src/db/models/device.rs +++ b/src/db/models/device.rs @@ -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 { db_run! { conn: { devices::table