Room topic reset test fails

This commit is contained in:
Devin R 2020-07-23 01:12:25 -04:00
parent 5842ddf36e
commit a0db51b3bd
4 changed files with 134 additions and 59 deletions

View File

@ -180,7 +180,14 @@ pub fn auth_check(
}
if event.kind() == EventType::RoomPowerLevels {
if !check_power_levels(room_version, event, &auth_events)? {
tracing::info!("starting m.room.power_levels check");
if let Some(required_pwr_lvl) = check_power_levels(room_version, event, &auth_events) {
if !required_pwr_lvl {
tracing::warn!("power level was not allowed");
return Some(false);
}
} else {
tracing::warn!("power level was not allowed");
return Some(false);
}
tracing::info!("power levels event allowed");
@ -372,6 +379,13 @@ fn can_send_event(event: &StateEvent, auth_events: &StateMap<StateEvent>) -> Opt
let send_level = get_send_level(event.kind(), event.state_key(), ple);
let user_level = get_user_power_level(event.sender(), auth_events);
tracing::debug!(
"{} snd {} usr {}",
event.event_id().unwrap().to_string(),
send_level,
user_level
);
if user_level < send_level {
return Some(false);
}
@ -394,16 +408,17 @@ fn check_power_levels(
) -> Option<bool> {
use itertools::Itertools;
let key = (power_event.kind(), power_event.state_key()?);
let key = (power_event.kind(), power_event.state_key().unwrap());
let current_state = auth_events.get(&key)?;
let user_content = power_event
.deserialize_content::<room::power_levels::PowerLevelsEventContent>()
.ok()?;
.unwrap();
let current_content = current_state
.deserialize_content::<room::power_levels::PowerLevelsEventContent>()
.ok()?;
.unwrap();
tracing::info!("validation of power event finished");
// validation of users is done in Ruma, synapse for loops validating user_ids and integers here
let user_level = get_user_power_level(power_event.sender(), auth_events);
@ -424,6 +439,8 @@ fn check_power_levels(
event_levels_to_check.push(ev_id);
}
tracing::debug!("events to check {:?}", event_levels_to_check);
// TODO validate MSC2209 depending on room version check "notifications".
// synapse does this very differently with the loops (see comments below)
// but since we have a validated JSON event we can check the levels directly
@ -435,6 +452,7 @@ fn check_power_levels(
let old_level_too_big = old_level > user_level;
let new_level_too_big = new_level > user_level;
if old_level_too_big || new_level_too_big {
tracing::info!("m.room.power_level cannot add ops > than own");
return Some(false); // cannot add ops greater than own
}
}
@ -456,6 +474,7 @@ fn check_power_levels(
}
if user != power_event.sender() {
if old_level.map(|int| (*int).into()) == Some(user_level) {
tracing::info!("m.room.power_level cannot remove ops == to own");
return Some(false); // cannot remove ops level == to own
}
}
@ -463,6 +482,7 @@ fn check_power_levels(
let old_level_too_big = old_level.map(|int| (*int).into()) > Some(user_level);
let new_level_too_big = new_level.map(|int| (*int).into()) > Some(user_level);
if old_level_too_big || new_level_too_big {
tracing::info!("m.room.power_level failed to add ops > than own");
return Some(false); // cannot add ops greater than own
}
}
@ -480,6 +500,7 @@ fn check_power_levels(
let old_level_too_big = old_level.map(|int| (*int).into()) > Some(user_level);
let new_level_too_big = new_level.map(|int| (*int).into()) > Some(user_level);
if old_level_too_big || new_level_too_big {
tracing::info!("m.room.power_level failed to add ops > than own");
return Some(false); // cannot add ops greater than own
}
}
@ -579,21 +600,30 @@ fn get_send_level(
state_key: Option<String>,
power_lvl: Option<&StateEvent>,
) -> i64 {
tracing::debug!("{:?} {:?}", e_type, state_key);
if let Some(ple) = power_lvl {
if state_key.is_some() {
if let Ok(content) =
serde_json::from_value::<room::power_levels::PowerLevelsEventContent>(ple.content())
{
if let Some(_specific_ev) = content.events.get(&e_type) {
// this is done differently in synapse the `specific_ev` is set and if `users_default` is
// found it is used
if let Ok(content) =
serde_json::from_value::<room::power_levels::PowerLevelsEventContent>(ple.content())
{
let mut lvl: i64 = content
.events
.get(&e_type)
.cloned()
.unwrap_or(js_int::int!(50))
.into();
let state_def: i64 = content.state_default.into();
let event_def: i64 = content.events_default.into();
if state_key.is_some() {
if state_def > lvl {
lvl = event_def;
}
content.users_default.into()
} else {
return 50;
}
if event_def > lvl {
lvl = event_def;
}
return lvl;
} else {
return 0;
return 50;
}
} else {
return 0;

View File

@ -140,7 +140,13 @@ impl StateResolution {
// TODO make sure each conflicting event is in event_map??
// synapse says `full_set = {eid for eid in full_conflicted_set if eid in event_map}`
all_conflicted.retain(|id| event_map.contains_key(id));
println!(
"ALL {:?}",
all_conflicted
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
);
// get only the power events with a state_key: "" or ban/kick event (sender != state_key)
let power_events = all_conflicted
.iter()
@ -148,7 +154,7 @@ impl StateResolution {
.cloned()
.collect::<Vec<_>>();
tracing::debug!(
println!(
"POWER {:?}",
power_events
.iter()
@ -165,7 +171,7 @@ impl StateResolution {
&all_conflicted,
);
tracing::debug!(
println!(
"SRTD {:?}",
sorted_power_levels
.iter()
@ -203,7 +209,7 @@ impl StateResolution {
.cloned()
.collect::<Vec<_>>();
tracing::debug!(
println!(
"LEFT {:?}",
events_to_resolve
.iter()
@ -218,7 +224,7 @@ impl StateResolution {
let sorted_left_events =
self.mainline_sort(room_id, &events_to_resolve, power_event, &event_map, store);
tracing::debug!(
println!(
"SORTED LEFT {:?}",
sorted_left_events
.iter()
@ -324,7 +330,7 @@ impl StateResolution {
let mut event_to_pl = BTreeMap::new();
for (idx, event_id) in graph.keys().enumerate() {
let pl = self.get_power_level_for_sender(room_id, &event_id, event_map, store);
tracing::debug!("{} power level {}", event_id.to_string(), pl);
println!("{} power level {}", event_id.to_string(), pl);
event_to_pl.insert(event_id.clone(), pl);
@ -424,16 +430,17 @@ impl StateResolution {
&self,
room_id: &RoomId,
event_id: &EventId,
_event_map: &EventMap<StateEvent>, // TODO use event_map over store ??
event_map: &EventMap<StateEvent>, // TODO use event_map over store ??
store: &dyn StateStore,
) -> i64 {
tracing::info!("fetch event senders ({}) power level", event_id.to_string());
let event = event_map.get(event_id);
let mut pl = None;
// TODO store.auth_event_ids returns "self" with the event ids is this ok
// event.auth_event_ids does not include its own event id ?
for aid in store.auth_event_ids(room_id, &[event_id.clone()]).unwrap() {
if let Ok(aev) = store.get_event(&aid) {
for aid in event_map.get(event_id).unwrap().auth_event_ids() {
println!("aid {}", aid.to_string());
if let Some(aev) = event_map.get(&aid) {
if aev.is_type_and_key(EventType::RoomPowerLevels, "") {
pl = Some(aev);
break;
@ -442,8 +449,10 @@ impl StateResolution {
}
if pl.is_none() {
for aid in store.auth_event_ids(room_id, &[event_id.clone()]).unwrap() {
if let Ok(aev) = store.get_event(&aid) {
for aid in event_map.get(event_id).unwrap().auth_event_ids() {
println!("aid NONE {}", aid.to_string());
if let Some(aev) = event_map.get(&aid) {
if aev.is_type_and_key(EventType::RoomCreate, "") {
if let Ok(content) = aev
.deserialize_content::<ruma::events::room::create::CreateEventContent>()
@ -467,7 +476,12 @@ impl StateResolution {
})
.flatten()
{
content.users_default.into()
if let Some(ev) = event {
if let Some(user) = content.users.get(ev.sender()) {
return (*user).into();
}
}
content.state_default.into()
} else {
0
}
@ -510,6 +524,7 @@ impl StateResolution {
}
}
tracing::debug!("event to check {:?}", event.event_id().unwrap().to_string());
if !event_auth::auth_check(room_version, &event, auth_events)
.ok_or("Auth check failed due to deserialization most likely".to_string())
.unwrap()

View File

@ -35,8 +35,8 @@ impl StateEvent {
.contains(&content.membership)
{
return event.sender.as_str()
// TODO does None here mean the same as state_key = ""
!= event.state_key.as_deref().unwrap_or("");
// TODO is None here a failure
!= event.state_key.as_deref().unwrap_or("NOT A STATE KEY");
}
}
@ -44,32 +44,9 @@ impl StateEvent {
}
_ => false,
},
Pdu::RoomV3Pdu(event) => event.state_key == Some("".into()),
},
Self::Sync(any_event) => match any_event {
PduStub::RoomV1PduStub(event) => match event.kind {
EventType::RoomPowerLevels
| EventType::RoomJoinRules
| EventType::RoomCreate => event.state_key == Some("".into()),
EventType::RoomMember => {
if let Ok(content) =
serde_json::from_value::<MemberEventContent>(event.content.clone())
{
if [MembershipState::Leave, MembershipState::Ban]
.contains(&content.membership)
{
return event.sender.as_str()
// TODO does None here mean the same as state_key = ""
!= event.state_key.as_deref().unwrap_or("");
}
}
false
}
_ => false,
},
PduStub::RoomV3PduStub(event) => event.state_key == Some("".into()),
Pdu::RoomV3Pdu(event) => panic!(),
},
Self::Sync(any_event) => panic!(),
}
}
pub fn deserialize_content<C: serde::de::DeserializeOwned>(

View File

@ -286,10 +286,10 @@ fn INITIAL_EDGES() -> Vec<EventId> {
fn do_check(events: &[StateEvent], edges: Vec<Vec<EventId>>, expected_state_ids: Vec<EventId>) {
use itertools::Itertools;
// to activate logging use `RUST_LOG=debug cargo t`
tracer::fmt()
.with_env_filter(tracer::EnvFilter::from_default_env())
.init();
// to activate logging use `RUST_LOG=debug cargo t one_test_only`
// tracer::fmt()
// .with_env_filter(tracer::EnvFilter::from_default_env())
// .init();
let mut resolver = StateResolution::default();
// TODO what do we fill this with, everything ??
@ -519,6 +519,59 @@ fn ban_vs_power_level() {
}
// #[test]
fn topic_basic() {
let events = &[
to_init_pdu_event("T1", alice(), EventType::RoomTopic, Some(""), json!({})),
to_init_pdu_event(
"PA1",
alice(),
EventType::RoomPowerLevels,
Some(""),
json!({"users": {alice(): 100, bobo(): 50}}),
),
to_init_pdu_event("T2", alice(), EventType::RoomTopic, Some(""), json!({})),
to_init_pdu_event(
"PA2",
alice(),
EventType::RoomPowerLevels,
Some(""),
json!({"users": {alice(): 100, bobo(): 0}}),
),
to_init_pdu_event(
"PAB",
bobo(),
EventType::RoomPowerLevels,
Some(""),
json!({"users": {alice(): 100, bobo(): 50}}),
),
to_init_pdu_event("T3", bobo(), EventType::RoomTopic, Some(""), json!({})),
];
let edges = vec![
vec!["END", "PA2", "T2", "PA1", "T1", "START"],
vec!["END", "T3", "PB", "PA1"],
]
.into_iter()
.map(|list| {
list.into_iter()
.map(|s| format!("${}:foo", s))
.map(EventId::try_from)
.collect::<Result<Vec<_>, _>>()
.unwrap()
})
.collect::<Vec<_>>();
let expected_state_ids = vec!["PA2", "T2"]
.into_iter()
.map(|s| format!("${}:foo", s))
.map(EventId::try_from)
.collect::<Result<Vec<_>, _>>()
.unwrap();
do_check(events, edges, expected_state_ids)
}
#[test]
fn topic_reset() {
let events = &[
to_init_pdu_event("T1", alice(), EventType::RoomTopic, Some(""), json!({})),