Skip to content

Commit

Permalink
add admin command to force demote a local user from a room
Browse files Browse the repository at this point in the history
Signed-off-by: strawberry <strawberry@puppygock.gay>
  • Loading branch information
girlbossceo committed Sep 15, 2024
1 parent a65dd6d commit 895b178
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 2 deletions.
76 changes: 74 additions & 2 deletions src/admin/user/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ use api::client::{join_room_by_id_helper, leave_all_rooms, leave_room, update_av
use conduit::{error, info, utils, warn, PduBuilder, Result};
use ruma::{
events::{
room::{message::RoomMessageEventContent, redaction::RoomRedactionEventContent},
room::{
message::RoomMessageEventContent,
power_levels::{RoomPowerLevels, RoomPowerLevelsEventContent},
redaction::RoomRedactionEventContent,
},
tag::{TagEvent, TagEventContent, TagInfo},
RoomAccountDataEventType, TimelineEventType,
RoomAccountDataEventType, StateEventType, TimelineEventType,
},
EventId, OwnedRoomId, OwnedRoomOrAliasId, OwnedUserId, RoomId,
};
Expand Down Expand Up @@ -387,6 +391,74 @@ pub(super) async fn force_leave_room(
)))
}

#[admin_command]
pub(super) async fn force_demote(
&self, user_id: String, room_id: OwnedRoomOrAliasId,
) -> Result<RoomMessageEventContent> {
let user_id = parse_local_user_id(self.services, &user_id)?;
let room_id = self.services.rooms.alias.resolve(&room_id).await?;

assert!(
self.services.globals.user_is_local(&user_id),
"Parsed user_id must be a local user"
);

let state_lock = self.services.rooms.state.mutex.lock(&room_id).await;

let room_power_levels = self
.services
.rooms
.state_accessor
.room_state_get(&room_id, &StateEventType::RoomPowerLevels, "")?
.as_ref()
.and_then(|event| serde_json::from_str(event.content.get()).ok()?)
.and_then(|content: RoomPowerLevelsEventContent| content.into());

let user_can_demote_self = room_power_levels
.as_ref()
.is_some_and(|power_levels_content| {
RoomPowerLevels::from(power_levels_content.clone()).user_can_change_user_power_level(&user_id, &user_id)
}) || self
.services
.rooms
.state_accessor
.room_state_get(&room_id, &StateEventType::RoomCreate, "")?
.as_ref()
.is_some_and(|event| event.sender == user_id);

if !user_can_demote_self {
return Ok(RoomMessageEventContent::notice_markdown(
"User is not allowed to modify their own power levels in the room.",
));
}

let mut power_levels_content = room_power_levels.unwrap_or_default();
power_levels_content.users.remove(&user_id);

let event_id = self
.services
.rooms
.timeline
.build_and_append_pdu(
PduBuilder {
event_type: TimelineEventType::RoomPowerLevels,
content: to_raw_value(&power_levels_content).expect("event is valid, we just created it"),
unsigned: None,
state_key: Some(String::new()),
redacts: None,
timestamp: None,
},
&user_id,
&room_id,
&state_lock,
)
.await?;

Ok(RoomMessageEventContent::notice_markdown(format!(
"User {user_id} demoted themselves to the room default power level in {room_id} - {event_id}"
)))
}

#[admin_command]
pub(super) async fn make_user_admin(&self, user_id: String) -> Result<RoomMessageEventContent> {
let user_id = parse_local_user_id(self.services, &user_id)?;
Expand Down
7 changes: 7 additions & 0 deletions src/admin/user/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ pub(super) enum UserCommand {
room_id: OwnedRoomOrAliasId,
},

/// - Forces the specified user to drop their power levels to the room
/// default, if their permissions allow and the auth check permits
ForceDemote {
user_id: String,
room_id: OwnedRoomOrAliasId,
},

/// - Grant server-admin privileges to a user.
MakeUserAdmin {
user_id: String,
Expand Down

0 comments on commit 895b178

Please sign in to comment.