Example #1
0
    def get_state_for_pdu(self, origin, room_id, event_id):
        yield run_on_reactor()

        in_room = yield self.auth.check_host_in_room(room_id, origin)
        if not in_room:
            raise AuthError(403, "Host not in room.")

        state_groups = yield self.store.get_state_groups([event_id])

        if state_groups:
            _, state = state_groups.items().pop()
            results = {(e.type, e.state_key): e for e in state}

            event = yield self.store.get_event(event_id)
            if event and event.is_state():
                # Get previous state
                if "replaces_state" in event.unsigned:
                    prev_id = event.unsigned["replaces_state"]
                    if prev_id != event.event_id:
                        prev_event = yield self.store.get_event(prev_id)
                        results[(event.type, event.state_key)] = prev_event
                else:
                    del results[(event.type, event.state_key)]

            res = results.values()
            for event in res:
                event.signatures.update(
                    compute_event_signature(event, self.hs.hostname,
                                            self.hs.config.signing_key[0]))

            defer.returnValue(res)
        else:
            defer.returnValue([])
Example #2
0
    def on_context_state_request(self, origin, room_id, event_id):
        if event_id:
            pdus = yield self.handler.get_state_for_pdu(
                origin, room_id, event_id,
            )
            auth_chain = yield self.store.get_auth_chain(
                [pdu.event_id for pdu in pdus]
            )

            for event in auth_chain:
                # We sign these again because there was a bug where we
                # incorrectly signed things the first time round
                if self.hs.is_mine_id(event.event_id):
                    event.signatures.update(
                        compute_event_signature(
                            event,
                            self.hs.hostname,
                            self.hs.config.signing_key[0]
                        )
                    )
        else:
            raise NotImplementedError("Specify an event")

        defer.returnValue((200, {
            "pdus": [pdu.get_pdu_json() for pdu in pdus],
            "auth_chain": [pdu.get_pdu_json() for pdu in auth_chain],
        }))
Example #3
0
    def get_persisted_pdu(self, origin, event_id, do_auth=True):
        """ Get a PDU from the database with given origin and id.

        Returns:
            Deferred: Results in a `Pdu`.
        """
        event = yield self.store.get_event(
            event_id,
            allow_none=True,
        )

        if event:
            # FIXME: This is a temporary work around where we occasionally
            # return events slightly differently than when they were
            # originally signed
            event.signatures.update(
                compute_event_signature(event, self.hs.hostname,
                                        self.hs.config.signing_key[0]))

            if do_auth:
                in_room = yield self.auth.check_host_in_room(
                    event.room_id, origin)
                if not in_room:
                    raise AuthError(403, "Host not in room.")

            defer.returnValue(event)
        else:
            defer.returnValue(None)
Example #4
0
    def on_query_auth(self, origin, event_id, remote_auth_chain, rejects,
                      missing):
        # Just go through and process each event in `remote_auth_chain`. We
        # don't want to fall into the trap of `missing` being wrong.
        for e in remote_auth_chain:
            try:
                yield self._handle_new_event(origin, e)
            except AuthError:
                pass

        # Now get the current auth_chain for the event.
        local_auth_chain = yield self.store.get_auth_chain([event_id])

        # TODO: Check if we would now reject event_id. If so we need to tell
        # everyone.

        ret = yield self.construct_auth_difference(
            local_auth_chain, remote_auth_chain
        )

        for event in ret["auth_chain"]:
            event.signatures.update(
                compute_event_signature(
                    event,
                    self.hs.hostname,
                    self.hs.config.signing_key[0]
                )
            )

        logger.debug("on_query_auth returning: %s", ret)

        defer.returnValue(ret)
Example #5
0
    def on_invite_request(self, origin, pdu):
        """ We've got an invite event. Process and persist it. Sign it.

        Respond with the now signed event.
        """
        event = pdu

        event.internal_metadata.outlier = True

        event.signatures.update(
            compute_event_signature(event, self.hs.hostname,
                                    self.hs.config.signing_key[0]))

        context = yield self.state_handler.compute_event_context(event)

        yield self.store.persist_event(
            event,
            context=context,
            backfilled=False,
        )

        target_user = self.hs.parse_userid(event.state_key)
        yield self.notifier.on_new_room_event(
            event,
            extra_users=[target_user],
        )

        defer.returnValue(event)
Example #6
0
    def get_persisted_pdu(self, origin, event_id, do_auth=True):
        """ Get a PDU from the database with given origin and id.

        Returns:
            Deferred: Results in a `Pdu`.
        """
        event = yield self.store.get_event(
            event_id,
            allow_none=True,
            allow_rejected=True,
        )

        if event:
            # FIXME: This is a temporary work around where we occasionally
            # return events slightly differently than when they were
            # originally signed
            event.signatures.update(
                compute_event_signature(
                    event,
                    self.hs.hostname,
                    self.hs.config.signing_key[0]
                )
            )

            if do_auth:
                in_room = yield self.auth.check_host_in_room(
                    event.room_id,
                    origin
                )
                if not in_room:
                    raise AuthError(403, "Host not in room.")

            defer.returnValue(event)
        else:
            defer.returnValue(None)
Example #7
0
    def on_query_auth(self, origin, event_id, remote_auth_chain, rejects,
                      missing):
        # Just go through and process each event in `remote_auth_chain`. We
        # don't want to fall into the trap of `missing` being wrong.
        for e in remote_auth_chain:
            try:
                yield self._handle_new_event(origin, e)
            except AuthError:
                pass

        # Now get the current auth_chain for the event.
        local_auth_chain = yield self.store.get_auth_chain([event_id])

        # TODO: Check if we would now reject event_id. If so we need to tell
        # everyone.

        ret = yield self.construct_auth_difference(
            local_auth_chain, remote_auth_chain
        )

        for event in ret["auth_chain"]:
            event.signatures.update(
                compute_event_signature(
                    event,
                    self.hs.hostname,
                    self.hs.config.signing_key[0]
                )
            )

        logger.debug("on_query_auth returning: %s", ret)

        defer.returnValue(ret)
Example #8
0
    def on_invite_request(self, origin, pdu):
        """ We've got an invite event. Process and persist it. Sign it.

        Respond with the now signed event.
        """
        event = pdu

        event.internal_metadata.outlier = True

        event.signatures.update(
            compute_event_signature(
                event,
                self.hs.hostname,
                self.hs.config.signing_key[0]
            )
        )

        context = yield self.state_handler.compute_event_context(event)

        yield self.store.persist_event(
            event,
            context=context,
            backfilled=False,
        )

        target_user = UserID.from_string(event.state_key)
        yield self.notifier.on_new_room_event(
            event, extra_users=[target_user],
        )

        defer.returnValue(event)
Example #9
0
    def on_invite_request(self, origin, pdu):
        """ We've got an invite event. Process and persist it. Sign it.

        Respond with the now signed event.
        """
        event = pdu

        event.internal_metadata.outlier = True

        event.signatures.update(
            compute_event_signature(event, self.hs.hostname,
                                    self.hs.config.signing_key[0]))

        context = yield self.state_handler.compute_event_context(event)

        yield self.store.persist_event(
            event,
            context=context,
            backfilled=False,
        )

        target_user = UserID.from_string(event.state_key)
        d = self.notifier.on_new_room_event(
            event,
            extra_users=[target_user],
        )

        def log_failure(f):
            logger.warn("Failed to notify about %s: %s", event.event_id,
                        f.value)

        d.addErrback(log_failure)

        defer.returnValue(event)
Example #10
0
    def on_event_auth(self, event_id):
        auth = yield self.store.get_auth_chain([event_id])

        for event in auth:
            event.signatures.update(
                compute_event_signature(event, self.hs.hostname,
                                        self.hs.config.signing_key[0]))

        defer.returnValue([e for e in auth])
Example #11
0
    def on_event_auth(self, event_id):
        auth = yield self.store.get_auth_chain([event_id])

        for event in auth:
            event.signatures.update(
                compute_event_signature(
                    event,
                    self.hs.hostname,
                    self.hs.config.signing_key[0]
                )
            )

        defer.returnValue([e for e in auth])
Example #12
0
    def get_state_for_pdu(self, origin, room_id, event_id, do_auth=True):
        yield run_on_reactor()

        if do_auth:
            in_room = yield self.auth.check_host_in_room(room_id, origin)
            if not in_room:
                raise AuthError(403, "Host not in room.")

        state_groups = yield self.store.get_state_groups(
            [event_id]
        )

        if state_groups:
            _, state = state_groups.items().pop()
            results = {
                (e.type, e.state_key): e for e in state
            }

            event = yield self.store.get_event(event_id)
            if event and event.is_state():
                # Get previous state
                if "replaces_state" in event.unsigned:
                    prev_id = event.unsigned["replaces_state"]
                    if prev_id != event.event_id:
                        prev_event = yield self.store.get_event(prev_id)
                        results[(event.type, event.state_key)] = prev_event
                else:
                    del results[(event.type, event.state_key)]

            res = results.values()
            for event in res:
                event.signatures.update(
                    compute_event_signature(
                        event,
                        self.hs.hostname,
                        self.hs.config.signing_key[0]
                    )
                )

            defer.returnValue(res)
        else:
            defer.returnValue([])
Example #13
0
    def _on_context_state_request_compute(self, room_id, event_id):
        pdus = yield self.handler.get_state_for_pdu(
            room_id,
            event_id,
        )
        auth_chain = yield self.store.get_auth_chain(
            [pdu.event_id for pdu in pdus])

        for event in auth_chain:
            # We sign these again because there was a bug where we
            # incorrectly signed things the first time round
            if self.hs.is_mine_id(event.event_id):
                event.signatures.update(
                    compute_event_signature(event, self.hs.hostname,
                                            self.hs.config.signing_key[0]))

        defer.returnValue({
            "pdus": [pdu.get_pdu_json() for pdu in pdus],
            "auth_chain": [pdu.get_pdu_json() for pdu in auth_chain],
        })
Example #14
0
    def on_invite_request(self, origin, pdu):
        """ We've got an invite event. Process and persist it. Sign it.

        Respond with the now signed event.
        """
        event = pdu

        event.internal_metadata.outlier = True

        event.signatures.update(
            compute_event_signature(
                event,
                self.hs.hostname,
                self.hs.config.signing_key[0]
            )
        )

        context = yield self.state_handler.compute_event_context(event)

        event_stream_id, max_stream_id = yield self.store.persist_event(
            event,
            context=context,
            backfilled=False,
        )

        target_user = UserID.from_string(event.state_key)
        with PreserveLoggingContext():
            d = self.notifier.on_new_room_event(
                event, event_stream_id, max_stream_id,
                extra_users=[target_user],
            )

        def log_failure(f):
            logger.warn(
                "Failed to notify about %s: %s",
                event.event_id, f.value
            )

        d.addErrback(log_failure)

        defer.returnValue(event)
Example #15
0
    def on_context_state_request(self, origin, room_id, event_id):
        if event_id:
            pdus = yield self.handler.get_state_for_pdu(
                origin,
                room_id,
                event_id,
            )
            auth_chain = yield self.store.get_auth_chain(
                [pdu.event_id for pdu in pdus])

            for event in auth_chain:
                event.signatures.update(
                    compute_event_signature(event, self.hs.hostname,
                                            self.hs.config.signing_key[0]))
        else:
            raise NotImplementedError("Specify an event")

        defer.returnValue((200, {
            "pdus": [pdu.get_pdu_json() for pdu in pdus],
            "auth_chain": [pdu.get_pdu_json() for pdu in auth_chain],
        }))
Example #16
0
    def on_context_state_request(self, origin, room_id, event_id):
        if event_id:
            pdus = yield self.handler.get_state_for_pdu(
                origin, room_id, event_id,
            )
            auth_chain = yield self.store.get_auth_chain(
                [pdu.event_id for pdu in pdus]
            )

            for event in auth_chain:
                event.signatures.update(
                    compute_event_signature(
                        event,
                        self.hs.hostname,
                        self.hs.config.signing_key[0]
                    )
                )
        else:
            raise NotImplementedError("Specify an event")

        defer.returnValue((200, {
            "pdus": [pdu.get_pdu_json() for pdu in pdus],
            "auth_chain": [pdu.get_pdu_json() for pdu in auth_chain],
        }))
Example #17
0
    def _on_context_state_request_compute(self, room_id, event_id):
        pdus = yield self.handler.get_state_for_pdu(
            room_id, event_id,
        )
        auth_chain = yield self.store.get_auth_chain(
            [pdu.event_id for pdu in pdus]
        )

        for event in auth_chain:
            # We sign these again because there was a bug where we
            # incorrectly signed things the first time round
            if self.hs.is_mine_id(event.event_id):
                event.signatures.update(
                    compute_event_signature(
                        event.get_pdu_json(),
                        self.hs.hostname,
                        self.hs.config.signing_key[0]
                    )
                )

        defer.returnValue({
            "pdus": [pdu.get_pdu_json() for pdu in pdus],
            "auth_chain": [pdu.get_pdu_json() for pdu in auth_chain],
        })
Example #18
0
def reinsert_events(cursor, server_name, signing_key):
    print "Running delta: v10"

    cursor.executescript(delta_sql)

    cursor.execute("SELECT * FROM events ORDER BY rowid ASC")

    print "Getting events..."

    rows = store.cursor_to_dict(cursor)

    events = store._generate_event_json(cursor, rows)

    print "Got events from DB."

    algorithms = {
        "sha256": hashlib.sha256,
    }

    key_id = "%s:%s" % (signing_key.alg, signing_key.version)
    verify_key = signing_key.verify_key
    verify_key.alg = signing_key.alg
    verify_key.version = signing_key.version

    server_keys = {server_name: {key_id: verify_key}}

    i = 0
    N = len(events)

    for event in events:
        if i % 100 == 0:
            print "Processed: %d/%d events" % (
                i,
                N,
            )
        i += 1

        # for alg_name in event.hashes:
        #     if check_event_content_hash(event, algorithms[alg_name]):
        #         pass
        #     else:
        #         pass
        #         print "FAIL content hash %s %s" % (alg_name, event.event_id, )

        have_own_correctly_signed = False
        for host, sigs in event.signatures.items():
            pruned = prune_event(event)

            for key_id in sigs:
                if host not in server_keys:
                    server_keys[host] = {}  # get_key(host)
                if key_id in server_keys[host]:
                    try:
                        verify_signed_json(pruned.get_pdu_json(), host,
                                           server_keys[host][key_id])

                        if host == server_name:
                            have_own_correctly_signed = True
                    except SignatureVerifyException:
                        print "FAIL signature check %s %s" % (key_id,
                                                              event.event_id)

        # TODO: Re sign with our own server key
        if not have_own_correctly_signed:
            sigs = compute_event_signature(event, server_name, signing_key)
            event.signatures.update(sigs)

            pruned = prune_event(event)

            for key_id in event.signatures[server_name]:
                verify_signed_json(pruned.get_pdu_json(), server_name,
                                   server_keys[server_name][key_id])

        event_json = encode_canonical_json(event.get_dict()).decode("UTF-8")

        metadata_json = encode_canonical_json(
            event.internal_metadata.get_dict()).decode("UTF-8")

        store._simple_insert_txn(
            cursor,
            table="event_json",
            values={
                "event_id": event.event_id,
                "room_id": event.room_id,
                "internal_metadata": metadata_json,
                "json": event_json,
            },
            or_replace=True,
        )
Example #19
0
def reinsert_events(cursor, server_name, signing_key):
    print "Running delta: v10"

    cursor.executescript(delta_sql)

    cursor.execute(
        "SELECT * FROM events ORDER BY rowid ASC"
    )

    print "Getting events..."

    rows = store.cursor_to_dict(cursor)

    events = store._generate_event_json(cursor, rows)

    print "Got events from DB."

    algorithms = {
        "sha256": hashlib.sha256,
    }

    key_id = "%s:%s" % (signing_key.alg, signing_key.version)
    verify_key = signing_key.verify_key
    verify_key.alg = signing_key.alg
    verify_key.version = signing_key.version

    server_keys = {
        server_name: {
            key_id: verify_key
        }
    }

    i = 0
    N = len(events)

    for event in events:
        if i % 100 == 0:
            print "Processed: %d/%d events" % (i,N,)
        i += 1

        # for alg_name in event.hashes:
        #     if check_event_content_hash(event, algorithms[alg_name]):
        #         pass
        #     else:
        #         pass
        #         print "FAIL content hash %s %s" % (alg_name, event.event_id, )

        have_own_correctly_signed = False
        for host, sigs in event.signatures.items():
            pruned = prune_event(event)

            for key_id in sigs:
                if host not in server_keys:
                    server_keys[host] = {}  # get_key(host)
                if key_id in server_keys[host]:
                    try:
                        verify_signed_json(
                            pruned.get_pdu_json(),
                            host,
                            server_keys[host][key_id]
                        )

                        if host == server_name:
                            have_own_correctly_signed = True
                    except SignatureVerifyException:
                        print "FAIL signature check %s %s" % (
                            key_id, event.event_id
                        )

        # TODO: Re sign with our own server key
        if not have_own_correctly_signed:
            sigs = compute_event_signature(event, server_name, signing_key)
            event.signatures.update(sigs)

            pruned = prune_event(event)

            for key_id in event.signatures[server_name]:
                verify_signed_json(
                    pruned.get_pdu_json(),
                    server_name,
                    server_keys[server_name][key_id]
                )

        event_json = encode_canonical_json(
            event.get_dict()
        ).decode("UTF-8")

        metadata_json = encode_canonical_json(
            event.internal_metadata.get_dict()
        ).decode("UTF-8")

        store._simple_insert_txn(
            cursor,
            table="event_json",
            values={
                "event_id": event.event_id,
                "room_id": event.room_id,
                "internal_metadata": metadata_json,
                "json": event_json,
            },
            or_replace=True,
        )
Example #20
0
    async def _on_send_membership_event(
        self, origin: str, content: JsonDict, membership_type: str, room_id: str
    ) -> Tuple[EventBase, EventContext]:
        """Handle an on_send_{join,leave,knock} request

        Does some preliminary validation before passing the request on to the
        federation handler.

        Args:
            origin: The (authenticated) requesting server
            content: The body of the send_* request - a complete membership event
            membership_type: The expected membership type (join or leave, depending
                on the endpoint)
            room_id: The room_id from the request, to be validated against the room_id
                in the event

        Returns:
            The event and context of the event after inserting it into the room graph.

        Raises:
            SynapseError if there is a problem with the request, including things like
               the room_id not matching or the event not being authorized.
        """
        assert_params_in_dict(content, ["room_id"])
        if content["room_id"] != room_id:
            raise SynapseError(
                400,
                "Room ID in body does not match that in request path",
                Codes.BAD_JSON,
            )

        room_version = await self.store.get_room_version(room_id)

        if membership_type == Membership.KNOCK and not room_version.msc2403_knocking:
            raise SynapseError(
                403,
                "This room version does not support knocking",
                errcode=Codes.FORBIDDEN,
            )

        event = event_from_pdu_json(content, room_version)

        if event.type != EventTypes.Member or not event.is_state():
            raise SynapseError(400, "Not an m.room.member event", Codes.BAD_JSON)

        if event.content.get("membership") != membership_type:
            raise SynapseError(400, "Not a %s event" % membership_type, Codes.BAD_JSON)

        origin_host, _ = parse_server_name(origin)
        await self.check_server_matches_acl(origin_host, event.room_id)

        logger.debug("_on_send_membership_event: pdu sigs: %s", event.signatures)

        # Sign the event since we're vouching on behalf of the remote server that
        # the event is valid to be sent into the room. Currently this is only done
        # if the user is being joined via restricted join rules.
        if (
            room_version.msc3083_join_rules
            and event.membership == Membership.JOIN
            and "join_authorised_via_users_server" in event.content
        ):
            # We can only authorise our own users.
            authorising_server = get_domain_from_id(
                event.content["join_authorised_via_users_server"]
            )
            if authorising_server != self.server_name:
                raise SynapseError(
                    400,
                    f"Cannot authorise request from resident server: {authorising_server}",
                )

            event.signatures.update(
                compute_event_signature(
                    room_version,
                    event.get_pdu_json(),
                    self.hs.hostname,
                    self.hs.signing_key,
                )
            )

        event = await self._check_sigs_and_hash(room_version, event)

        return await self._federation_event_handler.on_send_membership_event(
            origin, event
        )