delete pushers created with different access token on password change

This commit is contained in:
cy 2025-03-19 20:55:14 -04:00
parent 7bf92c8a37
commit 33c5afe050
No known key found for this signature in database
5 changed files with 53 additions and 14 deletions

View file

@ -4,7 +4,8 @@ use axum::extract::State;
use axum_client_ip::InsecureClientIp; use axum_client_ip::InsecureClientIp;
use conduwuit::{ use conduwuit::{
Err, Error, PduBuilder, Result, debug_info, err, error, info, is_equal_to, utils, Err, Error, PduBuilder, Result, debug_info, err, error, info, is_equal_to, utils,
utils::ReadyExt, warn, utils::{ReadyExt, stream::BroadbandExt},
warn,
}; };
use futures::{FutureExt, StreamExt}; use futures::{FutureExt, StreamExt};
use register::RegistrationKind; use register::RegistrationKind;
@ -627,6 +628,26 @@ pub(crate) async fn change_password_route(
.ready_filter(|id| *id != sender_device) .ready_filter(|id| *id != sender_device)
.for_each(|id| services.users.remove_device(sender_user, id)) .for_each(|id| services.users.remove_device(sender_user, id))
.await; .await;
// Remove all pushers except the ones associated with this session
services
.pusher
.get_pushkeys(sender_user)
.map(ToOwned::to_owned)
.broad_filter_map(|pushkey| async move {
services
.pusher
.get_pusher_device(&pushkey)
.await
.ok()
.filter(|pusher_device| pusher_device != sender_device)
.is_some()
.then_some(pushkey)
})
.for_each(|pushkey| async move {
services.pusher.delete_pusher(sender_user, &pushkey).await;
})
.await;
} }
info!("User {sender_user} changed their password."); info!("User {sender_user} changed their password.");

View file

@ -503,7 +503,7 @@ pub(crate) async fn set_pushers_route(
services services
.pusher .pusher
.set_pusher(sender_user, &body.action) .set_pusher(sender_user, body.sender_device(), &body.action)
.await?; .await?;
Ok(set_pusher::v3::Response::new()) Ok(set_pusher::v3::Response::new())

View file

@ -219,6 +219,10 @@ pub(super) static MAPS: &[Descriptor] = &[
name: "senderkey_pusher", name: "senderkey_pusher",
..descriptor::RANDOM_SMALL ..descriptor::RANDOM_SMALL
}, },
Descriptor {
name: "pushkey_deviceid",
..descriptor::RANDOM_SMALL
},
Descriptor { Descriptor {
name: "server_signingkeys", name: "server_signingkeys",
..descriptor::RANDOM ..descriptor::RANDOM

View file

@ -10,7 +10,7 @@ use database::{Deserialized, Ignore, Interfix, Json, Map};
use futures::{Stream, StreamExt}; use futures::{Stream, StreamExt};
use ipaddress::IPAddress; use ipaddress::IPAddress;
use ruma::{ use ruma::{
RoomId, UInt, UserId, DeviceId, OwnedDeviceId, RoomId, UInt, UserId,
api::{ api::{
IncomingResponse, MatrixVersion, OutgoingRequest, SendAccessToken, IncomingResponse, MatrixVersion, OutgoingRequest, SendAccessToken,
client::push::{Pusher, PusherKind, set_pusher}, client::push::{Pusher, PusherKind, set_pusher},
@ -48,6 +48,7 @@ struct Services {
struct Data { struct Data {
senderkey_pusher: Arc<Map>, senderkey_pusher: Arc<Map>,
pushkey_deviceid: Arc<Map>,
} }
impl crate::Service for Service { impl crate::Service for Service {
@ -55,6 +56,7 @@ impl crate::Service for Service {
Ok(Arc::new(Self { Ok(Arc::new(Self {
db: Data { db: Data {
senderkey_pusher: args.db["senderkey_pusher"].clone(), senderkey_pusher: args.db["senderkey_pusher"].clone(),
pushkey_deviceid: args.db["pushkey_deviceid"].clone(),
}, },
services: Services { services: Services {
globals: args.depend::<globals::Service>("globals"), globals: args.depend::<globals::Service>("globals"),
@ -75,6 +77,7 @@ impl Service {
pub async fn set_pusher( pub async fn set_pusher(
&self, &self,
sender: &UserId, sender: &UserId,
sender_device: &DeviceId,
pusher: &set_pusher::v3::PusherAction, pusher: &set_pusher::v3::PusherAction,
) -> Result { ) -> Result {
match pusher { match pusher {
@ -123,24 +126,35 @@ impl Service {
} }
} }
let key = (sender, data.pusher.ids.pushkey.as_str()); let pushkey = data.pusher.ids.pushkey.as_str();
let key = (sender, pushkey);
self.db.senderkey_pusher.put(key, Json(pusher)); self.db.senderkey_pusher.put(key, Json(pusher));
self.db.pushkey_deviceid.insert(pushkey, sender_device);
}, },
| set_pusher::v3::PusherAction::Delete(ids) => { | set_pusher::v3::PusherAction::Delete(ids) => {
let key = (sender, ids.pushkey.as_str()); self.delete_pusher(sender, ids.pushkey.as_str()).await;
self.db.senderkey_pusher.del(key);
self.services
.sending
.cleanup_events(None, Some(sender), Some(ids.pushkey.as_str()))
.await
.ok();
}, },
} }
Ok(()) Ok(())
} }
pub async fn delete_pusher(&self, sender: &UserId, pushkey: &str) {
let key = (sender, pushkey);
self.db.senderkey_pusher.del(key);
self.db.pushkey_deviceid.remove(pushkey);
self.services
.sending
.cleanup_events(None, Some(sender), Some(pushkey))
.await
.ok();
}
pub async fn get_pusher_device(&self, pushkey: &str) -> Result<OwnedDeviceId> {
self.db.pushkey_deviceid.get(pushkey).await.deserialized()
}
pub async fn get_pusher(&self, sender: &UserId, pushkey: &str) -> Result<Pusher> { pub async fn get_pusher(&self, sender: &UserId, pushkey: &str) -> Result<Pusher> {
let senderkey = (sender, pushkey); let senderkey = (sender, pushkey);
self.db self.db

View file

@ -69,8 +69,8 @@
{"Action":"pass","Test":"TestChangePassword/After_changing_password,_can_log_in_with_new_password"} {"Action":"pass","Test":"TestChangePassword/After_changing_password,_can_log_in_with_new_password"}
{"Action":"pass","Test":"TestChangePassword/After_changing_password,_different_sessions_can_optionally_be_kept"} {"Action":"pass","Test":"TestChangePassword/After_changing_password,_different_sessions_can_optionally_be_kept"}
{"Action":"pass","Test":"TestChangePassword/After_changing_password,_existing_session_still_works"} {"Action":"pass","Test":"TestChangePassword/After_changing_password,_existing_session_still_works"}
{"Action":"fail","Test":"TestChangePasswordPushers"} {"Action":"pass","Test":"TestChangePasswordPushers"}
{"Action":"fail","Test":"TestChangePasswordPushers/Pushers_created_with_a_different_access_token_are_deleted_on_password_change"} {"Action":"pass","Test":"TestChangePasswordPushers/Pushers_created_with_a_different_access_token_are_deleted_on_password_change"}
{"Action":"pass","Test":"TestChangePasswordPushers/Pushers_created_with_the_same_access_token_are_not_deleted_on_password_change"} {"Action":"pass","Test":"TestChangePasswordPushers/Pushers_created_with_the_same_access_token_are_not_deleted_on_password_change"}
{"Action":"fail","Test":"TestClientSpacesSummary"} {"Action":"fail","Test":"TestClientSpacesSummary"}
{"Action":"fail","Test":"TestClientSpacesSummary/max_depth"} {"Action":"fail","Test":"TestClientSpacesSummary/max_depth"}