state-res: Enforce integer power levels for room v10
According to MSC3667
This commit is contained in:
parent
2fcb7315b4
commit
e683d28afe
@ -21,6 +21,10 @@ use tracing::{debug, error, info, warn};
|
|||||||
|
|
||||||
use crate::{room_version::RoomVersion, Error, Event, PowerLevelsContentFields, Result};
|
use crate::{room_version::RoomVersion, Error, Event, PowerLevelsContentFields, Result};
|
||||||
|
|
||||||
|
mod int_power_levels;
|
||||||
|
|
||||||
|
use int_power_levels::IntRoomPowerLevelsEventContent;
|
||||||
|
|
||||||
// FIXME: field extracting could be bundled for `content`
|
// FIXME: field extracting could be bundled for `content`
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct GetMembership {
|
struct GetMembership {
|
||||||
@ -745,22 +749,26 @@ fn check_power_levels(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// - If any of the keys users_default, events_default, state_default, ban, redact, kick, or
|
||||||
|
// invite in content are present and not an integer, reject.
|
||||||
|
// - If either of the keys events or notifications in content are present and not a dictionary
|
||||||
|
// with values that are integers, reject.
|
||||||
|
// - If users key in content is not a dictionary with keys that are valid user IDs with values
|
||||||
|
// that are integers, reject.
|
||||||
|
let user_content: RoomPowerLevelsEventContent =
|
||||||
|
deserialize_power_levels(power_event.content().get(), room_version)?;
|
||||||
|
|
||||||
|
// Validation of users is done in Ruma, synapse for loops validating user_ids and integers here
|
||||||
|
info!("validation of power event finished");
|
||||||
|
|
||||||
let current_state = match previous_power_event {
|
let current_state = match previous_power_event {
|
||||||
Some(current_state) => current_state,
|
Some(current_state) => current_state,
|
||||||
// If there is no previous m.room.power_levels event in the room, allow
|
// If there is no previous m.room.power_levels event in the room, allow
|
||||||
None => return Some(true),
|
None => return Some(true),
|
||||||
};
|
};
|
||||||
|
|
||||||
// If users key in content is not a dictionary with keys that are valid user IDs
|
let current_content: RoomPowerLevelsEventContent =
|
||||||
// with values that are integers (or a string that is an integer), reject.
|
deserialize_power_levels(current_state.content().get(), room_version)?;
|
||||||
let user_content =
|
|
||||||
from_json_str::<RoomPowerLevelsEventContent>(power_event.content().get()).unwrap();
|
|
||||||
|
|
||||||
let current_content =
|
|
||||||
from_json_str::<RoomPowerLevelsEventContent>(current_state.content().get()).unwrap();
|
|
||||||
|
|
||||||
// Validation of users is done in Ruma, synapse for loops validating user_ids and integers here
|
|
||||||
info!("validation of power event finished");
|
|
||||||
|
|
||||||
let mut user_levels_to_check = BTreeSet::new();
|
let mut user_levels_to_check = BTreeSet::new();
|
||||||
let old_list = ¤t_content.users;
|
let old_list = ¤t_content.users;
|
||||||
@ -864,6 +872,31 @@ fn check_power_levels(
|
|||||||
Some(true)
|
Some(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn deserialize_power_levels(
|
||||||
|
content: &str,
|
||||||
|
room_version: &RoomVersion,
|
||||||
|
) -> Option<RoomPowerLevelsEventContent> {
|
||||||
|
if room_version.integer_power_levels {
|
||||||
|
match from_json_str::<IntRoomPowerLevelsEventContent>(content) {
|
||||||
|
Ok(content) => Some(content.into()),
|
||||||
|
Err(_) => {
|
||||||
|
error!("m.room.power_levels event is not valid with integer values");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match from_json_str(content) {
|
||||||
|
Ok(content) => Some(content),
|
||||||
|
Err(_) => {
|
||||||
|
error!(
|
||||||
|
"m.room.power_levels event is not valid with integer or string integer values"
|
||||||
|
);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn get_deserialize_levels(
|
fn get_deserialize_levels(
|
||||||
old: &serde_json::Value,
|
old: &serde_json::Value,
|
||||||
new: &serde_json::Value,
|
new: &serde_json::Value,
|
||||||
|
94
crates/ruma-state-res/src/event_auth/int_power_levels.rs
Normal file
94
crates/ruma-state-res/src/event_auth/int_power_levels.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use js_int::Int;
|
||||||
|
use ruma_common::{
|
||||||
|
events::{room::power_levels::RoomPowerLevelsEventContent, RoomEventType},
|
||||||
|
power_levels::{default_power_level, NotificationPowerLevels},
|
||||||
|
OwnedUserId,
|
||||||
|
};
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct IntRoomPowerLevelsEventContent {
|
||||||
|
#[serde(default = "default_power_level")]
|
||||||
|
pub ban: Int,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub events: BTreeMap<RoomEventType, Int>,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub events_default: Int,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub invite: Int,
|
||||||
|
|
||||||
|
#[serde(default = "default_power_level")]
|
||||||
|
pub kick: Int,
|
||||||
|
|
||||||
|
#[serde(default = "default_power_level")]
|
||||||
|
pub redact: Int,
|
||||||
|
|
||||||
|
#[serde(default = "default_power_level")]
|
||||||
|
pub state_default: Int,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub users: BTreeMap<OwnedUserId, Int>,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub users_default: Int,
|
||||||
|
|
||||||
|
#[serde(default)]
|
||||||
|
pub notifications: IntNotificationPowerLevels,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<IntRoomPowerLevelsEventContent> for RoomPowerLevelsEventContent {
|
||||||
|
fn from(int_pl: IntRoomPowerLevelsEventContent) -> Self {
|
||||||
|
let IntRoomPowerLevelsEventContent {
|
||||||
|
ban,
|
||||||
|
events,
|
||||||
|
events_default,
|
||||||
|
invite,
|
||||||
|
kick,
|
||||||
|
redact,
|
||||||
|
state_default,
|
||||||
|
users,
|
||||||
|
users_default,
|
||||||
|
notifications,
|
||||||
|
} = int_pl;
|
||||||
|
|
||||||
|
let mut pl = Self::new();
|
||||||
|
pl.ban = ban;
|
||||||
|
pl.events = events;
|
||||||
|
pl.events_default = events_default;
|
||||||
|
pl.invite = invite;
|
||||||
|
pl.kick = kick;
|
||||||
|
pl.redact = redact;
|
||||||
|
pl.state_default = state_default;
|
||||||
|
pl.users = users;
|
||||||
|
pl.users_default = users_default;
|
||||||
|
pl.notifications = notifications.into();
|
||||||
|
|
||||||
|
pl
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct IntNotificationPowerLevels {
|
||||||
|
#[serde(default = "default_power_level")]
|
||||||
|
pub room: Int,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for IntNotificationPowerLevels {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self { room: default_power_level() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<IntNotificationPowerLevels> for NotificationPowerLevels {
|
||||||
|
fn from(int_notif: IntNotificationPowerLevels) -> Self {
|
||||||
|
let mut notif = Self::new();
|
||||||
|
notif.room = int_notif.room;
|
||||||
|
|
||||||
|
notif
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user