Fix an issue with ignoring power_level changes on divergent graphs
Changes to m.room.power_levels events are supposed to be handled at a high priority; however a typo meant that the relevant bit of code was never executed, so they were handled just like any other state change - which meant that a bad person could cause room state changes by forking the graph from a point in history when they were allowed to do so.pull/365/head
parent
06bfd0a3c0
commit
78f6010207
|
@ -307,19 +307,23 @@ class StateHandler(object):
|
|||
|
||||
We resolve conflicts in the following order:
|
||||
1. power levels
|
||||
2. memberships
|
||||
3. other events.
|
||||
2. join rules
|
||||
3. memberships
|
||||
4. other events.
|
||||
"""
|
||||
resolved_state = {}
|
||||
power_key = (EventTypes.PowerLevels, "")
|
||||
if power_key in conflicted_state.items():
|
||||
power_levels = conflicted_state[power_key]
|
||||
resolved_state[power_key] = self._resolve_auth_events(power_levels)
|
||||
if power_key in conflicted_state:
|
||||
events = conflicted_state[power_key]
|
||||
logger.debug("Resolving conflicted power levels %r", events)
|
||||
resolved_state[power_key] = self._resolve_auth_events(
|
||||
events, auth_events)
|
||||
|
||||
auth_events.update(resolved_state)
|
||||
|
||||
for key, events in conflicted_state.items():
|
||||
if key[0] == EventTypes.JoinRules:
|
||||
logger.debug("Resolving conflicted join rules %r", events)
|
||||
resolved_state[key] = self._resolve_auth_events(
|
||||
events,
|
||||
auth_events
|
||||
|
@ -329,6 +333,7 @@ class StateHandler(object):
|
|||
|
||||
for key, events in conflicted_state.items():
|
||||
if key[0] == EventTypes.Member:
|
||||
logger.debug("Resolving conflicted member lists %r", events)
|
||||
resolved_state[key] = self._resolve_auth_events(
|
||||
events,
|
||||
auth_events
|
||||
|
@ -338,6 +343,7 @@ class StateHandler(object):
|
|||
|
||||
for key, events in conflicted_state.items():
|
||||
if key not in resolved_state:
|
||||
logger.debug("Resolving conflicted state %r:%r", key, events)
|
||||
resolved_state[key] = self._resolve_normal_events(
|
||||
events, auth_events
|
||||
)
|
||||
|
|
|
@ -317,6 +317,99 @@ class StateTestCase(unittest.TestCase):
|
|||
{e.event_id for e in context_store["E"].current_state.values()}
|
||||
)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def test_branch_have_perms_conflict(self):
|
||||
userid1 = "@user_id:example.com"
|
||||
userid2 = "@user_id2:example.com"
|
||||
|
||||
nodes = {
|
||||
"A1": DictObj(
|
||||
type=EventTypes.Create,
|
||||
state_key="",
|
||||
content={"creator": userid1},
|
||||
depth=1,
|
||||
),
|
||||
"A2": DictObj(
|
||||
type=EventTypes.Member,
|
||||
state_key=userid1,
|
||||
content={"membership": Membership.JOIN},
|
||||
membership=Membership.JOIN,
|
||||
),
|
||||
"A3": DictObj(
|
||||
type=EventTypes.Member,
|
||||
state_key=userid2,
|
||||
content={"membership": Membership.JOIN},
|
||||
membership=Membership.JOIN,
|
||||
),
|
||||
"A4": DictObj(
|
||||
type=EventTypes.PowerLevels,
|
||||
state_key="",
|
||||
content={
|
||||
"events": {"m.room.name": 50},
|
||||
"users": {userid1: 100,
|
||||
userid2: 60},
|
||||
},
|
||||
),
|
||||
"A5": DictObj(
|
||||
type=EventTypes.Name,
|
||||
state_key="",
|
||||
),
|
||||
"B": DictObj(
|
||||
type=EventTypes.PowerLevels,
|
||||
state_key="",
|
||||
content={
|
||||
"events": {"m.room.name": 50},
|
||||
"users": {userid2: 30},
|
||||
},
|
||||
),
|
||||
"C": DictObj(
|
||||
type=EventTypes.Name,
|
||||
state_key="",
|
||||
sender=userid2,
|
||||
),
|
||||
"D": DictObj(
|
||||
type=EventTypes.Message,
|
||||
),
|
||||
}
|
||||
edges = {
|
||||
"A2": ["A1"],
|
||||
"A3": ["A2"],
|
||||
"A4": ["A3"],
|
||||
"A5": ["A4"],
|
||||
"B": ["A5"],
|
||||
"C": ["A5"],
|
||||
"D": ["B", "C"]
|
||||
}
|
||||
self._add_depths(nodes, edges)
|
||||
graph = Graph(nodes, edges)
|
||||
|
||||
store = StateGroupStore()
|
||||
self.store.get_state_groups.side_effect = store.get_state_groups
|
||||
|
||||
context_store = {}
|
||||
|
||||
for event in graph.walk():
|
||||
context = yield self.state.compute_event_context(event)
|
||||
store.store_state_groups(event, context)
|
||||
context_store[event.event_id] = context
|
||||
|
||||
self.assertSetEqual(
|
||||
{"A1", "A2", "A3", "A5", "B"},
|
||||
{e.event_id for e in context_store["D"].current_state.values()}
|
||||
)
|
||||
|
||||
def _add_depths(self, nodes, edges):
|
||||
def _get_depth(ev):
|
||||
node = nodes[ev]
|
||||
if 'depth' not in node:
|
||||
prevs = edges[ev]
|
||||
depth = max(_get_depth(prev) for prev in prevs) + 1
|
||||
node['depth'] = depth
|
||||
return node['depth']
|
||||
|
||||
for n in nodes:
|
||||
_get_depth(n)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def test_annotate_with_old_message(self):
|
||||
event = create_event(type="test_message", name="event")
|
||||
|
|
Loading…
Reference in New Issue