Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.

Commit e9e5fe2

Browse files
committed
implement MSC4165, removing own power levels on deactivation
Signed-off-by: strawberry <strawberry@puppygock.gay>
1 parent 17fd34e commit e9e5fe2

1 file changed

Lines changed: 68 additions & 8 deletions

File tree

src/api/client/account.rs

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::fmt::Write;
22

33
use axum::extract::State;
44
use axum_client_ip::InsecureClientIp;
5-
use conduit::{debug_info, error, info, utils, warn, Error, Result};
5+
use conduit::{debug_info, error, info, utils, warn, Error, PduBuilder, Result};
66
use register::RegistrationKind;
77
use ruma::{
88
api::client::{
@@ -15,9 +15,16 @@ use ruma::{
1515
error::ErrorKind,
1616
uiaa::{AuthFlow, AuthType, UiaaInfo},
1717
},
18-
events::{room::message::RoomMessageEventContent, GlobalAccountDataEventType},
18+
events::{
19+
room::{
20+
message::RoomMessageEventContent,
21+
power_levels::{RoomPowerLevels, RoomPowerLevelsEventContent},
22+
},
23+
GlobalAccountDataEventType, StateEventType, TimelineEventType,
24+
},
1925
push, OwnedRoomId, UserId,
2026
};
27+
use serde_json::value::to_raw_value;
2128
use service::Services;
2229

2330
use super::{join_room_by_id_helper, DEVICE_ID_LENGTH, SESSION_ID_LENGTH, TOKEN_LENGTH};
@@ -647,26 +654,79 @@ pub(crate) async fn check_registration_token_validity(
647654
/// - Removing display name
648655
/// - Removing avatar URL and blurhash
649656
/// - Removing all profile data
650-
/// - Leaving all rooms
657+
/// - Leaving all rooms (and forgets all of them)
651658
pub async fn full_user_deactivate(
652659
services: &Services, user_id: &UserId, all_joined_rooms: Vec<OwnedRoomId>,
653660
) -> Result<()> {
654661
services.users.deactivate_account(user_id)?;
655662

656663
super::update_displayname(services, user_id, None, all_joined_rooms.clone()).await?;
657-
super::update_avatar_url(services, user_id, None, None, all_joined_rooms).await?;
658-
super::leave_all_rooms(services, user_id).await;
664+
super::update_avatar_url(services, user_id, None, None, all_joined_rooms.clone()).await?;
659665

660666
let all_profile_keys = services
661667
.users
662668
.all_profile_keys(user_id)
663669
.filter_map(Result::ok);
664670

665671
for (profile_key, _profile_value) in all_profile_keys {
666-
services
667-
.users
668-
.set_profile_key(user_id, &profile_key, None)?;
672+
if let Err(e) = services.users.set_profile_key(user_id, &profile_key, None) {
673+
warn!("Failed removing {user_id} profile key {profile_key}: {e}");
674+
}
675+
}
676+
677+
for room_id in all_joined_rooms {
678+
let state_lock = services.rooms.state.mutex.lock(&room_id).await;
679+
680+
let room_power_levels = services
681+
.rooms
682+
.state_accessor
683+
.room_state_get(&room_id, &StateEventType::RoomPowerLevels, "")?
684+
.as_ref()
685+
.and_then(|event| serde_json::from_str(event.content.get()).ok()?)
686+
.and_then(|content: RoomPowerLevelsEventContent| content.into());
687+
688+
let user_can_demote_self = room_power_levels
689+
.as_ref()
690+
.is_some_and(|power_levels_content| {
691+
RoomPowerLevels::from(power_levels_content.clone()).user_can_change_user_power_level(user_id, user_id)
692+
}) || services
693+
.rooms
694+
.state_accessor
695+
.room_state_get(&room_id, &StateEventType::RoomCreate, "")?
696+
.as_ref()
697+
.is_some_and(|event| event.sender == user_id);
698+
699+
if user_can_demote_self {
700+
let mut power_levels_content = room_power_levels.unwrap_or_default();
701+
power_levels_content.users.remove(user_id);
702+
703+
// ignore errors so deactivation doesn't fail
704+
if let Err(e) = services
705+
.rooms
706+
.timeline
707+
.build_and_append_pdu(
708+
PduBuilder {
709+
event_type: TimelineEventType::RoomPowerLevels,
710+
content: to_raw_value(&power_levels_content).expect("event is valid, we just created it"),
711+
unsigned: None,
712+
state_key: Some(String::new()),
713+
redacts: None,
714+
timestamp: None,
715+
},
716+
user_id,
717+
&room_id,
718+
&state_lock,
719+
)
720+
.await
721+
{
722+
warn!(%room_id, %user_id, "Failed to demote user's own power level: {e}");
723+
} else {
724+
info!("Demoted {user_id} in {room_id} as part of account deactivation");
725+
}
726+
}
669727
}
670728

729+
super::leave_all_rooms(services, user_id).await;
730+
671731
Ok(())
672732
}

0 commit comments

Comments
 (0)