Ejemplo n.º 1
0
    async def _handle_request(self, request):
        with Measure(self.clock, "repl_fed_send_events_parse"):
            content = parse_json_object_from_request(request)

            backfilled = content["backfilled"]

            event_payloads = content["events"]

            event_and_contexts = []
            for event_payload in event_payloads:
                event_dict = event_payload["event"]
                format_ver = event_payload["event_format_version"]
                internal_metadata = event_payload["internal_metadata"]
                rejected_reason = event_payload["rejected_reason"]

                EventType = event_type_from_format_version(format_ver)
                event = EventType(event_dict, internal_metadata,
                                  rejected_reason)

                context = EventContext.deserialize(self.storage,
                                                   event_payload["context"])

                event_and_contexts.append((event, context))

        logger.info("Got %d events from federation", len(event_and_contexts))

        await self.federation_handler.persist_events_and_notify(
            event_and_contexts, backfilled)

        return 200, {}
Ejemplo n.º 2
0
def event_from_pdu_json(pdu_json, event_format_version, outlier=False):
    """Construct a FrozenEvent from an event json received over federation

    Args:
        pdu_json (object): pdu as received over federation
        event_format_version (int): The event format version
        outlier (bool): True to mark this event as an outlier

    Returns:
        FrozenEvent

    Raises:
        SynapseError: if the pdu is missing required fields or is otherwise
            not a valid matrix event
    """
    # we could probably enforce a bunch of other fields here (room_id, sender,
    # origin, etc etc)
    assert_params_in_dict(pdu_json, ("type", "depth"))

    depth = pdu_json["depth"]
    if not isinstance(depth, six.integer_types):
        raise SynapseError(400, "Depth %r not an intger" % (depth, ),
                           Codes.BAD_JSON)

    if depth < 0:
        raise SynapseError(400, "Depth too small", Codes.BAD_JSON)
    elif depth > MAX_DEPTH:
        raise SynapseError(400, "Depth too large", Codes.BAD_JSON)

    event = event_type_from_format_version(event_format_version)(pdu_json)

    event.internal_metadata.outlier = outlier

    return event
Ejemplo n.º 3
0
    async def _handle_request(self, request, event_id):
        with Measure(self.clock, "repl_send_event_parse"):
            content = parse_json_object_from_request(request)

            event_dict = content["event"]
            format_ver = content["event_format_version"]
            internal_metadata = content["internal_metadata"]
            rejected_reason = content["rejected_reason"]

            EventType = event_type_from_format_version(format_ver)
            event = EventType(event_dict, internal_metadata, rejected_reason)

            requester = Requester.deserialize(self.store, content["requester"])
            context = EventContext.deserialize(self.storage,
                                               content["context"])

            ratelimit = content["ratelimit"]
            extra_users = [
                UserID.from_string(u) for u in content["extra_users"]
            ]

        if requester.user:
            request.authenticated_entity = requester.user.to_string()

        logger.info("Got event to send with ID: %s into room: %s",
                    event.event_id, event.room_id)

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

        return 200, {}
Ejemplo n.º 4
0
    def _handle_request(self, request, event_id):
        with Measure(self.clock, "repl_send_event_parse"):
            content = parse_json_object_from_request(request)

            event_dict = content["event"]
            format_ver = content["event_format_version"]
            internal_metadata = content["internal_metadata"]
            rejected_reason = content["rejected_reason"]

            EventType = event_type_from_format_version(format_ver)
            event = EventType(event_dict, internal_metadata, rejected_reason)

            requester = Requester.deserialize(self.store, content["requester"])
            context = yield EventContext.deserialize(self.store, content["context"])

            ratelimit = content["ratelimit"]
            extra_users = [UserID.from_string(u) for u in content["extra_users"]]

        if requester.user:
            request.authenticated_entity = requester.user.to_string()

        logger.info(
            "Got event to send with ID: %s into room: %s",
            event.event_id, event.room_id,
        )

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

        defer.returnValue((200, {}))
Ejemplo n.º 5
0
    def _get_event_from_row(self,
                            internal_metadata,
                            js,
                            redactions,
                            format_version,
                            rejected_reason=None):
        """Parse an event row which has been read from the database

        Args:
            internal_metadata (str): json-encoded internal_metadata column
            js (str): json-encoded event body from event_json
            redactions (list[str]): a list of the events which claim to have redacted
                this event, from the redactions table
            format_version: (str): the 'format_version' column
            rejected_reason (str|None): the reason this event was rejected, if any

        Returns:
            _EventCacheEntry
        """
        with Measure(self._clock, "_get_event_from_row"):
            d = json.loads(js)
            internal_metadata = json.loads(internal_metadata)

            if format_version is None:
                # This means that we stored the event before we had the concept
                # of a event format version, so it must be a V1 event.
                format_version = EventFormatVersions.V1

            original_ev = event_type_from_format_version(format_version)(
                event_dict=d,
                internal_metadata_dict=internal_metadata,
                rejected_reason=rejected_reason,
            )

            redacted_event = yield self._maybe_redact_event_row(
                original_ev, redactions)

            cache_entry = _EventCacheEntry(event=original_ev,
                                           redacted_event=redacted_event)

            self._get_event_cache.prefill((original_ev.event_id, ),
                                          cache_entry)

        defer.returnValue(cache_entry)
Ejemplo n.º 6
0
def create_local_event_from_event_dict(
    clock: Clock,
    hostname: str,
    signing_key: SigningKey,
    room_version: RoomVersion,
    event_dict: JsonDict,
    internal_metadata_dict: Optional[JsonDict] = None,
) -> EventBase:
    """Takes a fully formed event dict, ensuring that fields like `origin`
    and `origin_server_ts` have correct values for a locally produced event,
    then signs and hashes it.
    """

    format_version = room_version.event_format
    if format_version not in KNOWN_EVENT_FORMAT_VERSIONS:
        raise Exception("No event format defined for version %r" %
                        (format_version, ))

    if internal_metadata_dict is None:
        internal_metadata_dict = {}

    time_now = int(clock.time_msec())

    if format_version == EventFormatVersions.V1:
        event_dict["event_id"] = _create_event_id(clock, hostname)

    event_dict["origin"] = hostname
    event_dict.setdefault("origin_server_ts", time_now)

    event_dict.setdefault("unsigned", {})
    age = event_dict["unsigned"].pop("age", 0)
    event_dict["unsigned"].setdefault("age_ts", time_now - age)

    event_dict.setdefault("signatures", {})

    add_hashes_and_signatures(room_version, event_dict, hostname, signing_key)
    return event_type_from_format_version(format_version)(
        event_dict, internal_metadata_dict=internal_metadata_dict)
Ejemplo n.º 7
0
    def _get_events_from_db(self, event_ids, allow_rejected=False):
        """Fetch a bunch of events from the database.

        Returned events will be added to the cache for future lookups.

        Args:
            event_ids (Iterable[str]): The event_ids of the events to fetch
            allow_rejected (bool): Whether to include rejected events

        Returns:
            Deferred[Dict[str, _EventCacheEntry]]:
                map from event id to result. May return extra events which
                weren't asked for.
        """
        fetched_events = {}
        events_to_fetch = event_ids

        while events_to_fetch:
            row_map = yield self._enqueue_events(events_to_fetch)

            # we need to recursively fetch any redactions of those events
            redaction_ids = set()
            for event_id in events_to_fetch:
                row = row_map.get(event_id)
                fetched_events[event_id] = row
                if row:
                    redaction_ids.update(row["redactions"])

            events_to_fetch = redaction_ids.difference(fetched_events.keys())
            if events_to_fetch:
                logger.debug("Also fetching redaction events %s",
                             events_to_fetch)

        # build a map from event_id to EventBase
        event_map = {}
        for event_id, row in fetched_events.items():
            if not row:
                continue
            assert row["event_id"] == event_id

            rejected_reason = row["rejected_reason"]

            if not allow_rejected and rejected_reason:
                continue

            d = json.loads(row["json"])
            internal_metadata = json.loads(row["internal_metadata"])

            format_version = row["format_version"]
            if format_version is None:
                # This means that we stored the event before we had the concept
                # of a event format version, so it must be a V1 event.
                format_version = EventFormatVersions.V1

            original_ev = event_type_from_format_version(format_version)(
                event_dict=d,
                internal_metadata_dict=internal_metadata,
                rejected_reason=rejected_reason,
            )

            event_map[event_id] = original_ev

        # finally, we can decide whether each one nededs redacting, and build
        # the cache entries.
        result_map = {}
        for event_id, original_ev in event_map.items():
            redactions = fetched_events[event_id]["redactions"]
            redacted_event = self._maybe_redact_event_row(
                original_ev, redactions, event_map)

            cache_entry = _EventCacheEntry(event=original_ev,
                                           redacted_event=redacted_event)

            self._get_event_cache.prefill((event_id, ), cache_entry)
            result_map[event_id] = cache_entry

        return result_map
Ejemplo n.º 8
0
    def _get_event_from_row(self,
                            internal_metadata,
                            js,
                            redacted,
                            format_version,
                            rejected_reason=None):
        with Measure(self._clock, "_get_event_from_row"):
            d = json.loads(js)
            internal_metadata = json.loads(internal_metadata)

            if rejected_reason:
                rejected_reason = yield self._simple_select_one_onecol(
                    table="rejections",
                    keyvalues={"event_id": rejected_reason},
                    retcol="reason",
                    desc="_get_event_from_row_rejected_reason",
                )

            if format_version is None:
                # This means that we stored the event before we had the concept
                # of a event format version, so it must be a V1 event.
                format_version = EventFormatVersions.V1

            original_ev = event_type_from_format_version(format_version)(
                event_dict=d,
                internal_metadata_dict=internal_metadata,
                rejected_reason=rejected_reason,
            )

            redacted_event = None
            if redacted:
                redacted_event = prune_event(original_ev)

                redaction_id = yield self._simple_select_one_onecol(
                    table="redactions",
                    keyvalues={"redacts": redacted_event.event_id},
                    retcol="event_id",
                    desc="_get_event_from_row_redactions",
                )

                redacted_event.unsigned["redacted_by"] = redaction_id
                # Get the redaction event.

                because = yield self.get_event(
                    redaction_id,
                    check_redacted=False,
                    allow_none=True,
                )

                if because:
                    # It's fine to do add the event directly, since get_pdu_json
                    # will serialise this field correctly
                    redacted_event.unsigned["redacted_because"] = because

                    # Starting in room version v3, some redactions need to be
                    # rechecked if we didn't have the redacted event at the
                    # time, so we recheck on read instead.
                    if because.internal_metadata.need_to_check_redaction():
                        expected_domain = get_domain_from_id(
                            original_ev.sender)
                        if get_domain_from_id(
                                because.sender) == expected_domain:
                            # This redaction event is allowed. Mark as not needing a
                            # recheck.
                            because.internal_metadata.recheck_redaction = False
                        else:
                            # Senders don't match, so the event isn't actually redacted
                            redacted_event = None

            cache_entry = _EventCacheEntry(
                event=original_ev,
                redacted_event=redacted_event,
            )

            self._get_event_cache.prefill((original_ev.event_id, ),
                                          cache_entry)

        defer.returnValue(cache_entry)