Пример #1
0
    def _test(self, input):
        a = copy_power_levels_contents(input)

        self.assertEqual(a["ban"], 50)
        self.assertEqual(a["events"]["m.room.name"], 100)

        # make sure that changing the copy changes the copy and not the orig
        a["ban"] = 10
        a["events"]["m.room.power_levels"] = 20

        self.assertEqual(input["ban"], 50)
        self.assertEqual(input["events"]["m.room.power_levels"], 100)
Пример #2
0
    def clone_existing_room(
        self,
        requester: Requester,
        old_room_id: str,
        new_room_id: str,
        new_room_version: RoomVersion,
        tombstone_event_id: str,
    ):
        """Populate a new room based on an old room

        Args:
            requester: the user requesting the upgrade
            old_room_id : the id of the room to be replaced
            new_room_id: the id to give the new room (should already have been
                created with _gemerate_room_id())
            new_room_version: the new room version to use
            tombstone_event_id: the ID of the tombstone event in the old room.
        Returns:
            Deferred
        """
        user_id = requester.user.to_string()

        if not self.spam_checker.user_may_create_room(user_id):
            raise SynapseError(403, "You are not permitted to create rooms")

        creation_content = {
            "room_version": new_room_version.identifier,
            "predecessor": {
                "room_id": old_room_id,
                "event_id": tombstone_event_id
            },
        }

        # Check if old room was non-federatable

        # Get old room's create event
        old_room_create_event = yield self.store.get_create_event_for_room(
            old_room_id)

        # Check if the create event specified a non-federatable room
        if not old_room_create_event.content.get("m.federate", True):
            # If so, mark the new room as non-federatable as well
            creation_content["m.federate"] = False

        initial_state = dict()

        # Replicate relevant room events
        types_to_copy = (
            (EventTypes.JoinRules, ""),
            (EventTypes.Name, ""),
            (EventTypes.Topic, ""),
            (EventTypes.RoomHistoryVisibility, ""),
            (EventTypes.GuestAccess, ""),
            (EventTypes.RoomAvatar, ""),
            (EventTypes.RoomEncryption, ""),
            (EventTypes.ServerACL, ""),
            (EventTypes.RelatedGroups, ""),
            (EventTypes.PowerLevels, ""),
        )

        old_room_state_ids = yield self.store.get_filtered_current_state_ids(
            old_room_id, StateFilter.from_types(types_to_copy))
        # map from event_id to BaseEvent
        old_room_state_events = yield self.store.get_events(
            old_room_state_ids.values())

        for k, old_event_id in iteritems(old_room_state_ids):
            old_event = old_room_state_events.get(old_event_id)
            if old_event:
                initial_state[k] = old_event.content

        # deep-copy the power-levels event before we start modifying it
        # note that if frozen_dicts are enabled, `power_levels` will be a frozen
        # dict so we can't just copy.deepcopy it.
        initial_state[(EventTypes.PowerLevels,
                       "")] = power_levels = copy_power_levels_contents(
                           initial_state[(EventTypes.PowerLevels, "")])

        # Resolve the minimum power level required to send any state event
        # We will give the upgrading user this power level temporarily (if necessary) such that
        # they are able to copy all of the state events over, then revert them back to their
        # original power level afterwards in _update_upgraded_room_pls

        # Copy over user power levels now as this will not be possible with >100PL users once
        # the room has been created

        # Calculate the minimum power level needed to clone the room
        event_power_levels = power_levels.get("events", {})
        state_default = power_levels.get("state_default", 0)
        ban = power_levels.get("ban")
        needed_power_level = max(state_default, ban,
                                 max(event_power_levels.values()))

        # Raise the requester's power level in the new room if necessary
        current_power_level = power_levels["users"][user_id]
        if current_power_level < needed_power_level:
            power_levels["users"][user_id] = needed_power_level

        yield self._send_events_for_new_room(
            requester,
            new_room_id,
            # we expect to override all the presets with initial_state, so this is
            # somewhat arbitrary.
            preset_config=RoomCreationPreset.PRIVATE_CHAT,
            invite_list=[],
            initial_state=initial_state,
            creation_content=creation_content,
        )

        # Transfer membership events
        old_room_member_state_ids = yield self.store.get_filtered_current_state_ids(
            old_room_id, StateFilter.from_types([(EventTypes.Member, None)]))

        # map from event_id to BaseEvent
        old_room_member_state_events = yield self.store.get_events(
            old_room_member_state_ids.values())
        for k, old_event in iteritems(old_room_member_state_events):
            # Only transfer ban events
            if ("membership" in old_event.content
                    and old_event.content["membership"] == "ban"):
                yield self.room_member_handler.update_membership(
                    requester,
                    UserID.from_string(old_event["state_key"]),
                    new_room_id,
                    "ban",
                    ratelimit=False,
                    content=old_event.content,
                )
Пример #3
0
    def _update_upgraded_room_pls(
        self,
        requester: Requester,
        old_room_id: str,
        new_room_id: str,
        old_room_state: StateMap[str],
    ):
        """Send updated power levels in both rooms after an upgrade

        Args:
            requester: the user requesting the upgrade
            old_room_id: the id of the room to be replaced
            new_room_id: the id of the replacement room
            old_room_state: the state map for the old room

        Returns:
            Deferred
        """
        old_room_pl_event_id = old_room_state.get((EventTypes.PowerLevels, ""))

        if old_room_pl_event_id is None:
            logger.warning(
                "Not supported: upgrading a room with no PL event. Not setting PLs "
                "in old room.")
            return

        old_room_pl_state = yield self.store.get_event(old_room_pl_event_id)

        # we try to stop regular users from speaking by setting the PL required
        # to send regular events and invites to 'Moderator' level. That's normally
        # 50, but if the default PL in a room is 50 or more, then we set the
        # required PL above that.

        pl_content = dict(old_room_pl_state.content)
        users_default = int(pl_content.get("users_default", 0))
        restricted_level = max(users_default + 1, 50)

        updated = False
        for v in ("invite", "events_default"):
            current = int(pl_content.get(v, 0))
            if current < restricted_level:
                logger.info(
                    "Setting level for %s in %s to %i (was %i)",
                    v,
                    old_room_id,
                    restricted_level,
                    current,
                )
                pl_content[v] = restricted_level
                updated = True
            else:
                logger.info("Not setting level for %s (already %i)", v,
                            current)

        if updated:
            try:
                yield self.event_creation_handler.create_and_send_nonmember_event(
                    requester,
                    {
                        "type": EventTypes.PowerLevels,
                        "state_key": "",
                        "room_id": old_room_id,
                        "sender": requester.user.to_string(),
                        "content": pl_content,
                    },
                    ratelimit=False,
                )
            except AuthError as e:
                logger.warning("Unable to update PLs in old room: %s", e)

        new_pl_content = copy_power_levels_contents(old_room_pl_state.content)

        # pre-msc2260 rooms may not have the right setting for aliases. If no other
        # value is set, set it now.
        events_default = new_pl_content.get("events_default", 0)
        new_pl_content.setdefault("events",
                                  {}).setdefault(EventTypes.Aliases,
                                                 events_default)

        logger.info("Setting correct PLs in new room to %s", new_pl_content)
        yield self.event_creation_handler.create_and_send_nonmember_event(
            requester,
            {
                "type": EventTypes.PowerLevels,
                "state_key": "",
                "room_id": new_room_id,
                "sender": requester.user.to_string(),
                "content": new_pl_content,
            },
            ratelimit=False,
        )