directory.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014-2016 OpenMarket Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. from twisted.internet import defer
  16. from synapse.api.errors import AuthError, SynapseError, Codes
  17. from synapse.types import RoomAlias
  18. from synapse.http.servlet import parse_json_object_from_request
  19. from .base import ClientV1RestServlet, client_path_patterns
  20. import logging
  21. logger = logging.getLogger(__name__)
  22. def register_servlets(hs, http_server):
  23. ClientDirectoryServer(hs).register(http_server)
  24. ClientDirectoryListServer(hs).register(http_server)
  25. ClientAppserviceDirectoryListServer(hs).register(http_server)
  26. class ClientDirectoryServer(ClientV1RestServlet):
  27. PATTERNS = client_path_patterns("/directory/room/(?P<room_alias>[^/]*)$")
  28. def __init__(self, hs):
  29. super(ClientDirectoryServer, self).__init__(hs)
  30. self.store = hs.get_datastore()
  31. self.handlers = hs.get_handlers()
  32. @defer.inlineCallbacks
  33. def on_GET(self, request, room_alias):
  34. room_alias = RoomAlias.from_string(room_alias)
  35. dir_handler = self.handlers.directory_handler
  36. res = yield dir_handler.get_association(room_alias)
  37. defer.returnValue((200, res))
  38. @defer.inlineCallbacks
  39. def on_PUT(self, request, room_alias):
  40. content = parse_json_object_from_request(request)
  41. if "room_id" not in content:
  42. raise SynapseError(400, "Missing room_id key",
  43. errcode=Codes.BAD_JSON)
  44. logger.debug("Got content: %s", content)
  45. room_alias = RoomAlias.from_string(room_alias)
  46. logger.debug("Got room name: %s", room_alias.to_string())
  47. room_id = content["room_id"]
  48. servers = content["servers"] if "servers" in content else None
  49. logger.debug("Got room_id: %s", room_id)
  50. logger.debug("Got servers: %s", servers)
  51. # TODO(erikj): Check types.
  52. room = yield self.store.get_room(room_id)
  53. if room is None:
  54. raise SynapseError(400, "Room does not exist")
  55. dir_handler = self.handlers.directory_handler
  56. try:
  57. # try to auth as a user
  58. requester = yield self.auth.get_user_by_req(request)
  59. try:
  60. user_id = requester.user.to_string()
  61. yield dir_handler.create_association(
  62. user_id, room_alias, room_id, servers
  63. )
  64. yield dir_handler.send_room_alias_update_event(
  65. requester,
  66. user_id,
  67. room_id
  68. )
  69. except SynapseError as e:
  70. raise e
  71. except Exception:
  72. logger.exception("Failed to create association")
  73. raise
  74. except AuthError:
  75. # try to auth as an application service
  76. service = yield self.auth.get_appservice_by_req(request)
  77. yield dir_handler.create_appservice_association(
  78. service, room_alias, room_id, servers
  79. )
  80. logger.info(
  81. "Application service at %s created alias %s pointing to %s",
  82. service.url,
  83. room_alias.to_string(),
  84. room_id
  85. )
  86. defer.returnValue((200, {}))
  87. @defer.inlineCallbacks
  88. def on_DELETE(self, request, room_alias):
  89. dir_handler = self.handlers.directory_handler
  90. try:
  91. service = yield self.auth.get_appservice_by_req(request)
  92. room_alias = RoomAlias.from_string(room_alias)
  93. yield dir_handler.delete_appservice_association(
  94. service, room_alias
  95. )
  96. logger.info(
  97. "Application service at %s deleted alias %s",
  98. service.url,
  99. room_alias.to_string()
  100. )
  101. defer.returnValue((200, {}))
  102. except AuthError:
  103. # fallback to default user behaviour if they aren't an AS
  104. pass
  105. requester = yield self.auth.get_user_by_req(request)
  106. user = requester.user
  107. room_alias = RoomAlias.from_string(room_alias)
  108. yield dir_handler.delete_association(
  109. requester, user.to_string(), room_alias
  110. )
  111. logger.info(
  112. "User %s deleted alias %s",
  113. user.to_string(),
  114. room_alias.to_string()
  115. )
  116. defer.returnValue((200, {}))
  117. class ClientDirectoryListServer(ClientV1RestServlet):
  118. PATTERNS = client_path_patterns("/directory/list/room/(?P<room_id>[^/]*)$")
  119. def __init__(self, hs):
  120. super(ClientDirectoryListServer, self).__init__(hs)
  121. self.store = hs.get_datastore()
  122. self.handlers = hs.get_handlers()
  123. @defer.inlineCallbacks
  124. def on_GET(self, request, room_id):
  125. room = yield self.store.get_room(room_id)
  126. if room is None:
  127. raise SynapseError(400, "Unknown room")
  128. defer.returnValue((200, {
  129. "visibility": "public" if room["is_public"] else "private"
  130. }))
  131. @defer.inlineCallbacks
  132. def on_PUT(self, request, room_id):
  133. requester = yield self.auth.get_user_by_req(request)
  134. content = parse_json_object_from_request(request)
  135. visibility = content.get("visibility", "public")
  136. yield self.handlers.directory_handler.edit_published_room_list(
  137. requester, room_id, visibility,
  138. )
  139. defer.returnValue((200, {}))
  140. @defer.inlineCallbacks
  141. def on_DELETE(self, request, room_id):
  142. requester = yield self.auth.get_user_by_req(request)
  143. yield self.handlers.directory_handler.edit_published_room_list(
  144. requester, room_id, "private",
  145. )
  146. defer.returnValue((200, {}))
  147. class ClientAppserviceDirectoryListServer(ClientV1RestServlet):
  148. PATTERNS = client_path_patterns(
  149. "/directory/list/appservice/(?P<network_id>[^/]*)/(?P<room_id>[^/]*)$"
  150. )
  151. def __init__(self, hs):
  152. super(ClientAppserviceDirectoryListServer, self).__init__(hs)
  153. self.store = hs.get_datastore()
  154. self.handlers = hs.get_handlers()
  155. def on_PUT(self, request, network_id, room_id):
  156. content = parse_json_object_from_request(request)
  157. visibility = content.get("visibility", "public")
  158. return self._edit(request, network_id, room_id, visibility)
  159. def on_DELETE(self, request, network_id, room_id):
  160. return self._edit(request, network_id, room_id, "private")
  161. @defer.inlineCallbacks
  162. def _edit(self, request, network_id, room_id, visibility):
  163. requester = yield self.auth.get_user_by_req(request)
  164. if not requester.app_service:
  165. raise AuthError(
  166. 403, "Only appservices can edit the appservice published room list"
  167. )
  168. yield self.handlers.directory_handler.edit_published_appservice_room_list(
  169. requester.app_service.id, network_id, room_id, visibility,
  170. )
  171. defer.returnValue((200, {}))