diff --git a/src/api/core/accounts.rs b/src/api/core/accounts.rs index 6f6e2f3d4e1..b83694d6f8e 100644 --- a/src/api/core/accounts.rs +++ b/src/api/core/accounts.rs @@ -963,10 +963,6 @@ 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 { @@ -974,14 +970,18 @@ async fn put_device_token(uuid: &str, data: JsonUpcase, headers: Head 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() { + /* only generate a new push_uuid if push is enabled, so we can call register_push_device later */ + if device.push_uuid.is_none() && CONFIG.push_enabled() { device.push_uuid = Some(uuid::Uuid::new_v4().to_string()); } 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}")); + + if CONFIG.push_enabled() { + if let Err(e) = register_push_device(device).await { + err!(format!("An error occurred while proceeding registration of a device: {e}")); + } } Ok(()) diff --git a/src/api/identity.rs b/src/api/identity.rs index e561161030a..02b2c671430 100644 --- a/src/api/identity.rs +++ b/src/api/identity.rs @@ -12,6 +12,7 @@ use crate::{ core::accounts::{PreloginData, RegisterData, _prelogin, _register}, core::log_user_event, core::two_factor::{duo, email, email::EmailTokenData, yubikey}, + push::register_missing_push_devices_for_user, ApiResult, EmptyResult, JsonResult, JsonUpcase, }, auth::{generate_organization_api_key_login_claims, ClientHeaders, ClientIp}, @@ -206,6 +207,9 @@ async fn _password_login( ) } + // Register possible missing push devices + register_missing_push_devices_for_user(&user.uuid, conn).await?; + let now = Utc::now().naive_utc(); if user.verified_at.is_none() && CONFIG.mail_enabled() && CONFIG.signups_verify() { diff --git a/src/api/push.rs b/src/api/push.rs index 3b0a573bee3..50cfda2e0e2 100644 --- a/src/api/push.rs +++ b/src/api/push.rs @@ -72,7 +72,48 @@ 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 { +pub async fn register_missing_push_devices_for_user(user_uuid: &str, conn: &mut crate::db::DbConn) -> EmptyResult { + if !CONFIG.push_enabled() { + return Ok(()); + } + + let devices = Device::find_unregistered_push_devices_by_user(user_uuid, conn).await; + + if devices.is_empty() { + debug!("No push device needs to be registered."); + return Ok(()); + } + + // Prevent registration of too many devices at once. + if devices.len() > 2 { + warn!( + "Account {user_uuid} has too many ({}) unregistered push devices. Skipping device registration.", + devices.len() + ); + return Ok(()); + } + + // find all mobile devices that have not been registered + for mut device in devices { + 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()); + // set a push token in case it's empty + if device.push_token.is_none() { + debug!("Skipping device registration because of an empty push token."); + continue; + } + if let Err(e) = device.save(conn).await { + err!(format!("An error occured while trying to save the device push token: {e}")); + } + if let Err(e) = register_push_device(device).await { + err!(format!("An error occured while proceeding registration of a device: {e}")); + } + } + Ok(()) +} + +pub async fn register_push_device(device: Device) -> EmptyResult { if !CONFIG.push_enabled() { return Ok(()); } @@ -80,7 +121,7 @@ pub async fn register_push_device(user_uuid: String, device: Device) -> EmptyRes //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, diff --git a/src/db/models/device.rs b/src/db/models/device.rs index b80b47a104c..1ae17c61cfc 100644 --- a/src/db/models/device.rs +++ b/src/db/models/device.rs @@ -203,6 +203,19 @@ impl Device { .from_db() }} } + + pub async fn find_unregistered_push_devices_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec { + db_run! { conn: { + devices::table + .filter(devices::user_uuid.eq(user_uuid)) + .filter(devices::atype.eq(DeviceType::Android as i32).or(devices::atype.eq(DeviceType::Ios as i32))) + .filter(devices::push_uuid.is_null()) + .load::(conn) + .expect("Error loading mobile devices") + .from_db() + }} + } + pub async fn find_push_devices_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec { db_run! { conn: { devices::table