room.py 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481
  1. # Copyright 2016-2021 The Matrix.org Foundation C.I.C.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. """Contains functions for performing events on rooms."""
  15. import itertools
  16. import logging
  17. import math
  18. import random
  19. import string
  20. from collections import OrderedDict
  21. from typing import (
  22. TYPE_CHECKING,
  23. Any,
  24. Awaitable,
  25. Collection,
  26. Dict,
  27. List,
  28. Optional,
  29. Tuple,
  30. )
  31. from synapse.api.constants import (
  32. EventContentFields,
  33. EventTypes,
  34. GuestAccess,
  35. HistoryVisibility,
  36. JoinRules,
  37. Membership,
  38. RoomCreationPreset,
  39. RoomEncryptionAlgorithms,
  40. RoomTypes,
  41. )
  42. from synapse.api.errors import (
  43. AuthError,
  44. Codes,
  45. LimitExceededError,
  46. NotFoundError,
  47. StoreError,
  48. SynapseError,
  49. )
  50. from synapse.api.filtering import Filter
  51. from synapse.api.room_versions import KNOWN_ROOM_VERSIONS, RoomVersion
  52. from synapse.event_auth import validate_event_for_room_version
  53. from synapse.events import EventBase
  54. from synapse.events.utils import copy_power_levels_contents
  55. from synapse.rest.admin._base import assert_user_is_admin
  56. from synapse.storage.state import StateFilter
  57. from synapse.streams import EventSource
  58. from synapse.types import (
  59. JsonDict,
  60. MutableStateMap,
  61. Requester,
  62. RoomAlias,
  63. RoomID,
  64. RoomStreamToken,
  65. StateMap,
  66. StreamToken,
  67. UserID,
  68. create_requester,
  69. )
  70. from synapse.util import stringutils
  71. from synapse.util.async_helpers import Linearizer
  72. from synapse.util.caches.response_cache import ResponseCache
  73. from synapse.util.stringutils import parse_and_validate_server_name
  74. from synapse.visibility import filter_events_for_client
  75. if TYPE_CHECKING:
  76. from synapse.server import HomeServer
  77. logger = logging.getLogger(__name__)
  78. id_server_scheme = "https://"
  79. FIVE_MINUTES_IN_MS = 5 * 60 * 1000
  80. class RoomCreationHandler:
  81. def __init__(self, hs: "HomeServer"):
  82. self.store = hs.get_datastore()
  83. self.auth = hs.get_auth()
  84. self.clock = hs.get_clock()
  85. self.hs = hs
  86. self.spam_checker = hs.get_spam_checker()
  87. self.event_creation_handler = hs.get_event_creation_handler()
  88. self.room_member_handler = hs.get_room_member_handler()
  89. self._event_auth_handler = hs.get_event_auth_handler()
  90. self.config = hs.config
  91. self.request_ratelimiter = hs.get_request_ratelimiter()
  92. # Room state based off defined presets
  93. self._presets_dict: Dict[str, Dict[str, Any]] = {
  94. RoomCreationPreset.PRIVATE_CHAT: {
  95. "join_rules": JoinRules.INVITE,
  96. "history_visibility": HistoryVisibility.SHARED,
  97. "original_invitees_have_ops": False,
  98. "guest_can_join": True,
  99. "power_level_content_override": {"invite": 0},
  100. },
  101. RoomCreationPreset.TRUSTED_PRIVATE_CHAT: {
  102. "join_rules": JoinRules.INVITE,
  103. "history_visibility": HistoryVisibility.SHARED,
  104. "original_invitees_have_ops": True,
  105. "guest_can_join": True,
  106. "power_level_content_override": {"invite": 0},
  107. },
  108. RoomCreationPreset.PUBLIC_CHAT: {
  109. "join_rules": JoinRules.PUBLIC,
  110. "history_visibility": HistoryVisibility.SHARED,
  111. "original_invitees_have_ops": False,
  112. "guest_can_join": False,
  113. "power_level_content_override": {},
  114. },
  115. }
  116. # Modify presets to selectively enable encryption by default per homeserver config
  117. for preset_name, preset_config in self._presets_dict.items():
  118. encrypted = (
  119. preset_name
  120. in self.config.room.encryption_enabled_by_default_for_room_presets
  121. )
  122. preset_config["encrypted"] = encrypted
  123. self._replication = hs.get_replication_data_handler()
  124. # linearizer to stop two upgrades happening at once
  125. self._upgrade_linearizer = Linearizer("room_upgrade_linearizer")
  126. # If a user tries to update the same room multiple times in quick
  127. # succession, only process the first attempt and return its result to
  128. # subsequent requests
  129. self._upgrade_response_cache: ResponseCache[Tuple[str, str]] = ResponseCache(
  130. hs.get_clock(), "room_upgrade", timeout_ms=FIVE_MINUTES_IN_MS
  131. )
  132. self._server_notices_mxid = hs.config.servernotices.server_notices_mxid
  133. self.third_party_event_rules = hs.get_third_party_event_rules()
  134. async def upgrade_room(
  135. self, requester: Requester, old_room_id: str, new_version: RoomVersion
  136. ) -> str:
  137. """Replace a room with a new room with a different version
  138. Args:
  139. requester: the user requesting the upgrade
  140. old_room_id: the id of the room to be replaced
  141. new_version: the new room version to use
  142. Returns:
  143. the new room id
  144. Raises:
  145. ShadowBanError if the requester is shadow-banned.
  146. """
  147. await self.request_ratelimiter.ratelimit(requester)
  148. user_id = requester.user.to_string()
  149. # Check if this room is already being upgraded by another person
  150. for key in self._upgrade_response_cache.pending_result_cache:
  151. if key[0] == old_room_id and key[1] != user_id:
  152. # Two different people are trying to upgrade the same room.
  153. # Send the second an error.
  154. #
  155. # Note that this of course only gets caught if both users are
  156. # on the same homeserver.
  157. raise SynapseError(
  158. 400, "An upgrade for this room is currently in progress"
  159. )
  160. # Upgrade the room
  161. #
  162. # If this user has sent multiple upgrade requests for the same room
  163. # and one of them is not complete yet, cache the response and
  164. # return it to all subsequent requests
  165. ret = await self._upgrade_response_cache.wrap(
  166. (old_room_id, user_id),
  167. self._upgrade_room,
  168. requester,
  169. old_room_id,
  170. new_version, # args for _upgrade_room
  171. )
  172. return ret
  173. async def _upgrade_room(
  174. self, requester: Requester, old_room_id: str, new_version: RoomVersion
  175. ) -> str:
  176. """
  177. Args:
  178. requester: the user requesting the upgrade
  179. old_room_id: the id of the room to be replaced
  180. new_versions: the version to upgrade the room to
  181. Raises:
  182. ShadowBanError if the requester is shadow-banned.
  183. """
  184. user_id = requester.user.to_string()
  185. assert self.hs.is_mine_id(user_id), "User must be our own: %s" % (user_id,)
  186. # start by allocating a new room id
  187. r = await self.store.get_room(old_room_id)
  188. if r is None:
  189. raise NotFoundError("Unknown room id %s" % (old_room_id,))
  190. new_room_id = await self._generate_room_id(
  191. creator_id=user_id,
  192. is_public=r["is_public"],
  193. room_version=new_version,
  194. )
  195. logger.info("Creating new room %s to replace %s", new_room_id, old_room_id)
  196. # we create and auth the tombstone event before properly creating the new
  197. # room, to check our user has perms in the old room.
  198. (
  199. tombstone_event,
  200. tombstone_context,
  201. ) = await self.event_creation_handler.create_event(
  202. requester,
  203. {
  204. "type": EventTypes.Tombstone,
  205. "state_key": "",
  206. "room_id": old_room_id,
  207. "sender": user_id,
  208. "content": {
  209. "body": "This room has been replaced",
  210. "replacement_room": new_room_id,
  211. },
  212. },
  213. )
  214. old_room_version = await self.store.get_room_version(old_room_id)
  215. validate_event_for_room_version(old_room_version, tombstone_event)
  216. await self._event_auth_handler.check_auth_rules_from_context(
  217. old_room_version, tombstone_event, tombstone_context
  218. )
  219. await self.clone_existing_room(
  220. requester,
  221. old_room_id=old_room_id,
  222. new_room_id=new_room_id,
  223. new_room_version=new_version,
  224. tombstone_event_id=tombstone_event.event_id,
  225. )
  226. # now send the tombstone
  227. await self.event_creation_handler.handle_new_client_event(
  228. requester=requester,
  229. event=tombstone_event,
  230. context=tombstone_context,
  231. )
  232. old_room_state = await tombstone_context.get_current_state_ids()
  233. # We know the tombstone event isn't an outlier so it has current state.
  234. assert old_room_state is not None
  235. # update any aliases
  236. await self._move_aliases_to_new_room(
  237. requester, old_room_id, new_room_id, old_room_state
  238. )
  239. # Copy over user push rules, tags and migrate room directory state
  240. await self.room_member_handler.transfer_room_state_on_room_upgrade(
  241. old_room_id, new_room_id
  242. )
  243. # finally, shut down the PLs in the old room, and update them in the new
  244. # room.
  245. await self._update_upgraded_room_pls(
  246. requester,
  247. old_room_id,
  248. new_room_id,
  249. old_room_state,
  250. )
  251. return new_room_id
  252. async def _update_upgraded_room_pls(
  253. self,
  254. requester: Requester,
  255. old_room_id: str,
  256. new_room_id: str,
  257. old_room_state: StateMap[str],
  258. ) -> None:
  259. """Send updated power levels in both rooms after an upgrade
  260. Args:
  261. requester: the user requesting the upgrade
  262. old_room_id: the id of the room to be replaced
  263. new_room_id: the id of the replacement room
  264. old_room_state: the state map for the old room
  265. Raises:
  266. ShadowBanError if the requester is shadow-banned.
  267. """
  268. old_room_pl_event_id = old_room_state.get((EventTypes.PowerLevels, ""))
  269. if old_room_pl_event_id is None:
  270. logger.warning(
  271. "Not supported: upgrading a room with no PL event. Not setting PLs "
  272. "in old room."
  273. )
  274. return
  275. old_room_pl_state = await self.store.get_event(old_room_pl_event_id)
  276. # we try to stop regular users from speaking by setting the PL required
  277. # to send regular events and invites to 'Moderator' level. That's normally
  278. # 50, but if the default PL in a room is 50 or more, then we set the
  279. # required PL above that.
  280. pl_content = dict(old_room_pl_state.content)
  281. users_default = int(pl_content.get("users_default", 0))
  282. restricted_level = max(users_default + 1, 50)
  283. updated = False
  284. for v in ("invite", "events_default"):
  285. current = int(pl_content.get(v, 0))
  286. if current < restricted_level:
  287. logger.debug(
  288. "Setting level for %s in %s to %i (was %i)",
  289. v,
  290. old_room_id,
  291. restricted_level,
  292. current,
  293. )
  294. pl_content[v] = restricted_level
  295. updated = True
  296. else:
  297. logger.debug("Not setting level for %s (already %i)", v, current)
  298. if updated:
  299. try:
  300. await self.event_creation_handler.create_and_send_nonmember_event(
  301. requester,
  302. {
  303. "type": EventTypes.PowerLevels,
  304. "state_key": "",
  305. "room_id": old_room_id,
  306. "sender": requester.user.to_string(),
  307. "content": pl_content,
  308. },
  309. ratelimit=False,
  310. )
  311. except AuthError as e:
  312. logger.warning("Unable to update PLs in old room: %s", e)
  313. await self.event_creation_handler.create_and_send_nonmember_event(
  314. requester,
  315. {
  316. "type": EventTypes.PowerLevels,
  317. "state_key": "",
  318. "room_id": new_room_id,
  319. "sender": requester.user.to_string(),
  320. "content": old_room_pl_state.content,
  321. },
  322. ratelimit=False,
  323. )
  324. async def clone_existing_room(
  325. self,
  326. requester: Requester,
  327. old_room_id: str,
  328. new_room_id: str,
  329. new_room_version: RoomVersion,
  330. tombstone_event_id: str,
  331. ) -> None:
  332. """Populate a new room based on an old room
  333. Args:
  334. requester: the user requesting the upgrade
  335. old_room_id : the id of the room to be replaced
  336. new_room_id: the id to give the new room (should already have been
  337. created with _gemerate_room_id())
  338. new_room_version: the new room version to use
  339. tombstone_event_id: the ID of the tombstone event in the old room.
  340. """
  341. user_id = requester.user.to_string()
  342. if not await self.spam_checker.user_may_create_room(user_id):
  343. raise SynapseError(403, "You are not permitted to create rooms")
  344. creation_content: JsonDict = {
  345. "room_version": new_room_version.identifier,
  346. "predecessor": {"room_id": old_room_id, "event_id": tombstone_event_id},
  347. }
  348. # Check if old room was non-federatable
  349. # Get old room's create event
  350. old_room_create_event = await self.store.get_create_event_for_room(old_room_id)
  351. # Check if the create event specified a non-federatable room
  352. if not old_room_create_event.content.get(EventContentFields.FEDERATE, True):
  353. # If so, mark the new room as non-federatable as well
  354. creation_content[EventContentFields.FEDERATE] = False
  355. initial_state = {}
  356. # Replicate relevant room events
  357. types_to_copy: List[Tuple[str, Optional[str]]] = [
  358. (EventTypes.JoinRules, ""),
  359. (EventTypes.Name, ""),
  360. (EventTypes.Topic, ""),
  361. (EventTypes.RoomHistoryVisibility, ""),
  362. (EventTypes.GuestAccess, ""),
  363. (EventTypes.RoomAvatar, ""),
  364. (EventTypes.RoomEncryption, ""),
  365. (EventTypes.ServerACL, ""),
  366. (EventTypes.RelatedGroups, ""),
  367. (EventTypes.PowerLevels, ""),
  368. ]
  369. # If the old room was a space, copy over the room type and the rooms in
  370. # the space.
  371. if (
  372. old_room_create_event.content.get(EventContentFields.ROOM_TYPE)
  373. == RoomTypes.SPACE
  374. ):
  375. creation_content[EventContentFields.ROOM_TYPE] = RoomTypes.SPACE
  376. types_to_copy.append((EventTypes.SpaceChild, None))
  377. old_room_state_ids = await self.store.get_filtered_current_state_ids(
  378. old_room_id, StateFilter.from_types(types_to_copy)
  379. )
  380. # map from event_id to BaseEvent
  381. old_room_state_events = await self.store.get_events(old_room_state_ids.values())
  382. for k, old_event_id in old_room_state_ids.items():
  383. old_event = old_room_state_events.get(old_event_id)
  384. if old_event:
  385. # If the event is an space child event with empty content, it was
  386. # removed from the space and should be ignored.
  387. if k[0] == EventTypes.SpaceChild and not old_event.content:
  388. continue
  389. initial_state[k] = old_event.content
  390. # deep-copy the power-levels event before we start modifying it
  391. # note that if frozen_dicts are enabled, `power_levels` will be a frozen
  392. # dict so we can't just copy.deepcopy it.
  393. initial_state[
  394. (EventTypes.PowerLevels, "")
  395. ] = power_levels = copy_power_levels_contents(
  396. initial_state[(EventTypes.PowerLevels, "")]
  397. )
  398. # Resolve the minimum power level required to send any state event
  399. # We will give the upgrading user this power level temporarily (if necessary) such that
  400. # they are able to copy all of the state events over, then revert them back to their
  401. # original power level afterwards in _update_upgraded_room_pls
  402. # Copy over user power levels now as this will not be possible with >100PL users once
  403. # the room has been created
  404. # Calculate the minimum power level needed to clone the room
  405. event_power_levels = power_levels.get("events", {})
  406. if not isinstance(event_power_levels, dict):
  407. event_power_levels = {}
  408. state_default = power_levels.get("state_default", 50)
  409. try:
  410. state_default_int = int(state_default) # type: ignore[arg-type]
  411. except (TypeError, ValueError):
  412. state_default_int = 50
  413. ban = power_levels.get("ban", 50)
  414. try:
  415. ban = int(ban) # type: ignore[arg-type]
  416. except (TypeError, ValueError):
  417. ban = 50
  418. needed_power_level = max(
  419. state_default_int, ban, max(event_power_levels.values())
  420. )
  421. # Get the user's current power level, this matches the logic in get_user_power_level,
  422. # but without the entire state map.
  423. user_power_levels = power_levels.setdefault("users", {})
  424. if not isinstance(user_power_levels, dict):
  425. user_power_levels = {}
  426. users_default = power_levels.get("users_default", 0)
  427. current_power_level = user_power_levels.get(user_id, users_default)
  428. try:
  429. current_power_level_int = int(current_power_level) # type: ignore[arg-type]
  430. except (TypeError, ValueError):
  431. current_power_level_int = 0
  432. # Raise the requester's power level in the new room if necessary
  433. if current_power_level_int < needed_power_level:
  434. user_power_levels[user_id] = needed_power_level
  435. await self._send_events_for_new_room(
  436. requester,
  437. new_room_id,
  438. # we expect to override all the presets with initial_state, so this is
  439. # somewhat arbitrary.
  440. preset_config=RoomCreationPreset.PRIVATE_CHAT,
  441. invite_list=[],
  442. initial_state=initial_state,
  443. creation_content=creation_content,
  444. ratelimit=False,
  445. )
  446. # Transfer membership events
  447. old_room_member_state_ids = await self.store.get_filtered_current_state_ids(
  448. old_room_id, StateFilter.from_types([(EventTypes.Member, None)])
  449. )
  450. # map from event_id to BaseEvent
  451. old_room_member_state_events = await self.store.get_events(
  452. old_room_member_state_ids.values()
  453. )
  454. for old_event in old_room_member_state_events.values():
  455. # Only transfer ban events
  456. if (
  457. "membership" in old_event.content
  458. and old_event.content["membership"] == "ban"
  459. ):
  460. await self.room_member_handler.update_membership(
  461. requester,
  462. UserID.from_string(old_event.state_key),
  463. new_room_id,
  464. "ban",
  465. ratelimit=False,
  466. content=old_event.content,
  467. )
  468. # XXX invites/joins
  469. # XXX 3pid invites
  470. async def _move_aliases_to_new_room(
  471. self,
  472. requester: Requester,
  473. old_room_id: str,
  474. new_room_id: str,
  475. old_room_state: StateMap[str],
  476. ) -> None:
  477. # check to see if we have a canonical alias.
  478. canonical_alias_event = None
  479. canonical_alias_event_id = old_room_state.get((EventTypes.CanonicalAlias, ""))
  480. if canonical_alias_event_id:
  481. canonical_alias_event = await self.store.get_event(canonical_alias_event_id)
  482. await self.store.update_aliases_for_room(old_room_id, new_room_id)
  483. if not canonical_alias_event:
  484. return
  485. # If there is a canonical alias we need to update the one in the old
  486. # room and set one in the new one.
  487. old_canonical_alias_content = dict(canonical_alias_event.content)
  488. new_canonical_alias_content = {}
  489. canonical = canonical_alias_event.content.get("alias")
  490. if canonical and self.hs.is_mine_id(canonical):
  491. new_canonical_alias_content["alias"] = canonical
  492. old_canonical_alias_content.pop("alias", None)
  493. # We convert to a list as it will be a Tuple.
  494. old_alt_aliases = list(old_canonical_alias_content.get("alt_aliases", []))
  495. if old_alt_aliases:
  496. old_canonical_alias_content["alt_aliases"] = old_alt_aliases
  497. new_alt_aliases = new_canonical_alias_content.setdefault("alt_aliases", [])
  498. for alias in canonical_alias_event.content.get("alt_aliases", []):
  499. try:
  500. if self.hs.is_mine_id(alias):
  501. new_alt_aliases.append(alias)
  502. old_alt_aliases.remove(alias)
  503. except Exception:
  504. logger.info(
  505. "Invalid alias %s in canonical alias event %s",
  506. alias,
  507. canonical_alias_event_id,
  508. )
  509. if not old_alt_aliases:
  510. old_canonical_alias_content.pop("alt_aliases")
  511. # If a canonical alias event existed for the old room, fire a canonical
  512. # alias event for the new room with a copy of the information.
  513. try:
  514. await self.event_creation_handler.create_and_send_nonmember_event(
  515. requester,
  516. {
  517. "type": EventTypes.CanonicalAlias,
  518. "state_key": "",
  519. "room_id": old_room_id,
  520. "sender": requester.user.to_string(),
  521. "content": old_canonical_alias_content,
  522. },
  523. ratelimit=False,
  524. )
  525. except SynapseError as e:
  526. # again I'm not really expecting this to fail, but if it does, I'd rather
  527. # we returned the new room to the client at this point.
  528. logger.error("Unable to send updated alias events in old room: %s", e)
  529. try:
  530. await self.event_creation_handler.create_and_send_nonmember_event(
  531. requester,
  532. {
  533. "type": EventTypes.CanonicalAlias,
  534. "state_key": "",
  535. "room_id": new_room_id,
  536. "sender": requester.user.to_string(),
  537. "content": new_canonical_alias_content,
  538. },
  539. ratelimit=False,
  540. )
  541. except SynapseError as e:
  542. # again I'm not really expecting this to fail, but if it does, I'd rather
  543. # we returned the new room to the client at this point.
  544. logger.error("Unable to send updated alias events in new room: %s", e)
  545. async def create_room(
  546. self,
  547. requester: Requester,
  548. config: JsonDict,
  549. ratelimit: bool = True,
  550. creator_join_profile: Optional[JsonDict] = None,
  551. ) -> Tuple[dict, int]:
  552. """Creates a new room.
  553. Args:
  554. requester:
  555. The user who requested the room creation.
  556. config : A dict of configuration options.
  557. ratelimit: set to False to disable the rate limiter
  558. creator_join_profile:
  559. Set to override the displayname and avatar for the creating
  560. user in this room. If unset, displayname and avatar will be
  561. derived from the user's profile. If set, should contain the
  562. values to go in the body of the 'join' event (typically
  563. `avatar_url` and/or `displayname`.
  564. Returns:
  565. First, a dict containing the keys `room_id` and, if an alias
  566. was, requested, `room_alias`. Secondly, the stream_id of the
  567. last persisted event.
  568. Raises:
  569. SynapseError if the room ID couldn't be stored, or something went
  570. horribly wrong.
  571. ResourceLimitError if server is blocked to some resource being
  572. exceeded
  573. """
  574. user_id = requester.user.to_string()
  575. await self.auth.check_auth_blocking(requester=requester)
  576. if (
  577. self._server_notices_mxid is not None
  578. and requester.user.to_string() == self._server_notices_mxid
  579. ):
  580. # allow the server notices mxid to create rooms
  581. is_requester_admin = True
  582. else:
  583. is_requester_admin = await self.auth.is_server_admin(requester.user)
  584. # Let the third party rules modify the room creation config if needed, or abort
  585. # the room creation entirely with an exception.
  586. await self.third_party_event_rules.on_create_room(
  587. requester, config, is_requester_admin=is_requester_admin
  588. )
  589. invite_3pid_list = config.get("invite_3pid", [])
  590. invite_list = config.get("invite", [])
  591. if not is_requester_admin and not (
  592. await self.spam_checker.user_may_create_room(user_id)
  593. and await self.spam_checker.user_may_create_room_with_invites(
  594. user_id,
  595. invite_list,
  596. invite_3pid_list,
  597. )
  598. ):
  599. raise SynapseError(403, "You are not permitted to create rooms")
  600. if ratelimit:
  601. await self.request_ratelimiter.ratelimit(requester)
  602. room_version_id = config.get(
  603. "room_version", self.config.server.default_room_version.identifier
  604. )
  605. if not isinstance(room_version_id, str):
  606. raise SynapseError(400, "room_version must be a string", Codes.BAD_JSON)
  607. room_version = KNOWN_ROOM_VERSIONS.get(room_version_id)
  608. if room_version is None:
  609. raise SynapseError(
  610. 400,
  611. "Your homeserver does not support this room version",
  612. Codes.UNSUPPORTED_ROOM_VERSION,
  613. )
  614. room_alias = None
  615. if "room_alias_name" in config:
  616. for wchar in string.whitespace:
  617. if wchar in config["room_alias_name"]:
  618. raise SynapseError(400, "Invalid characters in room alias")
  619. room_alias = RoomAlias(config["room_alias_name"], self.hs.hostname)
  620. mapping = await self.store.get_association_from_room_alias(room_alias)
  621. if mapping:
  622. raise SynapseError(400, "Room alias already taken", Codes.ROOM_IN_USE)
  623. for i in invite_list:
  624. try:
  625. uid = UserID.from_string(i)
  626. parse_and_validate_server_name(uid.domain)
  627. except Exception:
  628. raise SynapseError(400, "Invalid user_id: %s" % (i,))
  629. if (invite_list or invite_3pid_list) and requester.shadow_banned:
  630. # We randomly sleep a bit just to annoy the requester.
  631. await self.clock.sleep(random.randint(1, 10))
  632. # Allow the request to go through, but remove any associated invites.
  633. invite_3pid_list = []
  634. invite_list = []
  635. if invite_list or invite_3pid_list:
  636. try:
  637. # If there are invites in the request, see if the ratelimiting settings
  638. # allow that number of invites to be sent from the current user.
  639. await self.room_member_handler.ratelimit_multiple_invites(
  640. requester,
  641. room_id=None,
  642. n_invites=len(invite_list) + len(invite_3pid_list),
  643. update=False,
  644. )
  645. except LimitExceededError:
  646. raise SynapseError(400, "Cannot invite so many users at once")
  647. await self.event_creation_handler.assert_accepted_privacy_policy(requester)
  648. power_level_content_override = config.get("power_level_content_override")
  649. if (
  650. power_level_content_override
  651. and "users" in power_level_content_override
  652. and user_id not in power_level_content_override["users"]
  653. ):
  654. raise SynapseError(
  655. 400,
  656. "Not a valid power_level_content_override: 'users' did not contain %s"
  657. % (user_id,),
  658. )
  659. visibility = config.get("visibility", None)
  660. is_public = visibility == "public"
  661. room_id = await self._generate_room_id(
  662. creator_id=user_id,
  663. is_public=is_public,
  664. room_version=room_version,
  665. )
  666. # Check whether this visibility value is blocked by a third party module
  667. allowed_by_third_party_rules = await (
  668. self.third_party_event_rules.check_visibility_can_be_modified(
  669. room_id, visibility
  670. )
  671. )
  672. if not allowed_by_third_party_rules:
  673. raise SynapseError(403, "Room visibility value not allowed.")
  674. if is_public:
  675. if not self.config.roomdirectory.is_publishing_room_allowed(
  676. user_id, room_id, room_alias
  677. ):
  678. # Let's just return a generic message, as there may be all sorts of
  679. # reasons why we said no. TODO: Allow configurable error messages
  680. # per alias creation rule?
  681. raise SynapseError(403, "Not allowed to publish room")
  682. directory_handler = self.hs.get_directory_handler()
  683. if room_alias:
  684. await directory_handler.create_association(
  685. requester=requester,
  686. room_id=room_id,
  687. room_alias=room_alias,
  688. servers=[self.hs.hostname],
  689. check_membership=False,
  690. )
  691. preset_config = config.get(
  692. "preset",
  693. RoomCreationPreset.PRIVATE_CHAT
  694. if visibility == "private"
  695. else RoomCreationPreset.PUBLIC_CHAT,
  696. )
  697. raw_initial_state = config.get("initial_state", [])
  698. initial_state = OrderedDict()
  699. for val in raw_initial_state:
  700. initial_state[(val["type"], val.get("state_key", ""))] = val["content"]
  701. creation_content = config.get("creation_content", {})
  702. # override any attempt to set room versions via the creation_content
  703. creation_content["room_version"] = room_version.identifier
  704. last_stream_id = await self._send_events_for_new_room(
  705. requester,
  706. room_id,
  707. preset_config=preset_config,
  708. invite_list=invite_list,
  709. initial_state=initial_state,
  710. creation_content=creation_content,
  711. room_alias=room_alias,
  712. power_level_content_override=power_level_content_override,
  713. creator_join_profile=creator_join_profile,
  714. ratelimit=ratelimit,
  715. )
  716. if "name" in config:
  717. name = config["name"]
  718. (
  719. _,
  720. last_stream_id,
  721. ) = await self.event_creation_handler.create_and_send_nonmember_event(
  722. requester,
  723. {
  724. "type": EventTypes.Name,
  725. "room_id": room_id,
  726. "sender": user_id,
  727. "state_key": "",
  728. "content": {"name": name},
  729. },
  730. ratelimit=False,
  731. )
  732. if "topic" in config:
  733. topic = config["topic"]
  734. (
  735. _,
  736. last_stream_id,
  737. ) = await self.event_creation_handler.create_and_send_nonmember_event(
  738. requester,
  739. {
  740. "type": EventTypes.Topic,
  741. "room_id": room_id,
  742. "sender": user_id,
  743. "state_key": "",
  744. "content": {"topic": topic},
  745. },
  746. ratelimit=False,
  747. )
  748. # we avoid dropping the lock between invites, as otherwise joins can
  749. # start coming in and making the createRoom slow.
  750. #
  751. # we also don't need to check the requester's shadow-ban here, as we
  752. # have already done so above (and potentially emptied invite_list).
  753. with (await self.room_member_handler.member_linearizer.queue((room_id,))):
  754. content = {}
  755. is_direct = config.get("is_direct", None)
  756. if is_direct:
  757. content["is_direct"] = is_direct
  758. for invitee in invite_list:
  759. (
  760. _,
  761. last_stream_id,
  762. ) = await self.room_member_handler.update_membership_locked(
  763. requester,
  764. UserID.from_string(invitee),
  765. room_id,
  766. "invite",
  767. ratelimit=False,
  768. content=content,
  769. new_room=True,
  770. )
  771. for invite_3pid in invite_3pid_list:
  772. id_server = invite_3pid["id_server"]
  773. id_access_token = invite_3pid.get("id_access_token") # optional
  774. address = invite_3pid["address"]
  775. medium = invite_3pid["medium"]
  776. # Note that do_3pid_invite can raise a ShadowBanError, but this was
  777. # handled above by emptying invite_3pid_list.
  778. last_stream_id = await self.hs.get_room_member_handler().do_3pid_invite(
  779. room_id,
  780. requester.user,
  781. medium,
  782. address,
  783. id_server,
  784. requester,
  785. txn_id=None,
  786. id_access_token=id_access_token,
  787. )
  788. result = {"room_id": room_id}
  789. if room_alias:
  790. result["room_alias"] = room_alias.to_string()
  791. # Always wait for room creation to propagate before returning
  792. await self._replication.wait_for_stream_position(
  793. self.hs.config.worker.events_shard_config.get_instance(room_id),
  794. "events",
  795. last_stream_id,
  796. )
  797. return result, last_stream_id
  798. async def _send_events_for_new_room(
  799. self,
  800. creator: Requester,
  801. room_id: str,
  802. preset_config: str,
  803. invite_list: List[str],
  804. initial_state: MutableStateMap,
  805. creation_content: JsonDict,
  806. room_alias: Optional[RoomAlias] = None,
  807. power_level_content_override: Optional[JsonDict] = None,
  808. creator_join_profile: Optional[JsonDict] = None,
  809. ratelimit: bool = True,
  810. ) -> int:
  811. """Sends the initial events into a new room.
  812. `power_level_content_override` doesn't apply when initial state has
  813. power level state event content.
  814. Returns:
  815. The stream_id of the last event persisted.
  816. """
  817. creator_id = creator.user.to_string()
  818. event_keys = {"room_id": room_id, "sender": creator_id, "state_key": ""}
  819. def create(etype: str, content: JsonDict, **kwargs: Any) -> JsonDict:
  820. e = {"type": etype, "content": content}
  821. e.update(event_keys)
  822. e.update(kwargs)
  823. return e
  824. async def send(etype: str, content: JsonDict, **kwargs: Any) -> int:
  825. event = create(etype, content, **kwargs)
  826. logger.debug("Sending %s in new room", etype)
  827. # Allow these events to be sent even if the user is shadow-banned to
  828. # allow the room creation to complete.
  829. (
  830. _,
  831. last_stream_id,
  832. ) = await self.event_creation_handler.create_and_send_nonmember_event(
  833. creator,
  834. event,
  835. ratelimit=False,
  836. ignore_shadow_ban=True,
  837. )
  838. return last_stream_id
  839. try:
  840. config = self._presets_dict[preset_config]
  841. except KeyError:
  842. raise SynapseError(
  843. 400, f"'{preset_config}' is not a valid preset", errcode=Codes.BAD_JSON
  844. )
  845. creation_content.update({"creator": creator_id})
  846. await send(etype=EventTypes.Create, content=creation_content)
  847. logger.debug("Sending %s in new room", EventTypes.Member)
  848. await self.room_member_handler.update_membership(
  849. creator,
  850. creator.user,
  851. room_id,
  852. "join",
  853. ratelimit=ratelimit,
  854. content=creator_join_profile,
  855. new_room=True,
  856. )
  857. # We treat the power levels override specially as this needs to be one
  858. # of the first events that get sent into a room.
  859. pl_content = initial_state.pop((EventTypes.PowerLevels, ""), None)
  860. if pl_content is not None:
  861. last_sent_stream_id = await send(
  862. etype=EventTypes.PowerLevels, content=pl_content
  863. )
  864. else:
  865. power_level_content: JsonDict = {
  866. "users": {creator_id: 100},
  867. "users_default": 0,
  868. "events": {
  869. EventTypes.Name: 50,
  870. EventTypes.PowerLevels: 100,
  871. EventTypes.RoomHistoryVisibility: 100,
  872. EventTypes.CanonicalAlias: 50,
  873. EventTypes.RoomAvatar: 50,
  874. EventTypes.Tombstone: 100,
  875. EventTypes.ServerACL: 100,
  876. EventTypes.RoomEncryption: 100,
  877. },
  878. "events_default": 0,
  879. "state_default": 50,
  880. "ban": 50,
  881. "kick": 50,
  882. "redact": 50,
  883. "invite": 50,
  884. "historical": 100,
  885. }
  886. if config["original_invitees_have_ops"]:
  887. for invitee in invite_list:
  888. power_level_content["users"][invitee] = 100
  889. # Power levels overrides are defined per chat preset
  890. power_level_content.update(config["power_level_content_override"])
  891. if power_level_content_override:
  892. power_level_content.update(power_level_content_override)
  893. last_sent_stream_id = await send(
  894. etype=EventTypes.PowerLevels, content=power_level_content
  895. )
  896. if room_alias and (EventTypes.CanonicalAlias, "") not in initial_state:
  897. last_sent_stream_id = await send(
  898. etype=EventTypes.CanonicalAlias,
  899. content={"alias": room_alias.to_string()},
  900. )
  901. if (EventTypes.JoinRules, "") not in initial_state:
  902. last_sent_stream_id = await send(
  903. etype=EventTypes.JoinRules, content={"join_rule": config["join_rules"]}
  904. )
  905. if (EventTypes.RoomHistoryVisibility, "") not in initial_state:
  906. last_sent_stream_id = await send(
  907. etype=EventTypes.RoomHistoryVisibility,
  908. content={"history_visibility": config["history_visibility"]},
  909. )
  910. if config["guest_can_join"]:
  911. if (EventTypes.GuestAccess, "") not in initial_state:
  912. last_sent_stream_id = await send(
  913. etype=EventTypes.GuestAccess,
  914. content={EventContentFields.GUEST_ACCESS: GuestAccess.CAN_JOIN},
  915. )
  916. for (etype, state_key), content in initial_state.items():
  917. last_sent_stream_id = await send(
  918. etype=etype, state_key=state_key, content=content
  919. )
  920. if config["encrypted"]:
  921. last_sent_stream_id = await send(
  922. etype=EventTypes.RoomEncryption,
  923. state_key="",
  924. content={"algorithm": RoomEncryptionAlgorithms.DEFAULT},
  925. )
  926. return last_sent_stream_id
  927. async def _generate_room_id(
  928. self,
  929. creator_id: str,
  930. is_public: bool,
  931. room_version: RoomVersion,
  932. ) -> str:
  933. # autogen room IDs and try to create it. We may clash, so just
  934. # try a few times till one goes through, giving up eventually.
  935. attempts = 0
  936. while attempts < 5:
  937. try:
  938. random_string = stringutils.random_string(18)
  939. gen_room_id = RoomID(random_string, self.hs.hostname).to_string()
  940. await self.store.store_room(
  941. room_id=gen_room_id,
  942. room_creator_user_id=creator_id,
  943. is_public=is_public,
  944. room_version=room_version,
  945. )
  946. return gen_room_id
  947. except StoreError:
  948. attempts += 1
  949. raise StoreError(500, "Couldn't generate a room ID.")
  950. class RoomContextHandler:
  951. def __init__(self, hs: "HomeServer"):
  952. self.hs = hs
  953. self.auth = hs.get_auth()
  954. self.store = hs.get_datastore()
  955. self.storage = hs.get_storage()
  956. self.state_store = self.storage.state
  957. async def get_event_context(
  958. self,
  959. requester: Requester,
  960. room_id: str,
  961. event_id: str,
  962. limit: int,
  963. event_filter: Optional[Filter],
  964. use_admin_priviledge: bool = False,
  965. ) -> Optional[JsonDict]:
  966. """Retrieves events, pagination tokens and state around a given event
  967. in a room.
  968. Args:
  969. requester
  970. room_id
  971. event_id
  972. limit: The maximum number of events to return in total
  973. (excluding state).
  974. event_filter: the filter to apply to the events returned
  975. (excluding the target event_id)
  976. use_admin_priviledge: if `True`, return all events, regardless
  977. of whether `user` has access to them. To be used **ONLY**
  978. from the admin API.
  979. Returns:
  980. dict, or None if the event isn't found
  981. """
  982. user = requester.user
  983. if use_admin_priviledge:
  984. await assert_user_is_admin(self.auth, requester.user)
  985. before_limit = math.floor(limit / 2.0)
  986. after_limit = limit - before_limit
  987. users = await self.store.get_users_in_room(room_id)
  988. is_peeking = user.to_string() not in users
  989. async def filter_evts(events: List[EventBase]) -> List[EventBase]:
  990. if use_admin_priviledge:
  991. return events
  992. return await filter_events_for_client(
  993. self.storage, user.to_string(), events, is_peeking=is_peeking
  994. )
  995. event = await self.store.get_event(
  996. event_id, get_prev_content=True, allow_none=True
  997. )
  998. if not event:
  999. return None
  1000. filtered = await filter_evts([event])
  1001. if not filtered:
  1002. raise AuthError(403, "You don't have permission to access that event.")
  1003. results = await self.store.get_events_around(
  1004. room_id, event_id, before_limit, after_limit, event_filter
  1005. )
  1006. if event_filter:
  1007. results["events_before"] = event_filter.filter(results["events_before"])
  1008. results["events_after"] = event_filter.filter(results["events_after"])
  1009. results["events_before"] = await filter_evts(results["events_before"])
  1010. results["events_after"] = await filter_evts(results["events_after"])
  1011. # filter_evts can return a pruned event in case the user is allowed to see that
  1012. # there's something there but not see the content, so use the event that's in
  1013. # `filtered` rather than the event we retrieved from the datastore.
  1014. results["event"] = filtered[0]
  1015. if results["events_after"]:
  1016. last_event_id = results["events_after"][-1].event_id
  1017. else:
  1018. last_event_id = event_id
  1019. if event_filter and event_filter.lazy_load_members:
  1020. state_filter = StateFilter.from_lazy_load_member_list(
  1021. ev.sender
  1022. for ev in itertools.chain(
  1023. results["events_before"],
  1024. (results["event"],),
  1025. results["events_after"],
  1026. )
  1027. )
  1028. else:
  1029. state_filter = StateFilter.all()
  1030. # XXX: why do we return the state as of the last event rather than the
  1031. # first? Shouldn't we be consistent with /sync?
  1032. # https://github.com/matrix-org/matrix-doc/issues/687
  1033. state = await self.state_store.get_state_for_events(
  1034. [last_event_id], state_filter=state_filter
  1035. )
  1036. state_events = list(state[last_event_id].values())
  1037. if event_filter:
  1038. state_events = event_filter.filter(state_events)
  1039. results["state"] = await filter_evts(state_events)
  1040. # We use a dummy token here as we only care about the room portion of
  1041. # the token, which we replace.
  1042. token = StreamToken.START
  1043. results["start"] = await token.copy_and_replace(
  1044. "room_key", results["start"]
  1045. ).to_string(self.store)
  1046. results["end"] = await token.copy_and_replace(
  1047. "room_key", results["end"]
  1048. ).to_string(self.store)
  1049. return results
  1050. class RoomEventSource(EventSource[RoomStreamToken, EventBase]):
  1051. def __init__(self, hs: "HomeServer"):
  1052. self.store = hs.get_datastore()
  1053. async def get_new_events(
  1054. self,
  1055. user: UserID,
  1056. from_key: RoomStreamToken,
  1057. limit: Optional[int],
  1058. room_ids: Collection[str],
  1059. is_guest: bool,
  1060. explicit_room_id: Optional[str] = None,
  1061. ) -> Tuple[List[EventBase], RoomStreamToken]:
  1062. # We just ignore the key for now.
  1063. to_key = self.get_current_key()
  1064. if from_key.topological:
  1065. logger.warning("Stream has topological part!!!! %r", from_key)
  1066. from_key = RoomStreamToken(None, from_key.stream)
  1067. app_service = self.store.get_app_service_by_user_id(user.to_string())
  1068. if app_service:
  1069. # We no longer support AS users using /sync directly.
  1070. # See https://github.com/matrix-org/matrix-doc/issues/1144
  1071. raise NotImplementedError()
  1072. else:
  1073. room_events = await self.store.get_membership_changes_for_user(
  1074. user.to_string(), from_key, to_key
  1075. )
  1076. room_to_events = await self.store.get_room_events_stream_for_rooms(
  1077. room_ids=room_ids,
  1078. from_key=from_key,
  1079. to_key=to_key,
  1080. limit=limit or 10,
  1081. order="ASC",
  1082. )
  1083. events = list(room_events)
  1084. events.extend(e for evs, _ in room_to_events.values() for e in evs)
  1085. events.sort(key=lambda e: e.internal_metadata.order)
  1086. if limit:
  1087. events[:] = events[:limit]
  1088. if events:
  1089. end_key = events[-1].internal_metadata.after
  1090. else:
  1091. end_key = to_key
  1092. return events, end_key
  1093. def get_current_key(self) -> RoomStreamToken:
  1094. return self.store.get_room_max_token()
  1095. def get_current_key_for_room(self, room_id: str) -> Awaitable[str]:
  1096. return self.store.get_room_events_max_id(room_id)
  1097. class RoomShutdownHandler:
  1098. DEFAULT_MESSAGE = (
  1099. "Sharing illegal content on this server is not permitted and rooms in"
  1100. " violation will be blocked."
  1101. )
  1102. DEFAULT_ROOM_NAME = "Content Violation Notification"
  1103. def __init__(self, hs: "HomeServer"):
  1104. self.hs = hs
  1105. self.room_member_handler = hs.get_room_member_handler()
  1106. self._room_creation_handler = hs.get_room_creation_handler()
  1107. self._replication = hs.get_replication_data_handler()
  1108. self.event_creation_handler = hs.get_event_creation_handler()
  1109. self.state = hs.get_state_handler()
  1110. self.store = hs.get_datastore()
  1111. async def shutdown_room(
  1112. self,
  1113. room_id: str,
  1114. requester_user_id: str,
  1115. new_room_user_id: Optional[str] = None,
  1116. new_room_name: Optional[str] = None,
  1117. message: Optional[str] = None,
  1118. block: bool = False,
  1119. ) -> dict:
  1120. """
  1121. Shuts down a room. Moves all local users and room aliases automatically
  1122. to a new room if `new_room_user_id` is set. Otherwise local users only
  1123. leave the room without any information.
  1124. The new room will be created with the user specified by the
  1125. `new_room_user_id` parameter as room administrator and will contain a
  1126. message explaining what happened. Users invited to the new room will
  1127. have power level `-10` by default, and thus be unable to speak.
  1128. The local server will only have the power to move local user and room
  1129. aliases to the new room. Users on other servers will be unaffected.
  1130. Args:
  1131. room_id: The ID of the room to shut down.
  1132. requester_user_id:
  1133. User who requested the action and put the room on the
  1134. blocking list.
  1135. new_room_user_id:
  1136. If set, a new room will be created with this user ID
  1137. as the creator and admin, and all users in the old room will be
  1138. moved into that room. If not set, no new room will be created
  1139. and the users will just be removed from the old room.
  1140. new_room_name:
  1141. A string representing the name of the room that new users will
  1142. be invited to. Defaults to `Content Violation Notification`
  1143. message:
  1144. A string containing the first message that will be sent as
  1145. `new_room_user_id` in the new room. Ideally this will clearly
  1146. convey why the original room was shut down.
  1147. Defaults to `Sharing illegal content on this server is not
  1148. permitted and rooms in violation will be blocked.`
  1149. block:
  1150. If set to `true`, this room will be added to a blocking list,
  1151. preventing future attempts to join the room. Defaults to `false`.
  1152. Returns: a dict containing the following keys:
  1153. kicked_users: An array of users (`user_id`) that were kicked.
  1154. failed_to_kick_users:
  1155. An array of users (`user_id`) that that were not kicked.
  1156. local_aliases:
  1157. An array of strings representing the local aliases that were
  1158. migrated from the old room to the new.
  1159. new_room_id: A string representing the room ID of the new room.
  1160. """
  1161. if not new_room_name:
  1162. new_room_name = self.DEFAULT_ROOM_NAME
  1163. if not message:
  1164. message = self.DEFAULT_MESSAGE
  1165. if not RoomID.is_valid(room_id):
  1166. raise SynapseError(400, "%s is not a legal room ID" % (room_id,))
  1167. if not await self.store.get_room(room_id):
  1168. raise NotFoundError("Unknown room id %s" % (room_id,))
  1169. # This will work even if the room is already blocked, but that is
  1170. # desirable in case the first attempt at blocking the room failed below.
  1171. if block:
  1172. await self.store.block_room(room_id, requester_user_id)
  1173. if new_room_user_id is not None:
  1174. if not self.hs.is_mine_id(new_room_user_id):
  1175. raise SynapseError(
  1176. 400, "User must be our own: %s" % (new_room_user_id,)
  1177. )
  1178. room_creator_requester = create_requester(
  1179. new_room_user_id, authenticated_entity=requester_user_id
  1180. )
  1181. info, stream_id = await self._room_creation_handler.create_room(
  1182. room_creator_requester,
  1183. config={
  1184. "preset": RoomCreationPreset.PUBLIC_CHAT,
  1185. "name": new_room_name,
  1186. "power_level_content_override": {"users_default": -10},
  1187. },
  1188. ratelimit=False,
  1189. )
  1190. new_room_id = info["room_id"]
  1191. logger.info(
  1192. "Shutting down room %r, joining to new room: %r", room_id, new_room_id
  1193. )
  1194. # We now wait for the create room to come back in via replication so
  1195. # that we can assume that all the joins/invites have propagated before
  1196. # we try and auto join below.
  1197. await self._replication.wait_for_stream_position(
  1198. self.hs.config.worker.events_shard_config.get_instance(new_room_id),
  1199. "events",
  1200. stream_id,
  1201. )
  1202. else:
  1203. new_room_id = None
  1204. logger.info("Shutting down room %r", room_id)
  1205. users = await self.store.get_users_in_room(room_id)
  1206. kicked_users = []
  1207. failed_to_kick_users = []
  1208. for user_id in users:
  1209. if not self.hs.is_mine_id(user_id):
  1210. continue
  1211. logger.info("Kicking %r from %r...", user_id, room_id)
  1212. try:
  1213. # Kick users from room
  1214. target_requester = create_requester(
  1215. user_id, authenticated_entity=requester_user_id
  1216. )
  1217. _, stream_id = await self.room_member_handler.update_membership(
  1218. requester=target_requester,
  1219. target=target_requester.user,
  1220. room_id=room_id,
  1221. action=Membership.LEAVE,
  1222. content={},
  1223. ratelimit=False,
  1224. require_consent=False,
  1225. )
  1226. # Wait for leave to come in over replication before trying to forget.
  1227. await self._replication.wait_for_stream_position(
  1228. self.hs.config.worker.events_shard_config.get_instance(room_id),
  1229. "events",
  1230. stream_id,
  1231. )
  1232. await self.room_member_handler.forget(target_requester.user, room_id)
  1233. # Join users to new room
  1234. if new_room_user_id:
  1235. await self.room_member_handler.update_membership(
  1236. requester=target_requester,
  1237. target=target_requester.user,
  1238. room_id=new_room_id,
  1239. action=Membership.JOIN,
  1240. content={},
  1241. ratelimit=False,
  1242. require_consent=False,
  1243. )
  1244. kicked_users.append(user_id)
  1245. except Exception:
  1246. logger.exception(
  1247. "Failed to leave old room and join new room for %r", user_id
  1248. )
  1249. failed_to_kick_users.append(user_id)
  1250. # Send message in new room and move aliases
  1251. if new_room_user_id:
  1252. await self.event_creation_handler.create_and_send_nonmember_event(
  1253. room_creator_requester,
  1254. {
  1255. "type": "m.room.message",
  1256. "content": {"body": message, "msgtype": "m.text"},
  1257. "room_id": new_room_id,
  1258. "sender": new_room_user_id,
  1259. },
  1260. ratelimit=False,
  1261. )
  1262. aliases_for_room = await self.store.get_aliases_for_room(room_id)
  1263. await self.store.update_aliases_for_room(
  1264. room_id, new_room_id, requester_user_id
  1265. )
  1266. else:
  1267. aliases_for_room = []
  1268. return {
  1269. "kicked_users": kicked_users,
  1270. "failed_to_kick_users": failed_to_kick_users,
  1271. "local_aliases": aliases_for_room,
  1272. "new_room_id": new_room_id,
  1273. }