Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Pass through room version to event auth #4482

Merged
merged 3 commits into from
Jan 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/4482.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add infrastructure to support different event formats
14 changes: 10 additions & 4 deletions synapse/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def __init__(self, hs):
register_cache("cache", "token_cache", self.token_cache)

@defer.inlineCallbacks
def check_from_context(self, event, context, do_sig_check=True):
def check_from_context(self, room_version, event, context, do_sig_check=True):
prev_state_ids = yield context.get_prev_state_ids(self.store)
auth_events_ids = yield self.compute_auth_events(
event, prev_state_ids, for_verification=True,
Expand All @@ -74,12 +74,16 @@ def check_from_context(self, event, context, do_sig_check=True):
auth_events = {
(e.type, e.state_key): e for e in itervalues(auth_events)
}
self.check(event, auth_events=auth_events, do_sig_check=do_sig_check)
self.check(
room_version, event,
auth_events=auth_events, do_sig_check=do_sig_check,
)

def check(self, event, auth_events, do_sig_check=True):
def check(self, room_version, event, auth_events, do_sig_check=True):
""" Checks if this event is correctly authed.

Args:
room_version (str): version of the room
event: the event being checked.
auth_events (dict: event-key -> event): the existing room state.

Expand All @@ -88,7 +92,9 @@ def check(self, event, auth_events, do_sig_check=True):
True if the auth checks pass.
"""
with Measure(self.clock, "auth.check"):
event_auth.check(event, auth_events, do_sig_check=do_sig_check)
event_auth.check(
room_version, event, auth_events, do_sig_check=do_sig_check
)

@defer.inlineCallbacks
def check_joined_room(self, room_id, user_id, current_state=None):
Expand Down
3 changes: 2 additions & 1 deletion synapse/event_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
logger = logging.getLogger(__name__)


def check(event, auth_events, do_sig_check=True, do_size_check=True):
def check(room_version, event, auth_events, do_sig_check=True, do_size_check=True):
""" Checks if this event is correctly authed.

Args:
room_version (str): the version of the room
event: the event being checked.
auth_events (dict: event-key -> event): the existing room state.

Expand Down
20 changes: 12 additions & 8 deletions synapse/handlers/federation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1189,7 +1189,9 @@ def on_make_join_request(self, room_id, user_id):

# The remote hasn't signed it yet, obviously. We'll do the full checks
# when we get the event back in `on_send_join_request`
yield self.auth.check_from_context(event, context, do_sig_check=False)
yield self.auth.check_from_context(
room_version, event, context, do_sig_check=False,
)

defer.returnValue(event)

Expand Down Expand Up @@ -1388,7 +1390,9 @@ def on_make_leave_request(self, room_id, user_id):
try:
# The remote hasn't signed it yet, obviously. We'll do the full checks
# when we get the event back in `on_send_leave_request`
yield self.auth.check_from_context(event, context, do_sig_check=False)
yield self.auth.check_from_context(
room_version, event, context, do_sig_check=False,
)
except AuthError as e:
logger.warn("Failed to create new leave %r because %s", event, e)
raise e
Expand Down Expand Up @@ -1683,7 +1687,7 @@ def _persist_auth_tree(self, origin, auth_events, state, event):
auth_for_e[(EventTypes.Create, "")] = create_event

try:
self.auth.check(e, auth_events=auth_for_e)
self.auth.check(room_version, e, auth_events=auth_for_e)
except SynapseError as err:
# we may get SynapseErrors here as well as AuthErrors. For
# instance, there are a couple of (ancient) events in some
Expand Down Expand Up @@ -1927,6 +1931,8 @@ def do_auth(self, origin, event, context, auth_events):
current_state = set(e.event_id for e in auth_events.values())
different_auth = event_auth_events - current_state

room_version = yield self.store.get_room_version(event.room_id)

if different_auth and not event.internal_metadata.is_outlier():
# Do auth conflict res.
logger.info("Different auth: %s", different_auth)
Expand All @@ -1951,8 +1957,6 @@ def do_auth(self, origin, event, context, auth_events):
(d.type, d.state_key): d for d in different_events if d
})

room_version = yield self.store.get_room_version(event.room_id)

new_state = yield self.state_handler.resolve_events(
room_version,
[list(local_view.values()), list(remote_view.values())],
Expand Down Expand Up @@ -2052,7 +2056,7 @@ def do_auth(self, origin, event, context, auth_events):
)

try:
self.auth.check(event, auth_events=auth_events)
self.auth.check(room_version, event, auth_events=auth_events)
except AuthError as e:
logger.warn("Failed auth resolution for %r because %s", event, e)
raise e
Expand Down Expand Up @@ -2288,7 +2292,7 @@ def exchange_third_party_invite(
)

try:
yield self.auth.check_from_context(event, context)
yield self.auth.check_from_context(room_version, event, context)
except AuthError as e:
logger.warn("Denying new third party invite %r because %s", event, e)
raise e
Expand Down Expand Up @@ -2330,7 +2334,7 @@ def on_exchange_third_party_invite_request(self, origin, room_id, event_dict):
)

try:
self.auth.check_from_context(event, context)
self.auth.check_from_context(room_version, event, context)
except AuthError as e:
logger.warn("Denying third party invite %r because %s", event, e)
raise e
Expand Down
9 changes: 7 additions & 2 deletions synapse/handlers/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
from twisted.internet import defer
from twisted.internet.defer import succeed

from synapse.api.constants import MAX_DEPTH, EventTypes, Membership
from synapse.api.constants import MAX_DEPTH, EventTypes, Membership, RoomVersions
from synapse.api.errors import (
AuthError,
Codes,
Expand Down Expand Up @@ -611,8 +611,13 @@ def handle_new_client_event(
extra_users (list(UserID)): Any extra users to notify about event
"""

if event.is_state() and (event.type, event.state_key) == (EventTypes.Create, ""):
room_version = event.content.get("room_version", RoomVersions.V1)
else:
room_version = yield self.store.get_room_version(event.room_id)

try:
yield self.auth.check_from_context(event, context)
yield self.auth.check_from_context(room_version, event, context)
except AuthError as err:
logger.warn("Denying new event %r because %s", event, err)
raise err
Expand Down
5 changes: 4 additions & 1 deletion synapse/handlers/room.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ def upgrade_room(self, requester, old_room_id, new_version):
token_id=requester.access_token_id,
)
)
yield self.auth.check_from_context(tombstone_event, tombstone_context)
old_room_version = yield self.store.get_room_version(old_room_id)
yield self.auth.check_from_context(
old_room_version, tombstone_event, tombstone_context,
)

yield self.clone_exiting_room(
requester,
Expand Down
2 changes: 1 addition & 1 deletion synapse/state/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ def resolve_events_with_store(room_version, state_sets, event_map, state_res_sto
RoomVersions.VDH_TEST, RoomVersions.STATE_V2_TEST, RoomVersions.V2,
):
return v2.resolve_events_with_store(
state_sets, event_map, state_res_store,
room_version, state_sets, event_map, state_res_store,
)
else:
# This should only happen if we added a version but forgot to add it to
Expand Down
14 changes: 11 additions & 3 deletions synapse/state/v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
from twisted.internet import defer

from synapse import event_auth
from synapse.api.constants import EventTypes
from synapse.api.constants import EventTypes, RoomVersions
from synapse.api.errors import AuthError

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -274,7 +274,11 @@ def _resolve_auth_events(events, auth_events):
auth_events[(prev_event.type, prev_event.state_key)] = prev_event
try:
# The signatures have already been checked at this point
event_auth.check(event, auth_events, do_sig_check=False, do_size_check=False)
event_auth.check(
RoomVersions.V1, event, auth_events,
do_sig_check=False,
do_size_check=False,
)
prev_event = event
except AuthError:
return prev_event
Expand All @@ -286,7 +290,11 @@ def _resolve_normal_events(events, auth_events):
for event in _ordered_events(events):
try:
# The signatures have already been checked at this point
event_auth.check(event, auth_events, do_sig_check=False, do_size_check=False)
event_auth.check(
RoomVersions.V1, event, auth_events,
do_sig_check=False,
do_size_check=False,
)
return event
except AuthError:
pass
Expand Down
14 changes: 9 additions & 5 deletions synapse/state/v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@


@defer.inlineCallbacks
def resolve_events_with_store(state_sets, event_map, state_res_store):
def resolve_events_with_store(room_version, state_sets, event_map, state_res_store):
"""Resolves the state using the v2 state resolution algorithm

Args:
room_version (str): The room version

state_sets(list): List of dicts of (type, state_key) -> event_id,
which are the different state groups to resolve.

Expand Down Expand Up @@ -104,7 +106,7 @@ def resolve_events_with_store(state_sets, event_map, state_res_store):

# Now sequentially auth each one
resolved_state = yield _iterative_auth_checks(
sorted_power_events, unconflicted_state, event_map,
room_version, sorted_power_events, unconflicted_state, event_map,
state_res_store,
)

Expand All @@ -129,7 +131,7 @@ def resolve_events_with_store(state_sets, event_map, state_res_store):
logger.debug("resolving remaining events")

resolved_state = yield _iterative_auth_checks(
leftover_events, resolved_state, event_map,
room_version, leftover_events, resolved_state, event_map,
state_res_store,
)

Expand Down Expand Up @@ -350,11 +352,13 @@ def _get_power_order(event_id):


@defer.inlineCallbacks
def _iterative_auth_checks(event_ids, base_state, event_map, state_res_store):
def _iterative_auth_checks(room_version, event_ids, base_state, event_map,
state_res_store):
"""Sequentially apply auth checks to each event in given list, updating the
state as it goes along.

Args:
room_version (str)
event_ids (list[str]): Ordered list of events to apply auth checks to
base_state (dict[tuple[str, str], str]): The set of state to start with
event_map (dict[str,FrozenEvent])
Expand Down Expand Up @@ -385,7 +389,7 @@ def _iterative_auth_checks(event_ids, base_state, event_map, state_res_store):

try:
event_auth.check(
event, auth_events,
room_version, event, auth_events,
do_sig_check=False,
do_size_check=False
)
Expand Down
4 changes: 3 additions & 1 deletion tests/state/test_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import attr

from synapse.api.constants import EventTypes, JoinRules, Membership
from synapse.api.constants import EventTypes, JoinRules, Membership, RoomVersions
from synapse.event_auth import auth_types_for_event
from synapse.events import FrozenEvent
from synapse.state.v2 import lexicographical_topological_sort, resolve_events_with_store
Expand Down Expand Up @@ -539,6 +539,7 @@ def do_check(self, events, edges, expected_state_ids):
state_before = dict(state_at_event[prev_events[0]])
else:
state_d = resolve_events_with_store(
RoomVersions.V2,
[state_at_event[n] for n in prev_events],
event_map=event_map,
state_res_store=TestStateResolutionStore(event_map),
Expand Down Expand Up @@ -685,6 +686,7 @@ def test_event_map_none(self):
# Test that we correctly handle passing `None` as the event_map

state_d = resolve_events_with_store(
RoomVersions.V2,
[self.state_at_bob, self.state_at_charlie],
event_map=None,
state_res_store=TestStateResolutionStore(self.event_map),
Expand Down
13 changes: 11 additions & 2 deletions tests/test_event_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import unittest

from synapse import event_auth
from synapse.api.constants import RoomVersions
from synapse.api.errors import AuthError
from synapse.events import FrozenEvent

Expand All @@ -35,12 +36,16 @@ def test_random_users_cannot_send_state_before_first_pl(self):
}

# creator should be able to send state
event_auth.check(_random_state_event(creator), auth_events, do_sig_check=False)
event_auth.check(
RoomVersions.V1, _random_state_event(creator), auth_events,
do_sig_check=False,
)

# joiner should not be able to send state
self.assertRaises(
AuthError,
event_auth.check,
RoomVersions.V1,
_random_state_event(joiner),
auth_events,
do_sig_check=False,
Expand Down Expand Up @@ -69,13 +74,17 @@ def test_state_default_level(self):
self.assertRaises(
AuthError,
event_auth.check,
RoomVersions.V1,
_random_state_event(pleb),
auth_events,
do_sig_check=False,
),

# king should be able to send state
event_auth.check(_random_state_event(king), auth_events, do_sig_check=False)
event_auth.check(
RoomVersions.V1, _random_state_event(king), auth_events,
do_sig_check=False,
)


# helpers for making events
Expand Down