示例#1
0
        def delete_expired_event_txn(txn):
            # Delete the expiry timestamp associated with this event from the database.
            self._delete_event_expiry_txn(txn, event_id)

            if not event:
                # If we can't find the event, log a warning and delete the expiry date
                # from the database so that we don't try to expire it again in the
                # future.
                logger.warning(
                    "Can't expire event %s because we don't have it.", event_id
                )
                return

            # Prune the event's dict then convert it to JSON.
            pruned_json = frozendict_json_encoder.encode(
                prune_event_dict(event.room_version, event.get_dict())
            )

            # Update the event_json table to replace the event's JSON with the pruned
            # JSON.
            self._censor_event_txn(txn, event.event_id, pruned_json)

            # We need to invalidate the event cache entry for this event because we
            # changed its content in the database. We can't call
            # self._invalidate_cache_and_stream because self.get_event_cache isn't of the
            # right type.
            txn.call_after(self._get_event_cache.invalidate, (event.event_id,))
            # Send that invalidation to replication so that other workers also invalidate
            # the event cache.
            self._send_invalidation_to_replication(
                txn, "_get_event_cache", (event.event_id,)
            )
示例#2
0
    def handle_new_client_event(
        self,
        requester,
        event,
        context,
        ratelimit=True,
        extra_users=[],
    ):
        """Processes a new event. This includes checking auth, persisting it,
        notifying users, sending to remote servers, etc.

        If called from a worker will hit out to the master process for final
        processing.

        Args:
            requester (Requester)
            event (FrozenEvent)
            context (EventContext)
            ratelimit (bool)
            extra_users (list(UserID)): Any extra users to notify about event
        """

        try:
            yield self.auth.check_from_context(event, context)
        except AuthError as err:
            logger.warn("Denying new event %r because %s", event, err)
            raise err

        # Ensure that we can round trip before trying to persist in db
        try:
            dump = frozendict_json_encoder.encode(event.content)
            simplejson.loads(dump)
        except Exception:
            logger.exception("Failed to encode content: %r", event.content)
            raise

        yield self.action_generator.handle_push_actions_for_event(
            event, context)

        try:
            # If we're a worker we need to hit out to the master.
            if self.config.worker_app:
                yield send_event_to_master(
                    self.http_client,
                    host=self.config.worker_replication_host,
                    port=self.config.worker_replication_http_port,
                    requester=requester,
                    event=event,
                    context=context,
                    ratelimit=ratelimit,
                    extra_users=extra_users,
                )
                return

            yield self.persist_and_notify_client_event(
                requester,
                event,
                context,
                ratelimit=ratelimit,
                extra_users=extra_users,
            )
        except:  # noqa: E722, as we reraise the exception this is fine.
            # Ensure that we actually remove the entries in the push actions
            # staging area, if we calculated them.
            preserve_fn(self.store.remove_push_actions_from_staging)(
                event.event_id)
            raise
示例#3
0
    async def handle_new_client_event(self,
                                      requester,
                                      event,
                                      context,
                                      ratelimit=True,
                                      extra_users=[]) -> int:
        """Processes a new event. This includes checking auth, persisting it,
        notifying users, sending to remote servers, etc.

        If called from a worker will hit out to the master process for final
        processing.

        Args:
            requester (Requester)
            event (FrozenEvent)
            context (EventContext)
            ratelimit (bool)
            extra_users (list(UserID)): Any extra users to notify about event

        Return:
            The stream_id of the persisted event.
        """

        if event.is_state() and (event.type, event.state_key) == (
                EventTypes.Create,
                "",
        ):
            room_version = event.content.get("room_version",
                                             RoomVersions.V1.identifier)
        else:
            room_version = await self.store.get_room_version_id(event.room_id)

        event_allowed = await self.third_party_event_rules.check_event_allowed(
            event, context)
        if not event_allowed:
            raise SynapseError(403,
                               "This event is not allowed in this context",
                               Codes.FORBIDDEN)

        if event.internal_metadata.is_out_of_band_membership():
            # the only sort of out-of-band-membership events we expect to see here
            # are invite rejections we have generated ourselves.
            assert event.type == EventTypes.Member
            assert event.content["membership"] == Membership.LEAVE
        else:
            try:
                await self.auth.check_from_context(room_version, event,
                                                   context)
            except AuthError as err:
                logger.warning("Denying new event %r because %s", event, err)
                raise err

        # Ensure that we can round trip before trying to persist in db
        try:
            dump = frozendict_json_encoder.encode(event.content)
            json.loads(dump)
        except Exception:
            logger.exception("Failed to encode content: %r", event.content)
            raise

        await self.action_generator.handle_push_actions_for_event(
            event, context)

        # reraise does not allow inlineCallbacks to preserve the stacktrace, so we
        # hack around with a try/finally instead.
        success = False
        try:
            # If we're a worker we need to hit out to the master.
            if not self._is_event_writer:
                result = await self.send_event(
                    instance_name=self.config.worker.writers.events,
                    event_id=event.event_id,
                    store=self.store,
                    requester=requester,
                    event=event,
                    context=context,
                    ratelimit=ratelimit,
                    extra_users=extra_users,
                )
                stream_id = result["stream_id"]
                event.internal_metadata.stream_ordering = stream_id
                success = True
                return stream_id

            stream_id = await self.persist_and_notify_client_event(
                requester,
                event,
                context,
                ratelimit=ratelimit,
                extra_users=extra_users)

            success = True
            return stream_id
        finally:
            if not success:
                # Ensure that we actually remove the entries in the push actions
                # staging area, if we calculated them.
                run_in_background(self.store.remove_push_actions_from_staging,
                                  event.event_id)
示例#4
0
文件: message.py 项目: syamgk/synapse
    def handle_new_client_event(
        self, requester, event, context, ratelimit=True, extra_users=[]
    ):
        """Processes a new event. This includes checking auth, persisting it,
        notifying users, sending to remote servers, etc.

        If called from a worker will hit out to the master process for final
        processing.

        Args:
            requester (Requester)
            event (FrozenEvent)
            context (EventContext)
            ratelimit (bool)
            extra_users (list(UserID)): Any extra users to notify about event
        """

        if event.is_state() and (event.type, event.state_key) == (
            EventTypes.Create,
            "",
        ):
            room_version = event.content.get("room_version", RoomVersions.V1.identifier)
        else:
            room_version = yield self.store.get_room_version(event.room_id)

        event_allowed = yield self.third_party_event_rules.check_event_allowed(
            event, context
        )
        if not event_allowed:
            raise SynapseError(
                403, "This event is not allowed in this context", Codes.FORBIDDEN
            )

        try:
            yield self.auth.check_from_context(room_version, event, context)
        except AuthError as err:
            logger.warning("Denying new event %r because %s", event, err)
            raise err

        # Ensure that we can round trip before trying to persist in db
        try:
            dump = frozendict_json_encoder.encode(event.content)
            json.loads(dump)
        except Exception:
            logger.exception("Failed to encode content: %r", event.content)
            raise

        yield self.action_generator.handle_push_actions_for_event(event, context)

        # reraise does not allow inlineCallbacks to preserve the stacktrace, so we
        # hack around with a try/finally instead.
        success = False
        try:
            # If we're a worker we need to hit out to the master.
            if self.config.worker_app:
                yield self.send_event_to_master(
                    event_id=event.event_id,
                    store=self.store,
                    requester=requester,
                    event=event,
                    context=context,
                    ratelimit=ratelimit,
                    extra_users=extra_users,
                )
                success = True
                return

            yield self.persist_and_notify_client_event(
                requester, event, context, ratelimit=ratelimit, extra_users=extra_users
            )

            success = True
        finally:
            if not success:
                # Ensure that we actually remove the entries in the push actions
                # staging area, if we calculated them.
                run_in_background(
                    self.store.remove_push_actions_from_staging, event.event_id
                )
示例#5
0
    def handle_new_client_event(
        self,
        requester,
        event,
        context,
        ratelimit=True,
        extra_users=[],
    ):
        """Processes a new event. This includes checking auth, persisting it,
        notifying users, sending to remote servers, etc.

        If called from a worker will hit out to the master process for final
        processing.

        Args:
            requester (Requester)
            event (FrozenEvent)
            context (EventContext)
            ratelimit (bool)
            extra_users (list(UserID)): Any extra users to notify about event
        """

        if event.is_state() and (event.type, event.state_key) == (EventTypes.Create, ""):
            room_version = event.content.get(
                "room_version", RoomVersions.V1.identifier
            )
        else:
            room_version = yield self.store.get_room_version(event.room_id)

        try:
            yield self.auth.check_from_context(room_version, event, context)
        except AuthError as err:
            logger.warn("Denying new event %r because %s", event, err)
            raise err

        # Ensure that we can round trip before trying to persist in db
        try:
            dump = frozendict_json_encoder.encode(event.content)
            json.loads(dump)
        except Exception:
            logger.exception("Failed to encode content: %r", event.content)
            raise

        yield self.action_generator.handle_push_actions_for_event(
            event, context
        )

        # reraise does not allow inlineCallbacks to preserve the stacktrace, so we
        # hack around with a try/finally instead.
        success = False
        try:
            # If we're a worker we need to hit out to the master.
            if self.config.worker_app:
                yield self.send_event_to_master(
                    event_id=event.event_id,
                    store=self.store,
                    requester=requester,
                    event=event,
                    context=context,
                    ratelimit=ratelimit,
                    extra_users=extra_users,
                )
                success = True
                return

            yield self.persist_and_notify_client_event(
                requester,
                event,
                context,
                ratelimit=ratelimit,
                extra_users=extra_users,
            )

            success = True
        finally:
            if not success:
                # Ensure that we actually remove the entries in the push actions
                # staging area, if we calculated them.
                run_in_background(
                    self.store.remove_push_actions_from_staging,
                    event.event_id,
                )
示例#6
0
    async def _censor_redactions(self):
        """Censors all redactions older than the configured period that haven't
        been censored yet.

        By censor we mean update the event_json table with the redacted event.
        """

        if self.hs.config.redaction_retention_period is None:
            return

        if not (
            await self.db_pool.updates.has_completed_background_update(
                "redactions_have_censored_ts_idx"
            )
        ):
            # We don't want to run this until the appropriate index has been
            # created.
            return

        before_ts = self._clock.time_msec() - self.hs.config.redaction_retention_period

        # We fetch all redactions that:
        #   1. point to an event we have,
        #   2. has a received_ts from before the cut off, and
        #   3. we haven't yet censored.
        #
        # This is limited to 100 events to ensure that we don't try and do too
        # much at once. We'll get called again so this should eventually catch
        # up.
        sql = """
            SELECT redactions.event_id, redacts FROM redactions
            LEFT JOIN events AS original_event ON (
                redacts = original_event.event_id
            )
            WHERE NOT have_censored
            AND redactions.received_ts <= ?
            ORDER BY redactions.received_ts ASC
            LIMIT ?
        """

        rows = await self.db_pool.execute(
            "_censor_redactions_fetch", None, sql, before_ts, 100
        )

        updates = []

        for redaction_id, event_id in rows:
            redaction_event = await self.get_event(redaction_id, allow_none=True)
            original_event = await self.get_event(
                event_id, allow_rejected=True, allow_none=True
            )

            # The SQL above ensures that we have both the redaction and
            # original event, so if the `get_event` calls return None it
            # means that the redaction wasn't allowed. Either way we know that
            # the result won't change so we mark the fact that we've checked.
            if (
                redaction_event
                and original_event
                and original_event.internal_metadata.is_redacted()
            ):
                # Redaction was allowed
                pruned_json = frozendict_json_encoder.encode(
                    prune_event_dict(
                        original_event.room_version, original_event.get_dict()
                    )
                )
            else:
                # Redaction wasn't allowed
                pruned_json = None

            updates.append((redaction_id, event_id, pruned_json))

        def _update_censor_txn(txn):
            for redaction_id, event_id, pruned_json in updates:
                if pruned_json:
                    self._censor_event_txn(txn, event_id, pruned_json)

                self.db_pool.simple_update_one_txn(
                    txn,
                    table="redactions",
                    keyvalues={"event_id": redaction_id},
                    updatevalues={"have_censored": True},
                )

        await self.db_pool.runInteraction("_update_censor_txn", _update_censor_txn)
示例#7
0
文件: message.py 项目: rubo77/synapse
    def handle_new_client_event(
        self,
        requester,
        event,
        context,
        ratelimit=True,
        extra_users=[],
    ):
        """Processes a new event. This includes checking auth, persisting it,
        notifying users, sending to remote servers, etc.

        If called from a worker will hit out to the master process for final
        processing.

        Args:
            requester (Requester)
            event (FrozenEvent)
            context (EventContext)
            ratelimit (bool)
            extra_users (list(UserID)): Any extra users to notify about event
        """

        try:
            yield self.auth.check_from_context(event, context)
        except AuthError as err:
            logger.warn("Denying new event %r because %s", event, err)
            raise err

        # Ensure that we can round trip before trying to persist in db
        try:
            dump = frozendict_json_encoder.encode(event.content)
            simplejson.loads(dump)
        except Exception:
            logger.exception("Failed to encode content: %r", event.content)
            raise

        yield self.action_generator.handle_push_actions_for_event(
            event, context
        )

        try:
            # If we're a worker we need to hit out to the master.
            if self.config.worker_app:
                yield send_event_to_master(
                    self.http_client,
                    host=self.config.worker_replication_host,
                    port=self.config.worker_replication_http_port,
                    requester=requester,
                    event=event,
                    context=context,
                    ratelimit=ratelimit,
                    extra_users=extra_users,
                )
                return

            yield self.persist_and_notify_client_event(
                requester,
                event,
                context,
                ratelimit=ratelimit,
                extra_users=extra_users,
            )
        except:  # noqa: E722, as we reraise the exception this is fine.
            # Ensure that we actually remove the entries in the push actions
            # staging area, if we calculated them.
            tp, value, tb = sys.exc_info()

            run_in_background(
                self.store.remove_push_actions_from_staging,
                event.event_id,
            )

            six.reraise(tp, value, tb)