Rename power_event -> control_event and add more docs
This commit is contained in:
parent
8dbd9aae0b
commit
1eb89941b7
@ -90,6 +90,14 @@ pub fn auth_check(
|
|||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
tracing::info!("auth_check beginning for {}", incoming_event.kind());
|
tracing::info!("auth_check beginning for {}", incoming_event.kind());
|
||||||
|
|
||||||
|
tracing::debug!(
|
||||||
|
"{:?}",
|
||||||
|
auth_events
|
||||||
|
.values()
|
||||||
|
.map(|id| id.event_id().to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
);
|
||||||
|
|
||||||
// don't let power from other rooms be used
|
// don't let power from other rooms be used
|
||||||
for auth_event in auth_events.values() {
|
for auth_event in auth_events.values() {
|
||||||
if auth_event.room_id() != incoming_event.room_id() {
|
if auth_event.room_id() != incoming_event.room_id() {
|
||||||
|
89
src/lib.rs
89
src/lib.rs
@ -51,13 +51,15 @@ impl StateResolution {
|
|||||||
///
|
///
|
||||||
/// * `store` - Any type that implements `StateStore` acts as the database. When an event is not
|
/// * `store` - Any type that implements `StateStore` acts as the database. When an event is not
|
||||||
/// found in the `event_map` it will be retrieved from the `store`.
|
/// found in the `event_map` it will be retrieved from the `store`.
|
||||||
|
///
|
||||||
|
/// It is up the the caller to check that the events returned from `StateStore::get_event` are
|
||||||
|
/// events for the correct room (synapse checks that all events are in the right room).
|
||||||
pub fn resolve(
|
pub fn resolve(
|
||||||
room_id: &RoomId,
|
room_id: &RoomId,
|
||||||
room_version: &RoomVersionId,
|
room_version: &RoomVersionId,
|
||||||
state_sets: &[StateMap<EventId>],
|
state_sets: &[StateMap<EventId>],
|
||||||
event_map: Option<EventMap<StateEvent>>,
|
event_map: Option<EventMap<StateEvent>>,
|
||||||
store: &dyn StateStore,
|
store: &dyn StateStore,
|
||||||
// TODO actual error handling (`thiserror`??)
|
|
||||||
) -> Result<StateMap<EventId>> {
|
) -> Result<StateMap<EventId>> {
|
||||||
tracing::info!("State resolution starting");
|
tracing::info!("State resolution starting");
|
||||||
|
|
||||||
@ -112,33 +114,25 @@ impl StateResolution {
|
|||||||
|
|
||||||
tracing::debug!("event map size: {}", event_map.len());
|
tracing::debug!("event map size: {}", event_map.len());
|
||||||
|
|
||||||
for event in event_map.values() {
|
// we used to check that all events are events from the correct room
|
||||||
if event.room_id() != Some(room_id) {
|
// this is now a check the caller of `resolve` must make.
|
||||||
return Err(Error::InvalidPdu(format!(
|
|
||||||
"resolving event {} in room {}, when correct room is {}",
|
|
||||||
event.event_id(),
|
|
||||||
event.room_id().map(|id| id.as_str()).unwrap_or("`unknown`"),
|
|
||||||
room_id.as_str()
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// synapse says `full_set = {eid for eid in full_conflicted_set if eid in event_map}`
|
// synapse says `full_set = {eid for eid in full_conflicted_set if eid in event_map}`
|
||||||
//
|
//
|
||||||
// don't honor events we cannot "verify"
|
// don't honor events we cannot "verify"
|
||||||
all_conflicted.retain(|id| event_map.contains_key(id));
|
all_conflicted.retain(|id| event_map.contains_key(id));
|
||||||
|
|
||||||
// get only the power events with a state_key: "" or ban/kick event (sender != state_key)
|
// get only the control events with a state_key: "" or ban/kick event (sender != state_key)
|
||||||
let power_events = all_conflicted
|
let control_events = all_conflicted
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|id| is_power_event(id, &event_map))
|
.filter(|id| is_power_event(id, &event_map))
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// sort the power events based on power_level/clock/event_id and outgoing/incoming edges
|
// sort the control events based on power_level/clock/event_id and outgoing/incoming edges
|
||||||
let mut sorted_power_levels = StateResolution::reverse_topological_power_sort(
|
let mut sorted_control_levels = StateResolution::reverse_topological_power_sort(
|
||||||
room_id,
|
room_id,
|
||||||
&power_events,
|
&control_events,
|
||||||
&mut event_map,
|
&mut event_map,
|
||||||
store,
|
store,
|
||||||
&all_conflicted,
|
&all_conflicted,
|
||||||
@ -146,17 +140,17 @@ impl StateResolution {
|
|||||||
|
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
"SRTD {:?}",
|
"SRTD {:?}",
|
||||||
sorted_power_levels
|
sorted_control_levels
|
||||||
.iter()
|
.iter()
|
||||||
.map(ToString::to_string)
|
.map(ToString::to_string)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
);
|
);
|
||||||
|
|
||||||
// sequentially auth check each power level event event.
|
// sequentially auth check each control event.
|
||||||
let resolved = StateResolution::iterative_auth_check(
|
let resolved_control = StateResolution::iterative_auth_check(
|
||||||
room_id,
|
room_id,
|
||||||
room_version,
|
room_version,
|
||||||
&sorted_power_levels,
|
&sorted_control_levels,
|
||||||
&clean,
|
&clean,
|
||||||
&mut event_map,
|
&mut event_map,
|
||||||
store,
|
store,
|
||||||
@ -164,18 +158,18 @@ impl StateResolution {
|
|||||||
|
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
"AUTHED {:?}",
|
"AUTHED {:?}",
|
||||||
resolved
|
resolved_control
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(key, id)| (key, id.to_string()))
|
.map(|(key, id)| (key, id.to_string()))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
);
|
);
|
||||||
|
|
||||||
// At this point the power_events have been resolved we now have to
|
// At this point the control_events have been resolved we now have to
|
||||||
// sort the remaining events using the mainline of the resolved power level.
|
// sort the remaining events using the mainline of the resolved power level.
|
||||||
sorted_power_levels.dedup();
|
sorted_control_levels.dedup();
|
||||||
let deduped_power_ev = sorted_power_levels;
|
let deduped_power_ev = sorted_control_levels;
|
||||||
|
|
||||||
// we have resolved the power events so remove them, I'm sure there are other reasons to do so
|
// This removes the control events that passed auth and more importantly those that failed auth
|
||||||
let events_to_resolve = all_conflicted
|
let events_to_resolve = all_conflicted
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|id| !deduped_power_ev.contains(id))
|
.filter(|id| !deduped_power_ev.contains(id))
|
||||||
@ -190,7 +184,7 @@ impl StateResolution {
|
|||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
);
|
);
|
||||||
|
|
||||||
let power_event = resolved.get(&(EventType::RoomPowerLevels, Some("".into())));
|
let power_event = resolved_control.get(&(EventType::RoomPowerLevels, Some("".into())));
|
||||||
|
|
||||||
tracing::debug!("PL {:?}", power_event);
|
tracing::debug!("PL {:?}", power_event);
|
||||||
|
|
||||||
@ -214,7 +208,7 @@ impl StateResolution {
|
|||||||
room_id,
|
room_id,
|
||||||
room_version,
|
room_version,
|
||||||
&sorted_left_events,
|
&sorted_left_events,
|
||||||
&resolved,
|
&resolved_control, // the control events are added to the final resolved state
|
||||||
&mut event_map,
|
&mut event_map,
|
||||||
store,
|
store,
|
||||||
)?;
|
)?;
|
||||||
@ -226,8 +220,11 @@ impl StateResolution {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Split the events that have no conflicts from those that are conflicting.
|
/// Split the events that have no conflicts from those that are conflicting.
|
||||||
|
/// The return tuple looks like `(unconflicted, conflicted)`.
|
||||||
///
|
///
|
||||||
/// The tuple looks like `(unconflicted, conflicted)`.
|
/// State is determined to be conflicting if for the given key (EventType, StateKey) there
|
||||||
|
/// is not exactly one eventId. This includes missing events, if one state_set includes an event
|
||||||
|
/// that none of the other have this is a conflicting event.
|
||||||
pub fn separate(
|
pub fn separate(
|
||||||
state_sets: &[StateMap<EventId>],
|
state_sets: &[StateMap<EventId>],
|
||||||
) -> (StateMap<EventId>, StateMap<Vec<EventId>>) {
|
) -> (StateMap<EventId>, StateMap<Vec<EventId>>) {
|
||||||
@ -248,14 +245,6 @@ impl StateResolution {
|
|||||||
.dedup()
|
.dedup()
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
tracing::debug!(
|
|
||||||
"SEP {:?}",
|
|
||||||
event_ids
|
|
||||||
.iter()
|
|
||||||
.map(|i| i.map(ToString::to_string).unwrap_or_else(|| "None".into()))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
);
|
|
||||||
|
|
||||||
if event_ids.len() == 1 {
|
if event_ids.len() == 1 {
|
||||||
if let Some(Some(id)) = event_ids.pop() {
|
if let Some(Some(id)) = event_ids.pop() {
|
||||||
unconflicted_state.insert(key.clone(), id.clone());
|
unconflicted_state.insert(key.clone(), id.clone());
|
||||||
@ -488,13 +477,18 @@ impl StateResolution {
|
|||||||
|
|
||||||
/// Check the that each event is authenticated based on the events before it.
|
/// Check the that each event is authenticated based on the events before it.
|
||||||
///
|
///
|
||||||
/// For each `power_events` event we gather the events needed to auth it from the
|
/// ## Returns
|
||||||
|
///
|
||||||
|
/// The `unconflicted_state` combined with the newly auth'ed events. So any event that
|
||||||
|
/// fails the `event_auth::auth_check` will be excluded from the returned `StateMap<EventId>`.
|
||||||
|
///
|
||||||
|
/// For each `events_to_check` event we gather the events needed to auth it from the
|
||||||
/// `event_map` or `store` and verify each event using the `event_auth::auth_check`
|
/// `event_map` or `store` and verify each event using the `event_auth::auth_check`
|
||||||
/// function.
|
/// function.
|
||||||
pub fn iterative_auth_check(
|
pub fn iterative_auth_check(
|
||||||
room_id: &RoomId,
|
room_id: &RoomId,
|
||||||
room_version: &RoomVersionId,
|
room_version: &RoomVersionId,
|
||||||
power_events: &[EventId],
|
events_to_check: &[EventId],
|
||||||
unconflicted_state: &StateMap<EventId>,
|
unconflicted_state: &StateMap<EventId>,
|
||||||
event_map: &mut EventMap<StateEvent>,
|
event_map: &mut EventMap<StateEvent>,
|
||||||
store: &dyn StateStore,
|
store: &dyn StateStore,
|
||||||
@ -502,8 +496,8 @@ impl StateResolution {
|
|||||||
tracing::info!("starting iterative auth check");
|
tracing::info!("starting iterative auth check");
|
||||||
|
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
"{:?}",
|
"performing auth checks on {:?}",
|
||||||
power_events
|
events_to_check
|
||||||
.iter()
|
.iter()
|
||||||
.map(ToString::to_string)
|
.map(ToString::to_string)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
@ -511,7 +505,7 @@ impl StateResolution {
|
|||||||
|
|
||||||
let mut resolved_state = unconflicted_state.clone();
|
let mut resolved_state = unconflicted_state.clone();
|
||||||
|
|
||||||
for (idx, event_id) in power_events.iter().enumerate() {
|
for (idx, event_id) in events_to_check.iter().enumerate() {
|
||||||
let event =
|
let event =
|
||||||
StateResolution::get_or_load_event(room_id, event_id, event_map, store).unwrap();
|
StateResolution::get_or_load_event(room_id, event_id, event_map, store).unwrap();
|
||||||
|
|
||||||
@ -521,7 +515,7 @@ impl StateResolution {
|
|||||||
StateResolution::get_or_load_event(room_id, &aid, event_map, store)
|
StateResolution::get_or_load_event(room_id, &aid, event_map, store)
|
||||||
{
|
{
|
||||||
// TODO what to do when no state_key is found ??
|
// TODO what to do when no state_key is found ??
|
||||||
// TODO synapse check "rejected_reason", I'm guessing this is redacted_because for ruma ??
|
// TODO synapse check "rejected_reason", I'm guessing this is redacted_because in ruma ??
|
||||||
auth_events.insert((ev.kind(), ev.state_key()), ev);
|
auth_events.insert((ev.kind(), ev.state_key()), ev);
|
||||||
} else {
|
} else {
|
||||||
tracing::warn!("auth event id for {} is missing {}", aid, event_id);
|
tracing::warn!("auth event id for {} is missing {}", aid, event_id);
|
||||||
@ -544,7 +538,7 @@ impl StateResolution {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::debug!("event to check {:?}", event.event_id().to_string());
|
tracing::debug!("event to check {:?}", event.event_id().as_str());
|
||||||
|
|
||||||
let most_recent_prev_event = event
|
let most_recent_prev_event = event
|
||||||
.prev_event_ids()
|
.prev_event_ids()
|
||||||
@ -579,7 +573,12 @@ impl StateResolution {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the sorted `to_sort` list of `EventId`s based on a mainline sort using
|
/// Returns the sorted `to_sort` list of `EventId`s based on a mainline sort using
|
||||||
/// the `resolved_power_level`.
|
/// the depth of `resolved_power_level`, the server timestamp, and the eventId.
|
||||||
|
///
|
||||||
|
/// The depth of the given event is calculated based on the depth of it's closest "parent"
|
||||||
|
/// power_level event. If there have been two power events the after the most recent are
|
||||||
|
/// depth 0, the events before (with the first power level as a parent) will be marked
|
||||||
|
/// as depth 1. depth 1 is "older" than depth 0.
|
||||||
pub fn mainline_sort(
|
pub fn mainline_sort(
|
||||||
room_id: &RoomId,
|
room_id: &RoomId,
|
||||||
to_sort: &[EventId],
|
to_sort: &[EventId],
|
||||||
@ -664,6 +663,8 @@ impl StateResolution {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO make `event` not clone every loop
|
// TODO make `event` not clone every loop
|
||||||
|
/// Get the mainline depth from the `mainline_map` or finds a power_level event
|
||||||
|
/// that has an associated mainline depth.
|
||||||
fn get_mainline_depth(
|
fn get_mainline_depth(
|
||||||
room_id: &RoomId,
|
room_id: &RoomId,
|
||||||
mut event: Option<StateEvent>,
|
mut event: Option<StateEvent>,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user