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

Commit

Permalink
Refactor the membership check methods in Auth
Browse files Browse the repository at this point in the history
these were getting a bit unwieldy, so let's combine `check_joined_room` and
`check_user_was_in_room` into a single `check_user_in_room`.
  • Loading branch information
richvdh committed Feb 18, 2020
1 parent adfaea8 commit b58d17e
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 73 deletions.
80 changes: 37 additions & 43 deletions synapse/api/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# limitations under the License.

import logging
from typing import Optional

from six import itervalues

Expand All @@ -35,6 +36,7 @@
)
from synapse.api.room_versions import KNOWN_ROOM_VERSIONS
from synapse.config.server import is_threepid_reserved
from synapse.events import EventBase
from synapse.types import StateMap, UserID
from synapse.util.caches import CACHE_SIZE_FACTOR, register_cache
from synapse.util.caches.lrucache import LruCache
Expand Down Expand Up @@ -92,71 +94,61 @@ def check_from_context(self, room_version: str, event, context, do_sig_check=Tru
)

@defer.inlineCallbacks
def check_joined_room(self, room_id, user_id, current_state=None):
"""Check if the user is currently joined in the room
def check_user_in_room(
self,
room_id: str,
user_id: str,
current_state: Optional[StateMap[EventBase]] = None,
allow_departed_users: bool = False,
):
"""Check if the user is in the room, or was at some point.
Args:
room_id(str): The room to check.
user_id(str): The user to check.
current_state(dict): Optional map of the current state of the room.
room_id: The room to check.
user_id: The user to check.
current_state: Optional map of the current state of the room.
If provided then that map is used to check whether they are a
member of the room. Otherwise the current membership is
loaded from the database.
allow_departed_users: if True, accept users that were previously
members but have now departed.
Raises:
AuthError if the user is not in the room.
AuthError if the user is/was not in the room.
Returns:
A deferred membership event for the user if the user is in
the room.
Deferred[Optional[EventBase]]:
Membership event for the user if the user was in the
room. This will be the join event if they are currently joined to
the room. This will be the leave event if they have left the room.
"""
if current_state:
member = current_state.get((EventTypes.Member, user_id), None)
else:
member = yield self.state.get_current_state(
room_id=room_id, event_type=EventTypes.Member, state_key=user_id
)

self._check_joined_room(member, user_id, room_id)
return member

@defer.inlineCallbacks
def check_user_was_in_room(self, room_id, user_id):
"""Check if the user was in the room at some point.
Args:
room_id(str): The room to check.
user_id(str): The user to check.
Raises:
AuthError if the user was never in the room.
Returns:
A deferred membership event for the user if the user was in the
room. This will be the join event if they are currently joined to
the room. This will be the leave event if they have left the room.
"""
member = yield self.state.get_current_state(
room_id=room_id, event_type=EventTypes.Member, state_key=user_id
)
membership = member.membership if member else None

if membership not in (Membership.JOIN, Membership.LEAVE):
raise AuthError(403, "User %s not in room %s" % (user_id, room_id))
if membership == Membership.JOIN:
return member

if membership == Membership.LEAVE:
# XXX this looks totally bogus. Why do we not allow users who have been banned,
# or those who were members previously and have been re-invited?
if allow_departed_users and membership == Membership.LEAVE:
forgot = yield self.store.did_forget(user_id, room_id)
if forgot:
raise AuthError(403, "User %s not in room %s" % (user_id, room_id))
if not forgot:
return member

return member
raise AuthError(403, "User %s not in room %s" % (user_id, room_id))

@defer.inlineCallbacks
def check_host_in_room(self, room_id, host):
with Measure(self.clock, "check_host_in_room"):
latest_event_ids = yield self.store.is_host_joined(room_id, host)
return latest_event_ids

def _check_joined_room(self, member, user_id, room_id):
if not member or member.membership != Membership.JOIN:
raise AuthError(
403, "User %s not in room %s (%s)" % (user_id, room_id, repr(member))
)

def can_federate(self, event, auth_events):
creation_event = auth_events.get((EventTypes.Create, ""))

Expand Down Expand Up @@ -560,7 +552,7 @@ def check_can_change_room_list(self, room_id, user):
return True

user_id = user.to_string()
yield self.check_joined_room(room_id, user_id)
yield self.check_user_in_room(room_id, user_id)

# We currently require the user is a "moderator" in the room. We do this
# by checking if they would (theoretically) be able to change the
Expand Down Expand Up @@ -645,12 +637,14 @@ def check_in_room_or_world_readable(self, room_id, user_id):
"""

try:
# check_user_was_in_room will return the most recent membership
# check_user_in_room will return the most recent membership
# event for the user if:
# * The user is a non-guest user, and was ever in the room
# * The user is a guest user, and has joined the room
# else it will throw.
member_event = yield self.check_user_was_in_room(room_id, user_id)
member_event = yield self.check_user_in_room(
room_id, user_id, allow_departed_users=True
)
return member_event.membership, member_event.event_id
except AuthError:
visibility = yield self.state.get_current_state(
Expand Down
31 changes: 5 additions & 26 deletions synapse/handlers/initial_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from twisted.internet import defer

from synapse.api.constants import EventTypes, Membership
from synapse.api.errors import AuthError, Codes, SynapseError
from synapse.api.errors import SynapseError
from synapse.events.validator import EventValidator
from synapse.handlers.presence import format_user_presence_state
from synapse.logging.context import make_deferred_yieldable, run_in_background
Expand Down Expand Up @@ -274,9 +274,10 @@ async def room_initial_sync(self, requester, room_id, pagin_config=None):

user_id = requester.user.to_string()

membership, member_event_id = await self._check_in_room_or_world_readable(
room_id, user_id
)
(
membership,
member_event_id,
) = await self.auth.check_user_in_room_or_world_readable(room_id, user_id)
is_peeking = member_event_id is None

if membership == Membership.JOIN:
Expand Down Expand Up @@ -433,25 +434,3 @@ async def get_receipts():
ret["membership"] = membership

return ret

async def _check_in_room_or_world_readable(self, room_id, user_id):
try:
# check_user_was_in_room will return the most recent membership
# event for the user if:
# * The user is a non-guest user, and was ever in the room
# * The user is a guest user, and has joined the room
# else it will throw.
member_event = await self.auth.check_user_was_in_room(room_id, user_id)
return member_event.membership, member_event.event_id
except AuthError:
visibility = await self.state_handler.get_current_state(
room_id, EventTypes.RoomHistoryVisibility, ""
)
if (
visibility
and visibility.content["history_visibility"] == "world_readable"
):
return Membership.JOIN, None
raise AuthError(
403, "Guest access not allowed", errcode=Codes.GUEST_ACCESS_FORBIDDEN
)
4 changes: 2 additions & 2 deletions synapse/handlers/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def started_typing(self, target_user, auth_user, room_id, timeout):
if target_user_id != auth_user_id:
raise AuthError(400, "Cannot set another user's typing state")

yield self.auth.check_joined_room(room_id, target_user_id)
yield self.auth.check_user_in_room(room_id, target_user_id)

logger.debug("%s has started typing in %s", target_user_id, room_id)

Expand Down Expand Up @@ -155,7 +155,7 @@ def stopped_typing(self, target_user, auth_user, room_id):
if target_user_id != auth_user_id:
raise AuthError(400, "Cannot set another user's typing state")

yield self.auth.check_joined_room(room_id, target_user_id)
yield self.auth.check_user_in_room(room_id, target_user_id)

logger.debug("%s has stopped typing in %s", target_user_id, room_id)

Expand Down
4 changes: 2 additions & 2 deletions tests/handlers/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,11 +122,11 @@ def get_received_txn_response(*args):

self.room_members = []

def check_joined_room(room_id, user_id):
def check_user_in_room(room_id, user_id):
if user_id not in [u.to_string() for u in self.room_members]:
raise AuthError(401, "User is not in the room")

hs.get_auth().check_joined_room = check_joined_room
hs.get_auth().check_user_in_room = check_user_in_room

def get_joined_hosts_for_room(room_id):
return set(member.domain for member in self.room_members)
Expand Down

0 comments on commit b58d17e

Please sign in to comment.