Spiegel von
https://github.com/dani-garcia/vaultwarden.git
synchronisiert 2024-11-22 05:10:29 +01: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)
Dieser Commit ist enthalten in:
Ursprung
4b9384cb2b
Commit
3b283c289e
5 geänderte Dateien mit 60 neuen und 21 gelöschten Zeilen
|
@ -413,7 +413,7 @@ async fn deauth_user(uuid: &str, _token: AdminToken, mut conn: DbConn, nt: Notif
|
||||||
|
|
||||||
if CONFIG.push_enabled() {
|
if CONFIG.push_enabled() {
|
||||||
for device in Device::find_push_devices_by_user(&user.uuid, &mut conn).await {
|
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,
|
Ok(r) => r,
|
||||||
Err(e) => error!("Unable to unregister devices from Bitwarden server: {}", e),
|
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>")]
|
#[put("/devices/identifier/<uuid>/token", data = "<data>")]
|
||||||
async fn put_device_token(uuid: &str, data: JsonUpcase<PushToken>, headers: Headers, mut conn: DbConn) -> EmptyResult {
|
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 data = data.into_inner().data;
|
||||||
let token = data.PushToken;
|
let token = data.PushToken;
|
||||||
|
|
||||||
let mut device = match Device::find_by_uuid_and_user(&headers.device.uuid, &headers.user.uuid, &mut conn).await {
|
let mut device = match Device::find_by_uuid_and_user(&headers.device.uuid, &headers.user.uuid, &mut conn).await {
|
||||||
Some(device) => device,
|
Some(device) => device,
|
||||||
None => err!(format!("Error: device {uuid} should be present before a token can be assigned")),
|
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() {
|
// if the device already has been registered
|
||||||
device.push_uuid = Some(uuid::Uuid::new_v4().to_string());
|
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 {
|
if let Err(e) = device.save(&mut conn).await {
|
||||||
err!(format!("An error occurred while trying to save the device push token: {e}"));
|
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(())
|
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 {
|
if let Some(device) = Device::find_by_uuid(uuid, &mut conn).await {
|
||||||
Device::clear_push_token_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(())
|
Ok(())
|
||||||
|
|
|
@ -14,6 +14,7 @@ use crate::{
|
||||||
log_user_event,
|
log_user_event,
|
||||||
two_factor::{authenticator, duo, email, enforce_2fa_policy, webauthn, yubikey},
|
two_factor::{authenticator, duo, email, enforce_2fa_policy, webauthn, yubikey},
|
||||||
},
|
},
|
||||||
|
push::register_push_device,
|
||||||
ApiResult, EmptyResult, JsonResult, JsonUpcase,
|
ApiResult, EmptyResult, JsonResult, JsonUpcase,
|
||||||
},
|
},
|
||||||
auth::{generate_organization_api_key_login_claims, ClientHeaders, ClientIp},
|
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
|
// Common
|
||||||
// ---
|
// ---
|
||||||
// Disabled this variable, it was used to generate the JWT
|
// 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())
|
Ok(push_token.access_token.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn register_push_device(user_uuid: String, device: Device) -> EmptyResult {
|
pub async fn register_push_device(device: &mut Device, conn: &mut crate::db::DbConn) -> EmptyResult {
|
||||||
if !CONFIG.push_enabled() {
|
if !CONFIG.push_enabled() || !device.is_push_device() || device.is_registered() {
|
||||||
return Ok(());
|
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 :
|
//Needed to register a device for push to bitwarden :
|
||||||
let data = json!({
|
let data = json!({
|
||||||
"userId": user_uuid,
|
"userId": device.user_uuid,
|
||||||
"deviceId": device.push_uuid,
|
"deviceId": device.push_uuid,
|
||||||
"identifier": device.uuid,
|
"identifier": device.uuid,
|
||||||
"type": device.atype,
|
"type": device.atype,
|
||||||
"pushToken": device.push_token
|
"pushToken": device.push_token
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let auth_push_token = get_auth_push_token().await?;
|
||||||
let auth_header = format!("Bearer {}", &auth_push_token);
|
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")
|
.post(CONFIG.push_relay_uri() + "/push/register")
|
||||||
.header(CONTENT_TYPE, "application/json")
|
.header(CONTENT_TYPE, "application/json")
|
||||||
.header(ACCEPT, "application/json")
|
.header(ACCEPT, "application/json")
|
||||||
|
@ -101,12 +112,20 @@ pub async fn register_push_device(user_uuid: String, device: Device) -> EmptyRes
|
||||||
.json(&data)
|
.json(&data)
|
||||||
.send()
|
.send()
|
||||||
.await?
|
.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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn unregister_push_device(uuid: String) -> EmptyResult {
|
pub async fn unregister_push_device(push_uuid: Option<String>) -> EmptyResult {
|
||||||
if !CONFIG.push_enabled() {
|
if !CONFIG.push_enabled() || push_uuid.is_none() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
let auth_push_token = get_auth_push_token().await?;
|
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);
|
let auth_header = format!("Bearer {}", &auth_push_token);
|
||||||
|
|
||||||
match get_reqwest_client()
|
match get_reqwest_client()
|
||||||
.delete(CONFIG.push_relay_uri() + "/push/" + &uuid)
|
.delete(CONFIG.push_relay_uri() + "/push/" + &push_uuid.unwrap())
|
||||||
.header(AUTHORIZATION, auth_header)
|
.header(AUTHORIZATION, auth_header)
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -113,6 +113,14 @@ impl Device {
|
||||||
|
|
||||||
(encode_jwt(&claims), DEFAULT_VALIDITY.num_seconds())
|
(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;
|
use crate::db::DbConn;
|
||||||
|
@ -210,6 +218,7 @@ impl Device {
|
||||||
.from_db()
|
.from_db()
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn find_push_devices_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> {
|
pub async fn find_push_devices_by_user(user_uuid: &str, conn: &mut DbConn) -> Vec<Self> {
|
||||||
db_run! { conn: {
|
db_run! { conn: {
|
||||||
devices::table
|
devices::table
|
||||||
|
|
Laden …
In neuem Issue referenzieren