Grant ASes the ability to create alias in their own namespace.

Add a new errcode type M_EXCLUSIVE when users try to create aliases inside
AS namespaces, and when ASes try to create aliases outside their own
namespace.
This commit is contained in:
Kegan Dougal 2015-02-06 10:57:14 +00:00
parent 0227618d3c
commit e426df8e10
4 changed files with 63 additions and 24 deletions

View file

@ -380,6 +380,18 @@ class Auth(object):
raise AuthError(403, "Unrecognised access token.", raise AuthError(403, "Unrecognised access token.",
errcode=Codes.UNKNOWN_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): def is_server_admin(self, user):
return self.store.is_server_admin(user) return self.store.is_server_admin(user)

View file

@ -36,7 +36,8 @@ class Codes(object):
CAPTCHA_NEEDED = "M_CAPTCHA_NEEDED" CAPTCHA_NEEDED = "M_CAPTCHA_NEEDED"
CAPTCHA_INVALID = "M_CAPTCHA_INVALID" CAPTCHA_INVALID = "M_CAPTCHA_INVALID"
MISSING_PARAM = "M_MISSING_PARAM", MISSING_PARAM = "M_MISSING_PARAM",
TOO_LARGE = "M_TOO_LARGE" TOO_LARGE = "M_TOO_LARGE",
EXCLUSIVE = "M_EXCLUSIVE"
class CodeMessageException(RuntimeError): class CodeMessageException(RuntimeError):

View file

@ -37,24 +37,15 @@ class DirectoryHandler(BaseHandler):
) )
@defer.inlineCallbacks @defer.inlineCallbacks
def create_association(self, user_id, room_alias, room_id, servers=None): def _create_association(self, room_alias, room_id, servers=None):
# general association creation for both human users and app services
# TODO(erikj): Do auth.
if not self.hs.is_mine(room_alias): if not self.hs.is_mine(room_alias):
raise SynapseError(400, "Room alias must be local") raise SynapseError(400, "Room alias must be local")
# TODO(erikj): Change this. # TODO(erikj): Change this.
# TODO(erikj): Add transactions. # TODO(erikj): Add transactions.
# TODO(erikj): Check if there is a current association. # 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: if not servers:
servers = yield self.store.get_joined_hosts_for_room(room_id) servers = yield self.store.get_joined_hosts_for_room(room_id)
@ -67,6 +58,33 @@ class DirectoryHandler(BaseHandler):
servers 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 @defer.inlineCallbacks
def delete_association(self, user_id, room_alias): def delete_association(self, user_id, room_alias):
# TODO Check if server admin # TODO Check if server admin
@ -77,7 +95,8 @@ class DirectoryHandler(BaseHandler):
is_claimed = yield self.is_alias_exclusive_to_appservices(room_alias) is_claimed = yield self.is_alias_exclusive_to_appservices(room_alias)
if is_claimed: if is_claimed:
raise SynapseError( 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) room_id = yield self.store.delete_room_alias(room_alias)

View file

@ -45,8 +45,6 @@ class ClientDirectoryServer(ClientV1RestServlet):
@defer.inlineCallbacks @defer.inlineCallbacks
def on_PUT(self, request, room_alias): def on_PUT(self, request, room_alias):
user, client = yield self.auth.get_user_by_req(request)
content = _parse_json(request) content = _parse_json(request)
if not "room_id" in content: if not "room_id" in content:
raise SynapseError(400, "Missing room_id key", raise SynapseError(400, "Missing room_id key",
@ -70,16 +68,25 @@ class ClientDirectoryServer(ClientV1RestServlet):
dir_handler = self.handlers.directory_handler dir_handler = self.handlers.directory_handler
try: try:
user_id = user.to_string() # try to auth as a user
yield dir_handler.create_association( user, client = yield self.auth.get_user_by_req(request)
user_id, room_alias, room_id, servers 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, {})) defer.returnValue((200, {}))