diff --git a/synapse/api/auth.py b/synapse/api/auth.py index 15407df14..886e132e1 100644 --- a/synapse/api/auth.py +++ b/synapse/api/auth.py @@ -162,6 +162,8 @@ class Auth(object): """ try: user_id = yield self.store.get_user_by_token(token=token) + if not user_id: + raise StoreError() defer.returnValue(self.hs.parse_userid(user_id)) except StoreError: raise AuthError(403, "Unrecognised access token.", diff --git a/synapse/rest/room.py b/synapse/rest/room.py index 5eee49e51..b8d5cb87f 100644 --- a/synapse/rest/room.py +++ b/synapse/rest/room.py @@ -18,10 +18,8 @@ from twisted.internet import defer from base import RestServlet, client_path_pattern from synapse.api.errors import SynapseError, Codes -from synapse.api.events.room import ( - MessageEvent, RoomMemberEvent, FeedbackEvent -) -from synapse.api.constants import Feedback +from synapse.api.events.room import RoomMemberEvent +from synapse.api.constants import Membership from synapse.api.streams import PaginationConfig import json @@ -210,24 +208,63 @@ class RoomSendEventRestServlet(RestServlet): defer.returnValue(response) +# TODO: Needs unit testing for room ID + alias joins class JoinRoomAliasServlet(RestServlet): - PATTERN = client_path_pattern("/join/(?P[^/]+)$") + + def register(self, http_server): + # /join/$room_identifier[/$txn_id] + PATTERN = ("/join/(?P[^/]*)") + register_txn_path(self, PATTERN, http_server) @defer.inlineCallbacks - def on_PUT(self, request, room_alias): + def on_POST(self, request, room_identifier): user = yield self.auth.get_user_by_req(request) - if not user: - defer.returnValue((403, "Unrecognized user")) + # the identifier could be a room alias or a room id. Try one then the + # other if it fails to parse, without swallowing other valid + # SynapseErrors. - logger.debug("room_alias: %s", room_alias) + identifier = None + is_room_alias = False + try: + identifier = self.hs.parse_roomalias( + urllib.unquote(room_identifier) + ) + is_room_alias = True + except SynapseError: + identifier = self.hs.parse_roomid( + urllib.unquote(room_identifier) + ) - room_alias = self.hs.parse_roomalias(urllib.unquote(room_alias)) + # TODO: Support for specifying the home server to join with? - handler = self.handlers.room_member_handler - ret_dict = yield handler.join_room_alias(user, room_alias) + if is_room_alias: + handler = self.handlers.room_member_handler + ret_dict = yield handler.join_room_alias(user, identifier) + defer.returnValue((200, ret_dict)) + else: # room id + event = self.event_factory.create_event( + etype=RoomMemberEvent.TYPE, + content={"membership": Membership.JOIN}, + room_id=urllib.unquote(identifier.to_string()), + user_id=user.to_string(), + state_key=user.to_string() + ) + handler = self.handlers.room_member_handler + yield handler.change_membership(event) + defer.returnValue((200, "")) - defer.returnValue((200, ret_dict)) + @defer.inlineCallbacks + def on_PUT(self, request, room_identifier, txn_id): + try: + defer.returnValue(self.txns.get_client_transaction(request, txn_id)) + except KeyError: + pass + + response = yield self.on_POST(request, room_identifier) + + self.txns.store_client_transaction(request, txn_id, response) + defer.returnValue(response) # TODO: Needs unit testing diff --git a/synapse/server.py b/synapse/server.py index c5b0a3275..439b9d628 100644 --- a/synapse/server.py +++ b/synapse/server.py @@ -28,7 +28,7 @@ from synapse.handlers import Handlers from synapse.rest import RestServletFactory from synapse.state import StateHandler from synapse.storage import DataStore -from synapse.types import UserID, RoomAlias +from synapse.types import UserID, RoomAlias, RoomID from synapse.util import Clock from synapse.util.distributor import Distributor from synapse.util.lockutils import LockManager @@ -117,6 +117,9 @@ class BaseHomeServer(object): setattr(BaseHomeServer, "get_%s" % (depname), _get) + # TODO: Why are these parse_ methods so high up along with other globals? + # Surely these should be in a util package or in the api package? + # Other utility methods def parse_userid(self, s): """Parse the string given by 's' as a User ID and return a UserID @@ -128,6 +131,11 @@ class BaseHomeServer(object): object.""" return RoomAlias.from_string(s, hs=self) + def parse_roomid(self, s): + """Parse the string given by 's' as a Room ID and return a RoomID + object.""" + return RoomID.from_string(s, hs=self) + # Build magic accessors for every dependency for depname in BaseHomeServer.DEPENDENCIES: BaseHomeServer._make_dependency_method(depname)