groups_local.py 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2017 Vector Creations 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 SynapseError
  17. import logging
  18. logger = logging.getLogger(__name__)
  19. # TODO: Validate attestations
  20. # TODO: Allow users to "knock" or simpkly join depending on rules
  21. # TODO: is_priveged flag to users and is_public to users and rooms
  22. # TODO: Roles
  23. # TODO: Audit log for admins (profile updates, membership changes, users who tried
  24. # to join but were rejected, etc)
  25. # TODO: Flairs
  26. # TODO: Add group memebership /sync
  27. def _create_rerouter(name):
  28. def f(self, group_id, *args, **kwargs):
  29. if self.is_mine_id(group_id):
  30. return getattr(self.groups_server_handler, name)(
  31. group_id, *args, **kwargs
  32. )
  33. repl_layer = self.hs.get_replication_layer()
  34. return getattr(repl_layer, name)(group_id, *args, **kwargs)
  35. return f
  36. class GroupsLocalHandler(object):
  37. def __init__(self, hs):
  38. self.hs = hs
  39. self.store = hs.get_datastore()
  40. self.room_list_handler = hs.get_room_list_handler()
  41. self.groups_server_handler = hs.get_groups_server_handler()
  42. self.auth = hs.get_auth()
  43. self.clock = hs.get_clock()
  44. self.keyring = hs.get_keyring()
  45. self.is_mine_id = hs.is_mine_id
  46. self.signing_key = hs.config.signing_key[0]
  47. self.server_name = hs.hostname
  48. self.attestations = hs.get_groups_attestation_signing()
  49. # Ensure attestations get renewed
  50. hs.get_groups_attestation_renewer()
  51. get_group_profile = _create_rerouter("get_group_profile")
  52. get_rooms_in_group = _create_rerouter("get_rooms_in_group")
  53. update_group_summary_room = _create_rerouter("update_group_summary_room")
  54. delete_group_summary_room = _create_rerouter("delete_group_summary_room")
  55. update_group_category = _create_rerouter("update_group_category")
  56. delete_group_category = _create_rerouter("delete_group_category")
  57. get_group_category = _create_rerouter("get_group_category")
  58. get_group_categories = _create_rerouter("get_group_categories")
  59. update_group_summary_user = _create_rerouter("update_group_summary_user")
  60. delete_group_summary_user = _create_rerouter("delete_group_summary_user")
  61. update_group_role = _create_rerouter("update_group_role")
  62. delete_group_role = _create_rerouter("delete_group_role")
  63. get_group_role = _create_rerouter("get_group_role")
  64. get_group_roles = _create_rerouter("get_group_roles")
  65. @defer.inlineCallbacks
  66. def get_group_summary(self, group_id, requester_user_id):
  67. if self.is_mine_id(group_id):
  68. res = yield self.groups_server_handler.get_group_summary(
  69. group_id, requester_user_id
  70. )
  71. defer.returnValue(res)
  72. repl_layer = self.hs.get_replication_layer()
  73. res = yield repl_layer.get_group_summary(group_id, requester_user_id)
  74. chunk = res["users_section"]["users"]
  75. valid_users = []
  76. for entry in chunk:
  77. g_user_id = entry["user_id"]
  78. attestation = entry.pop("attestation")
  79. try:
  80. yield self.attestations.verify_attestation(
  81. attestation,
  82. group_id=group_id,
  83. user_id=g_user_id,
  84. )
  85. valid_users.append(entry)
  86. except Exception as e:
  87. logger.info("Failed to verify user is in group: %s", e)
  88. res["users_section"]["users"] = valid_users
  89. res["users_section"]["users"].sort(key=lambda e: e.get("order", 0))
  90. res["rooms_section"]["rooms"].sort(key=lambda e: e.get("order", 0))
  91. defer.returnValue(res)
  92. def create_group(self, group_id, user_id, content):
  93. logger.info("Asking to create group with ID: %r", group_id)
  94. if self.is_mine_id(group_id):
  95. return self.groups_server_handler.create_group(
  96. group_id, user_id, content
  97. )
  98. repl_layer = self.hs.get_replication_layer()
  99. return repl_layer.create_group(group_id, user_id, content) # TODO
  100. def add_room(self, group_id, user_id, room_id, content):
  101. if self.is_mine_id(group_id):
  102. return self.groups_server_handler.add_room(
  103. group_id, user_id, room_id, content
  104. )
  105. repl_layer = self.hs.get_replication_layer()
  106. return repl_layer.add_room_to_group(group_id, user_id, room_id, content) # TODO
  107. @defer.inlineCallbacks
  108. def get_users_in_group(self, group_id, requester_user_id):
  109. if self.is_mine_id(group_id):
  110. res = yield self.groups_server_handler.get_users_in_group(
  111. group_id, requester_user_id
  112. )
  113. defer.returnValue(res)
  114. repl_layer = self.hs.get_replication_layer()
  115. res = yield repl_layer.get_users_in_group(group_id, requester_user_id) # TODO
  116. chunk = res["chunk"]
  117. valid_entries = []
  118. for entry in chunk:
  119. g_user_id = entry["user_id"]
  120. attestation = entry.pop("attestation")
  121. try:
  122. yield self.attestations.verify_attestation(
  123. attestation,
  124. group_id=group_id,
  125. user_id=g_user_id,
  126. )
  127. valid_entries.append(entry)
  128. except Exception as e:
  129. logger.info("Failed to verify user is in group: %s", e)
  130. res["chunk"] = valid_entries
  131. defer.returnValue(res)
  132. @defer.inlineCallbacks
  133. def join_group(self, group_id, user_id, content):
  134. raise NotImplementedError() # TODO
  135. @defer.inlineCallbacks
  136. def accept_invite(self, group_id, user_id, content):
  137. if self.is_mine_id(group_id):
  138. yield self.groups_server_handler.accept_invite(
  139. group_id, user_id, content
  140. )
  141. local_attestation = None
  142. remote_attestation = None
  143. else:
  144. local_attestation = self.attestations.create_attestation(group_id, user_id)
  145. content["attestation"] = local_attestation
  146. repl_layer = self.hs.get_replication_layer()
  147. res = yield repl_layer.accept_group_invite(group_id, user_id, content)
  148. remote_attestation = res["attestation"]
  149. yield self.attestations.verify_attestation(
  150. remote_attestation,
  151. group_id=group_id,
  152. user_id=user_id,
  153. )
  154. yield self.store.register_user_group_membership(
  155. group_id, user_id,
  156. membership="join",
  157. is_admin=False,
  158. local_attestation=local_attestation,
  159. remote_attestation=remote_attestation,
  160. )
  161. defer.returnValue({})
  162. @defer.inlineCallbacks
  163. def invite(self, group_id, user_id, requester_user_id, config):
  164. content = {
  165. "requester_user_id": requester_user_id,
  166. "config": config,
  167. }
  168. if self.is_mine_id(group_id):
  169. res = yield self.groups_server_handler.invite_to_group(
  170. group_id, user_id, requester_user_id, content,
  171. )
  172. else:
  173. repl_layer = self.hs.get_replication_layer()
  174. res = yield repl_layer.invite_to_group(
  175. group_id, user_id, content,
  176. )
  177. defer.returnValue(res)
  178. @defer.inlineCallbacks
  179. def on_invite(self, group_id, user_id, content):
  180. # TODO: Support auto join and rejection
  181. if not self.is_mine_id(user_id):
  182. raise SynapseError(400, "User not on this server")
  183. local_profile = {}
  184. if "profile" in content:
  185. if "name" in content["profile"]:
  186. local_profile["name"] = content["profile"]["name"]
  187. if "avatar_url" in content["profile"]:
  188. local_profile["avatar_url"] = content["profile"]["avatar_url"]
  189. yield self.store.register_user_group_membership(
  190. group_id, user_id,
  191. membership="invite",
  192. content={"profile": local_profile, "inviter": content["inviter"]},
  193. )
  194. defer.returnValue({"state": "invite"})
  195. @defer.inlineCallbacks
  196. def remove_user_from_group(self, group_id, user_id, requester_user_id, content):
  197. if user_id == requester_user_id:
  198. yield self.store.register_user_group_membership(
  199. group_id, user_id,
  200. membership="leave",
  201. )
  202. # TODO: Should probably remember that we tried to leave so that we can
  203. # retry if the group server is currently down.
  204. if self.is_mine_id(group_id):
  205. res = yield self.groups_server_handler.remove_user_from_group(
  206. group_id, user_id, requester_user_id, content,
  207. )
  208. else:
  209. content["requester_user_id"] = requester_user_id
  210. repl_layer = self.hs.get_replication_layer()
  211. res = yield repl_layer.remove_user_from_group(
  212. group_id, user_id, content
  213. ) # TODO
  214. defer.returnValue(res)
  215. @defer.inlineCallbacks
  216. def user_removed_from_group(self, group_id, user_id, content):
  217. # TODO: Check if user in group
  218. yield self.store.register_user_group_membership(
  219. group_id, user_id,
  220. membership="leave",
  221. )
  222. @defer.inlineCallbacks
  223. def get_joined_groups(self, user_id):
  224. group_ids = yield self.store.get_joined_groups(user_id)
  225. defer.returnValue({"groups": group_ids})