Exemplo n.º 1
0
def event_from_pdu_json(
    pdu_json: JsonDict, room_version: RoomVersion, outlier: bool = False
) -> EventBase:
    """Construct an EventBase from an event json received over federation

    Args:
        pdu_json: pdu as received over federation
        room_version: The version of the room this event belongs to
        outlier: True to mark this event as an outlier

    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 = make_event_from_dict(pdu_json, room_version)
    event.internal_metadata.outlier = outlier

    return event
Exemplo n.º 2
0
    async def _handle_request(self, request):
        with Measure(self.clock, "repl_fed_send_events_parse"):
            content = parse_json_object_from_request(request)

            room_id = content["room_id"]
            backfilled = content["backfilled"]

            event_payloads = content["events"]

            event_and_contexts = []
            for event_payload in event_payloads:
                event_dict = event_payload["event"]
                room_ver = KNOWN_ROOM_VERSIONS[event_payload["room_version"]]
                internal_metadata = event_payload["internal_metadata"]
                rejected_reason = event_payload["rejected_reason"]

                event = make_event_from_dict(event_dict, room_ver,
                                             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))

        max_stream_id = await self.federation_handler.persist_events_and_notify(
            room_id, event_and_contexts, backfilled)

        return 200, {"max_stream_id": max_stream_id}
Exemplo n.º 3
0
    def test_sign_minimal(self):
        event_dict = {
            "event_id": "$0:domain",
            "origin": "domain",
            "origin_server_ts": 1000000,
            "signatures": {},
            "type": "X",
            "unsigned": {
                "age_ts": 1000000
            },
        }

        add_hashes_and_signatures(RoomVersions.V1, event_dict, HOSTNAME,
                                  self.signing_key)

        event = make_event_from_dict(event_dict)

        self.assertTrue(hasattr(event, "hashes"))
        self.assertIn("sha256", event.hashes)
        self.assertEquals(event.hashes["sha256"],
                          "6tJjLpXtggfke8UxFhAKg82QVkJzvKOVOOSjUDK4ZSI")

        self.assertTrue(hasattr(event, "signatures"))
        self.assertIn(HOSTNAME, event.signatures)
        self.assertIn(KEY_NAME, event.signatures["domain"])
        self.assertEquals(
            event.signatures[HOSTNAME][KEY_NAME],
            "2Wptgo4CwmLo/Y8B8qinxApKaCkBG2fjTWB7AbP5Uy+"
            "aIbygsSdLOFzvdDjww8zUVKCmI02eP9xtyJxc/cLiBA",
        )
Exemplo n.º 4
0
    def to_event(self, auth_events, prev_events):
        """Given the auth_events and prev_events, convert to a Frozen Event

        Args:
            auth_events (list[str]): list of event_ids
            prev_events (list[str]): list of event_ids

        Returns:
            FrozenEvent
        """
        global ORIGIN_SERVER_TS

        ts = ORIGIN_SERVER_TS
        ORIGIN_SERVER_TS = ORIGIN_SERVER_TS + 1

        event_dict = {
            "auth_events": [(a, {}) for a in auth_events],
            "prev_events": [(p, {}) for p in prev_events],
            "event_id": self.node_id,
            "sender": self.sender,
            "type": self.type,
            "content": self.content,
            "origin_server_ts": ts,
            "room_id": ROOM_ID,
        }

        if self.state_key is not None:
            event_dict["state_key"] = self.state_key

        return make_event_from_dict(event_dict)
Exemplo n.º 5
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"]
            room_ver = KNOWN_ROOM_VERSIONS[content["room_version"]]
            internal_metadata = content["internal_metadata"]
            rejected_reason = content["rejected_reason"]

            event = make_event_from_dict(event_dict, room_ver,
                                         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)

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

        return 200, {"stream_id": stream_id}
Exemplo n.º 6
0
    def build_event(
        self,
        sender=USER_ID,
        room_id=ROOM_ID,
        type="m.room.message",
        key=None,
        internal: Optional[dict] = None,
        depth=None,
        prev_events: Optional[list] = None,
        auth_events: Optional[list] = None,
        prev_state: Optional[list] = None,
        redacts=None,
        push_actions: Iterable = frozenset(),
        **content,
    ):
        prev_events = prev_events or []
        auth_events = auth_events or []
        prev_state = prev_state or []

        if depth is None:
            depth = self.event_id

        if not prev_events:
            latest_event_ids = self.get_success(
                self.master_store.get_latest_event_ids_in_room(room_id)
            )
            prev_events = [(ev_id, {}) for ev_id in latest_event_ids]

        event_dict = {
            "sender": sender,
            "type": type,
            "content": content,
            "event_id": "$%d:blue" % (self.event_id,),
            "room_id": room_id,
            "depth": depth,
            "origin_server_ts": self.event_id,
            "prev_events": prev_events,
            "auth_events": auth_events,
        }
        if key is not None:
            event_dict["state_key"] = key
            event_dict["prev_state"] = prev_state

        if redacts is not None:
            event_dict["redacts"] = redacts

        event = make_event_from_dict(event_dict, internal_metadata_dict=internal or {})

        self.event_id += 1
        state_handler = self.hs.get_state_handler()
        context = self.get_success(state_handler.compute_event_context(event))

        self.get_success(
            self.master_store.add_push_actions_to_staging(
                event.event_id,
                {user_id: actions for user_id, actions in push_actions},
                False,
            )
        )
        return event, context
Exemplo n.º 7
0
    def _poke_fed_invite(self, room_id: str, from_user: str) -> None:
        """
        Creates a invite (as if received over federation) for the room from the
        given hostname.

        Args:
            room_id: The room ID to issue an invite for.
            fed_hostname: The user to invite from.
        """
        # Poke an invite over federation into the database.
        fed_handler = self.hs.get_federation_handler()
        fed_hostname = UserID.from_string(from_user).domain
        event = make_event_from_dict({
            "room_id": room_id,
            "event_id": "!abcd:" + fed_hostname,
            "type": EventTypes.Member,
            "sender": from_user,
            "state_key": self.user,
            "content": {
                "membership": Membership.INVITE
            },
            "prev_events": [],
            "auth_events": [],
            "depth": 1,
            "origin_server_ts": 1234,
        })
        self.get_success(
            fed_handler.on_invite_request(fed_hostname, event,
                                          RoomVersions.V6))
Exemplo n.º 8
0
def event_from_pdu_json(pdu_json: JsonDict, room_version: RoomVersion) -> EventBase:
    """Construct an EventBase from an event json received over federation

    Args:
        pdu_json: pdu as received over federation
        room_version: The version of the room this event belongs to

    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"))

    # Strip any unauthorized values from "unsigned" if they exist
    if "unsigned" in pdu_json:
        _strip_unsigned_values(pdu_json)

    depth = pdu_json["depth"]
    if not isinstance(depth, int):
        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)

    # Validate that the JSON conforms to the specification.
    if room_version.strict_canonicaljson:
        validate_canonicaljson(pdu_json)

    event = make_event_from_dict(pdu_json, room_version)
    return event
Exemplo n.º 9
0
    def test_sign_message(self):
        event_dict = {
            "content": {
                "body": "Here is the message content"
            },
            "event_id": "$0:domain",
            "origin": "domain",
            "origin_server_ts": 1000000,
            "type": "m.room.message",
            "room_id": "!r:domain",
            "sender": "@u:domain",
            "signatures": {},
            "unsigned": {
                "age_ts": 1000000
            },
        }

        add_hashes_and_signatures(RoomVersions.V1, event_dict, HOSTNAME,
                                  self.signing_key)

        event = make_event_from_dict(event_dict)

        self.assertTrue(hasattr(event, "hashes"))
        self.assertIn("sha256", event.hashes)
        self.assertEquals(event.hashes["sha256"],
                          "onLKD1bGljeBWQhWZ1kaP9SorVmRQNdN5aM2JYU2n/g")

        self.assertTrue(hasattr(event, "signatures"))
        self.assertIn(HOSTNAME, event.signatures)
        self.assertIn(KEY_NAME, event.signatures["domain"])
        self.assertEquals(
            event.signatures[HOSTNAME][KEY_NAME],
            "Wm+VzmOUOz08Ds+0NTWb1d4CZrVsJSikkeRxh6aCcUw"
            "u6pNC78FunoD7KNWzqFn241eYHYMGCA5McEiVPdhzBA",
        )
Exemplo n.º 10
0
def _random_state_event(
    room_version: RoomVersion,
    sender: str,
    auth_events: Optional[Iterable[EventBase]] = None,
) -> EventBase:
    if auth_events is None:
        auth_events = []
    return make_event_from_dict(
        {
            "room_id":
            TEST_ROOM_ID,
            **_maybe_get_event_id_dict_for_room_version(room_version),
            "type":
            "test.state",
            "sender":
            sender,
            "state_key":
            "",
            "content": {
                "membership": "join"
            },
            "auth_events":
            _build_auth_dict_for_room_version(room_version, auth_events),
        },
        room_version=room_version,
    )
Exemplo n.º 11
0
    def test_cant_hide_direct_ancestors(self):
        """
        If you send a message, you must be able to provide the direct
        prev_events that said event references.
        """
        async def post_json(destination, path, data, headers=None, timeout=0):
            # If it asks us for new missing events, give them NOTHING
            if path.startswith("/_matrix/federation/v1/get_missing_events/"):
                return {"events": []}

        self.http_client.post_json = post_json

        # Figure out what the most recent event is
        most_recent = self.get_success(
            self.store.get_latest_event_ids_in_room(self.room_id))[0]

        # Now lie about an event
        lying_event = make_event_from_dict({
            "room_id":
            self.room_id,
            "sender":
            "@baduser:test.serv",
            "event_id":
            "one:test.serv",
            "depth":
            1000,
            "origin_server_ts":
            1,
            "type":
            "m.room.message",
            "origin":
            "test.serv",
            "content": {
                "body": "hewwo?"
            },
            "auth_events": [],
            "prev_events": [("two:test.serv", {}), (most_recent, {})],
        })

        federation_event_handler = self.homeserver.get_federation_event_handler(
        )
        with LoggingContext("test-context"):
            failure = self.get_failure(
                federation_event_handler.on_receive_pdu(
                    "test.serv", lying_event),
                FederationError,
            )

        # on_receive_pdu should throw an error
        self.assertEqual(
            failure.value.args[0],
            ("ERROR 403: Your server isn't divulging details about prev_events "
             "referenced in this event."),
        )

        # Make sure the invalid event isn't there
        extrem = self.get_success(
            self.store.get_latest_event_ids_in_room(self.room_id))
        self.assertEqual(extrem[0], "$join:test.serv")
Exemplo n.º 12
0
def _create_acl_event(content):
    return make_event_from_dict({
        "room_id": "!a:b",
        "event_id": "$a:b",
        "type": "m.room.server_acls",
        "sender": "@a:b",
        "content": content,
    })
Exemplo n.º 13
0
    def finish(self) -> SendJoinResponse:
        for c in self._coros:
            c.close()

        if self._response.event_dict:
            self._response.event = make_event_from_dict(
                self._response.event_dict, self._room_version
            )
        return self._response
Exemplo n.º 14
0
def _event_list_parser(room_version: RoomVersion, events: List[EventBase]):
    """Helper function for use with `ijson.items_coro` to parse an array of
    events and add them to the given list.
    """

    while True:
        obj = yield
        event = make_event_from_dict(obj, room_version)
        events.append(event)
Exemplo n.º 15
0
def _power_levels_event(sender, content):
    return make_event_from_dict({
        "room_id": TEST_ROOM_ID,
        "event_id": _get_event_id(),
        "type": "m.room.power_levels",
        "sender": sender,
        "state_key": "",
        "content": content,
    })
Exemplo n.º 16
0
def _create_event(user_id):
    return make_event_from_dict({
        "room_id": TEST_ROOM_ID,
        "event_id": _get_event_id(),
        "type": "m.room.create",
        "sender": user_id,
        "content": {
            "creator": user_id
        },
    })
Exemplo n.º 17
0
    def test_create_event_with_prev_events(self):
        """A create event with prev_events should be rejected

        https://spec.matrix.org/v1.3/rooms/v9/#authorization-rules
        1: If type is m.room.create:
            1. If it has any previous events, reject.
        """
        creator = f"@creator:{TEST_DOMAIN}"

        # we make both a good event and a bad event, to check that we are rejecting
        # the bad event for the reason we think we are.
        good_event = make_event_from_dict(
            {
                "room_id": TEST_ROOM_ID,
                "type": "m.room.create",
                "state_key": "",
                "sender": creator,
                "content": {
                    "creator": creator,
                    "room_version": RoomVersions.V9.identifier,
                },
                "auth_events": [],
                "prev_events": [],
            },
            room_version=RoomVersions.V9,
        )
        bad_event = make_event_from_dict(
            {
                **good_event.get_dict(), "prev_events": ["$fakeevent"]
            },
            room_version=RoomVersions.V9,
        )

        event_store = _StubEventSourceStore()

        get_awaitable_result(
            event_auth.check_state_independent_auth_rules(
                event_store, good_event))
        with self.assertRaises(AuthError):
            get_awaitable_result(
                event_auth.check_state_independent_auth_rules(
                    event_store, bad_event))
Exemplo n.º 18
0
def _alias_event(sender, **kwargs):
    data = {
        "room_id": TEST_ROOM_ID,
        "event_id": _get_event_id(),
        "type": "m.room.aliases",
        "sender": sender,
        "state_key": get_domain_from_id(sender),
        "content": {"aliases": []},
    }
    data.update(**kwargs)
    return make_event_from_dict(data)
Exemplo n.º 19
0
def _join_rules_event(sender, join_rule):
    return make_event_from_dict({
        "room_id": TEST_ROOM_ID,
        "event_id": _get_event_id(),
        "type": "m.room.join_rules",
        "sender": sender,
        "state_key": "",
        "content": {
            "join_rule": join_rule,
        },
    })
Exemplo n.º 20
0
def _random_state_event(sender):
    return make_event_from_dict({
        "room_id": TEST_ROOM_ID,
        "event_id": _get_event_id(),
        "type": "test.state",
        "sender": sender,
        "state_key": "",
        "content": {
            "membership": "join"
        },
    })
Exemplo n.º 21
0
def _join_event(user_id):
    return make_event_from_dict({
        "room_id": TEST_ROOM_ID,
        "event_id": _get_event_id(),
        "type": "m.room.member",
        "sender": user_id,
        "state_key": user_id,
        "content": {
            "membership": "join"
        },
    })
Exemplo n.º 22
0
    def _populate_events(self) -> None:
        """Ensure that there are test events in the database.

        When testing with the in-memory SQLite database, all the events are lost during
        the simulated outage.

        To ensure consistency between `room_id`s and `event_id`s before and after the
        outage, rows are built and inserted manually.

        Upserts are used to handle the non-SQLite case where events are not lost.
        """
        self.get_success(
            self.store.db_pool.simple_upsert(
                "rooms",
                {"room_id": self.room_id},
                {"room_version": RoomVersions.V4.identifier},
            ))

        self.event_ids: List[str] = []
        for idx in range(20):
            event_json = {
                "type": f"test {idx}",
                "room_id": self.room_id,
            }
            event = make_event_from_dict(event_json,
                                         room_version=RoomVersions.V4)
            event_id = event.event_id
            self.get_success(
                self.store.db_pool.simple_upsert(
                    "events",
                    {"event_id": event_id},
                    {
                        "event_id": event_id,
                        "room_id": self.room_id,
                        "topological_ordering": idx,
                        "stream_ordering": idx,
                        "type": event.type,
                        "processed": True,
                        "outlier": False,
                    },
                ))
            self.get_success(
                self.store.db_pool.simple_upsert(
                    "event_json",
                    {"event_id": event_id},
                    {
                        "room_id": self.room_id,
                        "json": json.dumps(event_json),
                        "internal_metadata": "{}",
                        "format_version": EventFormatVersions.V3,
                    },
                ))
            self.event_ids.append(event_id)
Exemplo n.º 23
0
def _member_event(user_id, membership, sender=None):
    return make_event_from_dict({
        "room_id": TEST_ROOM_ID,
        "event_id": _get_event_id(),
        "type": "m.room.member",
        "sender": sender or user_id,
        "state_key": user_id,
        "content": {
            "membership": membership
        },
        "prev_events": [],
    })
Exemplo n.º 24
0
    def run_test(self, evdict, matchdict, **kwargs):
        """
        Asserts that a new event constructed with `evdict` will look like
        `matchdict` when it is redacted.

        Args:
             evdict: The dictionary to build the event from.
             matchdict: The expected resulting dictionary.
             kwargs: Additional keyword arguments used to create the event.
        """
        self.assertEqual(
            prune_event(make_event_from_dict(evdict, **kwargs)).get_dict(),
            matchdict)
Exemplo n.º 25
0
    def prepare(self, reactor, clock, hs):
        self.store: EventsWorkerStore = hs.get_datastores().main

        # insert some test data
        for rid in ("room1", "room2"):
            self.get_success(
                self.store.db_pool.simple_insert(
                    "rooms",
                    {
                        "room_id": rid,
                        "room_version": 4
                    },
                ))

        self.event_ids: List[str] = []
        for idx, rid in enumerate((
                "room1",
                "room1",
                "room1",
                "room2",
        )):
            event_json = {"type": f"test {idx}", "room_id": rid}
            event = make_event_from_dict(event_json,
                                         room_version=RoomVersions.V4)
            event_id = event.event_id

            self.get_success(
                self.store.db_pool.simple_insert(
                    "events",
                    {
                        "event_id": event_id,
                        "room_id": rid,
                        "topological_ordering": idx,
                        "stream_ordering": idx,
                        "type": event.type,
                        "processed": True,
                        "outlier": False,
                    },
                ))
            self.get_success(
                self.store.db_pool.simple_insert(
                    "event_json",
                    {
                        "event_id": event_id,
                        "room_id": rid,
                        "json": json.dumps(event_json),
                        "internal_metadata": "{}",
                        "format_version": 3,
                    },
                ))
            self.event_ids.append(event_id)
Exemplo n.º 26
0
def _alias_event(room_version: RoomVersion, sender: str,
                 **kwargs) -> EventBase:
    data = {
        "room_id": TEST_ROOM_ID,
        **_maybe_get_event_id_dict_for_room_version(room_version),
        "type": "m.room.aliases",
        "sender": sender,
        "state_key": get_domain_from_id(sender),
        "content": {
            "aliases": []
        },
    }
    data.update(**kwargs)
    return make_event_from_dict(data, room_version=room_version)
Exemplo n.º 27
0
def _join_rules_event(room_version: RoomVersion, sender: str,
                      join_rule: str) -> EventBase:
    return make_event_from_dict(
        {
            "room_id": TEST_ROOM_ID,
            **_maybe_get_event_id_dict_for_room_version(room_version),
            "type": "m.room.join_rules",
            "sender": sender,
            "state_key": "",
            "content": {
                "join_rule": join_rule,
            },
        },
        room_version=room_version,
    )
Exemplo n.º 28
0
def _power_levels_event(
    room_version: RoomVersion,
    sender: str,
    content: JsonDict,
) -> EventBase:
    return make_event_from_dict(
        {
            "room_id": TEST_ROOM_ID,
            **_maybe_get_event_id_dict_for_room_version(room_version),
            "type": "m.room.power_levels",
            "sender": sender,
            "state_key": "",
            "content": content,
        },
        room_version=room_version,
    )
Exemplo n.º 29
0
def _member_event(
    user_id: str,
    membership: str,
    sender: Optional[str] = None,
    additional_content: Optional[dict] = None,
) -> EventBase:
    return make_event_from_dict(
        {
            "room_id": TEST_ROOM_ID,
            "event_id": _get_event_id(),
            "type": "m.room.member",
            "sender": sender or user_id,
            "state_key": user_id,
            "content": {"membership": membership, **(additional_content or {})},
            "prev_events": [],
        }
    )
Exemplo n.º 30
0
def _create_event(
    room_version: RoomVersion,
    user_id: str,
) -> EventBase:
    return make_event_from_dict(
        {
            "room_id": TEST_ROOM_ID,
            **_maybe_get_event_id_dict_for_room_version(room_version),
            "type": "m.room.create",
            "state_key": "",
            "sender": user_id,
            "content": {
                "creator": user_id
            },
            "auth_events": [],
        },
        room_version=room_version,
    )