diff --git a/synapse/api/auth.py b/synapse/api/auth.py
index 4f116184c9..ea8c461729 100644
--- a/synapse/api/auth.py
+++ b/synapse/api/auth.py
@@ -380,6 +380,18 @@ class Auth(object):
raise AuthError(403, "Unrecognised access token.",
errcode=Codes.UNKNOWN_TOKEN)
+ @defer.inlineCallbacks
+ def get_appservice_by_req(self, request):
+ try:
+ token = request.args["access_token"][0]
+ service = yield self.store.get_app_service_by_token(token)
+ if not service:
+ raise AuthError(403, "Unrecognised access token.",
+ errcode=Codes.UNKNOWN_TOKEN)
+ defer.returnValue(service)
+ except KeyError:
+ raise AuthError(403, "Missing access token.")
+
def is_server_admin(self, user):
return self.store.is_server_admin(user)
diff --git a/synapse/api/errors.py b/synapse/api/errors.py
index 5041828f18..eddd889778 100644
--- a/synapse/api/errors.py
+++ b/synapse/api/errors.py
@@ -36,7 +36,8 @@ class Codes(object):
CAPTCHA_NEEDED = "M_CAPTCHA_NEEDED"
CAPTCHA_INVALID = "M_CAPTCHA_INVALID"
MISSING_PARAM = "M_MISSING_PARAM",
- TOO_LARGE = "M_TOO_LARGE"
+ TOO_LARGE = "M_TOO_LARGE",
+ EXCLUSIVE = "M_EXCLUSIVE"
class CodeMessageException(RuntimeError):
diff --git a/synapse/handlers/directory.py b/synapse/handlers/directory.py
index 842f075fe0..4c15e57fa6 100644
--- a/synapse/handlers/directory.py
+++ b/synapse/handlers/directory.py
@@ -37,24 +37,15 @@ class DirectoryHandler(BaseHandler):
)
@defer.inlineCallbacks
- def create_association(self, user_id, room_alias, room_id, servers=None):
-
- # TODO(erikj): Do auth.
+ def _create_association(self, room_alias, room_id, servers=None):
+ # general association creation for both human users and app services
if not self.hs.is_mine(room_alias):
raise SynapseError(400, "Room alias must be local")
# TODO(erikj): Change this.
# TODO(erikj): Add transactions.
-
# TODO(erikj): Check if there is a current association.
-
- is_claimed = yield self.is_alias_exclusive_to_appservices(room_alias)
- if is_claimed:
- raise SynapseError(
- 400, "This alias is reserved by an application service."
- )
-
if not servers:
servers = yield self.store.get_joined_hosts_for_room(room_id)
@@ -67,6 +58,33 @@ class DirectoryHandler(BaseHandler):
servers
)
+
+ @defer.inlineCallbacks
+ def create_association(self, user_id, room_alias, room_id, servers=None):
+ # association creation for human users
+ # TODO(erikj): Do user auth.
+
+ is_claimed = yield self.is_alias_exclusive_to_appservices(room_alias)
+ if is_claimed:
+ raise SynapseError(
+ 400, "This alias is reserved by an application service.",
+ errcode=Codes.EXCLUSIVE
+ )
+ yield self._create_association(room_alias, room_id, servers)
+
+
+ @defer.inlineCallbacks
+ def create_appservice_association(self, service, room_alias, room_id,
+ servers=None):
+ if not service.is_interested_in_alias(room_alias.to_string()):
+ raise SynapseError(
+ 400, "This application service has not reserved"
+ " this kind of alias.", errcode=Codes.EXCLUSIVE
+ )
+
+ # association creation for app services
+ yield self._create_association(room_alias, room_id, servers)
+
@defer.inlineCallbacks
def delete_association(self, user_id, room_alias):
# TODO Check if server admin
@@ -77,7 +95,8 @@ class DirectoryHandler(BaseHandler):
is_claimed = yield self.is_alias_exclusive_to_appservices(room_alias)
if is_claimed:
raise SynapseError(
- 400, "This alias is reserved by an application service."
+ 400, "This alias is reserved by an application service.",
+ errcode=Codes.EXCLUSIVE
)
room_id = yield self.store.delete_room_alias(room_alias)
diff --git a/synapse/rest/client/v1/directory.py b/synapse/rest/client/v1/directory.py
index 8f65efec5f..f7e910bb40 100644
--- a/synapse/rest/client/v1/directory.py
+++ b/synapse/rest/client/v1/directory.py
@@ -45,8 +45,6 @@ class ClientDirectoryServer(ClientV1RestServlet):
@defer.inlineCallbacks
def on_PUT(self, request, room_alias):
- user, client = yield self.auth.get_user_by_req(request)
-
content = _parse_json(request)
if not "room_id" in content:
raise SynapseError(400, "Missing room_id key",
@@ -70,16 +68,25 @@ class ClientDirectoryServer(ClientV1RestServlet):
dir_handler = self.handlers.directory_handler
try:
- user_id = user.to_string()
- yield dir_handler.create_association(
- user_id, room_alias, room_id, servers
+ # try to auth as a user
+ user, client = yield self.auth.get_user_by_req(request)
+ try:
+ user_id = user.to_string()
+ yield dir_handler.create_association(
+ user_id, room_alias, room_id, servers
+ )
+ yield dir_handler.send_room_alias_update_event(user_id, room_id)
+ except SynapseError as e:
+ raise e
+ except:
+ logger.exception("Failed to create association")
+ raise
+ except AuthError:
+ # try to auth as an application service
+ service = yield self.auth.get_appservice_by_req(request)
+ yield dir_handler.create_appservice_association(
+ service, room_alias, room_id, servers
)
- yield dir_handler.send_room_alias_update_event(user_id, room_id)
- except SynapseError as e:
- raise e
- except:
- logger.exception("Failed to create association")
- raise
defer.returnValue((200, {}))
|