コード例 #1
0
ファイル: message.py プロジェクト: Xe/synapse
    def create_and_send_event(self, event_dict, ratelimit=True,
                              token_id=None, txn_id=None, is_guest=False):
        """ Given a dict from a client, create and handle a new event.

        Creates an FrozenEvent object, filling out auth_events, prev_events,
        etc.

        Adds display names to Join membership events.

        Persists and notifies local clients and federation.

        Args:
            event_dict (dict): An entire event
        """
        builder = self.event_builder_factory.new(event_dict)

        self.validator.validate_new(builder)

        if ratelimit:
            self.ratelimit(builder.user_id)
        # TODO(paul): Why does 'event' not have a 'user' object?
        user = UserID.from_string(builder.user_id)
        assert self.hs.is_mine(user), "User must be our own: %s" % (user,)

        if builder.type == EventTypes.Member:
            membership = builder.content.get("membership", None)
            if membership == Membership.JOIN:
                joinee = UserID.from_string(builder.state_key)
                # If event doesn't include a display name, add one.
                yield self.distributor.fire(
                    "collect_presencelike_data",
                    joinee,
                    builder.content
                )

        if token_id is not None:
            builder.internal_metadata.token_id = token_id

        if txn_id is not None:
            builder.internal_metadata.txn_id = txn_id

        event, context = yield self._create_new_client_event(
            builder=builder,
        )

        if event.type == EventTypes.Member:
            member_handler = self.hs.get_handlers().room_member_handler
            yield member_handler.change_membership(event, context, is_guest=is_guest)
        else:
            yield self.handle_new_client_event(
                event=event,
                context=context,
            )

        if event.type == EventTypes.Message:
            presence = self.hs.get_handlers().presence_handler
            with PreserveLoggingContext():
                presence.bump_presence_active_time(user)

        defer.returnValue(event)
コード例 #2
0
ファイル: admin.py プロジェクト: gergelypolonkai/synapse
    def on_POST(self, request, target_user_id):
        body = parse_json_object_from_request(request, allow_empty_body=True)
        erase = body.get("erase", False)
        if not isinstance(erase, bool):
            raise SynapseError(
                http_client.BAD_REQUEST,
                "Param 'erase' must be a boolean, if given",
                Codes.BAD_JSON,
            )

        UserID.from_string(target_user_id)
        requester = yield self.auth.get_user_by_req(request)
        is_admin = yield self.auth.is_server_admin(requester.user)

        if not is_admin:
            raise AuthError(403, "You are not a server admin")

        result = yield self._deactivate_account_handler.deactivate_account(
            target_user_id, erase,
        )
        if result:
            id_server_unbind_result = "success"
        else:
            id_server_unbind_result = "no-support"

        defer.returnValue((200, {
            "id_server_unbind_result": id_server_unbind_result,
        }))
コード例 #3
0
ファイル: __init__.py プロジェクト: matrix-org/synapse
    def on_POST(self, request, target_user_id):
        """Post request to get specific number of users from Synapse..
        This needs user to have administrator access in Synapse.
        Example:
            http://localhost:8008/_synapse/admin/v1/users_paginate/
            @admin:user?access_token=admin_access_token
        JsonBodyToSend:
            {
                "start": "0",
                "limit": "10
            }
        Returns:
            200 OK with json object {list[dict[str, Any]], count} or empty object.
        """
        yield assert_requester_is_admin(self.auth, request)
        UserID.from_string(target_user_id)

        order = "name"  # order by name in user table
        params = parse_json_object_from_request(request)
        assert_params_in_dict(params, ["limit", "start"])
        limit = params['limit']
        start = params['start']
        logger.info("limit: %s, start: %s", limit, start)

        ret = yield self.handlers.admin_handler.get_users_paginate(
            order, start, limit
        )
        defer.returnValue((200, ret))
コード例 #4
0
ファイル: test_profile.py プロジェクト: matrix-org/synapse
    def setUp(self):
        self.mock_federation = Mock()
        self.mock_registry = Mock()

        self.query_handlers = {}

        def register_query_handler(query_type, handler):
            self.query_handlers[query_type] = handler

        self.mock_registry.register_query_handler = register_query_handler

        hs = yield setup_test_homeserver(
            self.addCleanup,
            http_client=None,
            handlers=None,
            resource_for_federation=Mock(),
            federation_client=self.mock_federation,
            federation_server=Mock(),
            federation_registry=self.mock_registry,
            ratelimiter=NonCallableMock(spec_set=["can_do_action"]),
        )

        self.ratelimiter = hs.get_ratelimiter()
        self.ratelimiter.can_do_action.return_value = (True, 0)

        self.store = hs.get_datastore()

        self.frank = UserID.from_string("@1234ABCD:test")
        self.bob = UserID.from_string("@4567:test")
        self.alice = UserID.from_string("@alice:remote")

        yield self.store.create_profile(self.frank.localpart)

        self.handler = hs.get_profile_handler()
コード例 #5
0
ファイル: test_presence.py プロジェクト: Vutsuak16/synapse
    def setUp(self):
        hs = yield setup_test_homeserver(clock=MockClock())

        self.store = PresenceStore(hs)

        self.u_apple = UserID.from_string("@apple:test")
        self.u_banana = UserID.from_string("@banana:test")
コード例 #6
0
ファイル: test_types.py プロジェクト: heavenlyhash/synapse
    def test_compare(self):
        userA = UserID.from_string("@userA:my.domain")
        userAagain = UserID.from_string("@userA:my.domain")
        userB = UserID.from_string("@userB:my.domain")

        self.assertTrue(userA == userAagain)
        self.assertTrue(userA != userB)
コード例 #7
0
ファイル: test_types.py プロジェクト: martindale/synapse
    def test_compare(self):
        userA = UserID.from_string("@userA:my.domain", hs=mock_homeserver)
        userAagain = UserID.from_string("@userA:my.domain", hs=mock_homeserver)
        userB = UserID.from_string("@userB:my.domain", hs=mock_homeserver)

        self.assertTrue(userA == userAagain)
        self.assertTrue(userA != userB)
コード例 #8
0
ファイル: room.py プロジェクト: rrix/synapse
    def on_POST(self, request, room_id, membership_action, txn_id=None):
        user, client = yield self.auth.get_user_by_req(request)

        content = _parse_json(request)

        # target user is you unless it is an invite
        state_key = user.to_string()
        if membership_action in ["invite", "ban", "kick"]:
            if "user_id" not in content:
                raise SynapseError(400, "Missing user_id key.")
            state_key = content["user_id"]
            # make sure it looks like a user ID; it'll throw if it's invalid.
            UserID.from_string(state_key)

            if membership_action == "kick":
                membership_action = "leave"

        msg_handler = self.handlers.message_handler
        yield msg_handler.create_and_send_event(
            {
                "type": EventTypes.Member,
                "content": {"membership": unicode(membership_action)},
                "room_id": room_id,
                "sender": user.to_string(),
                "state_key": state_key,
            },
            client=client,
            txn_id=txn_id,
        )

        defer.returnValue((200, {}))
コード例 #9
0
ファイル: room.py プロジェクト: Xe/synapse
    def on_POST(self, request, room_id, membership_action, txn_id=None):
        user, token_id, is_guest = yield self.auth.get_user_by_req(
            request,
            allow_guest=True
        )

        if is_guest and membership_action not in {Membership.JOIN, Membership.LEAVE}:
            raise AuthError(403, "Guest access not allowed")

        content = _parse_json(request)

        # target user is you unless it is an invite
        state_key = user.to_string()

        if membership_action == "invite" and self._has_3pid_invite_keys(content):
            yield self.handlers.room_member_handler.do_3pid_invite(
                room_id,
                user,
                content["medium"],
                content["address"],
                content["id_server"],
                token_id,
                txn_id
            )
            defer.returnValue((200, {}))
            return
        elif membership_action in ["invite", "ban", "kick"]:
            if "user_id" in content:
                state_key = content["user_id"]
            else:
                raise SynapseError(400, "Missing user_id key.")

            # make sure it looks like a user ID; it'll throw if it's invalid.
            UserID.from_string(state_key)

            if membership_action == "kick":
                membership_action = "leave"

        msg_handler = self.handlers.message_handler

        content = {"membership": unicode(membership_action)}
        if is_guest:
            content["kind"] = "guest"

        yield msg_handler.create_and_send_event(
            {
                "type": EventTypes.Member,
                "content": content,
                "room_id": room_id,
                "sender": user.to_string(),
                "state_key": state_key,
            },
            token_id=token_id,
            txn_id=txn_id,
            is_guest=is_guest,
        )

        defer.returnValue((200, {}))
コード例 #10
0
ファイル: _base.py プロジェクト: cryptoempathy/synapse
    def handle_new_client_event(self, event, context, extra_destinations=[],
                                extra_users=[], suppress_auth=False):
        yield run_on_reactor()

        # We now need to go and hit out to wherever we need to hit out to.

        if not suppress_auth:
            self.auth.check(event, auth_events=context.current_state)

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

        federation_handler = self.hs.get_handlers().federation_handler

        if event.type == EventTypes.Member:
            if event.content["membership"] == Membership.INVITE:
                invitee = UserID.from_string(event.state_key)
                if not self.hs.is_mine(invitee):
                    # TODO: Can we add signature from remote server in a nicer
                    # way? If we have been invited by a remote server, we need
                    # to get them to sign the event.
                    returned_invite = yield federation_handler.send_invite(
                        invitee.domain,
                        event,
                    )

                    # TODO: Make sure the signatures actually are correct.
                    event.signatures.update(
                        returned_invite.signatures
                    )

        destinations = set(extra_destinations)
        for k, s in context.current_state.items():
            try:
                if k[0] == EventTypes.Member:
                    if s.content["membership"] == Membership.JOIN:
                        destinations.add(
                            UserID.from_string(s.state_key).domain
                        )
            except SynapseError:
                logger.warn(
                    "Failed to get destination from event %s", s.event_id
                )

        # Don't block waiting on waking up all the listeners.
        d = self.notifier.on_new_room_event(event, extra_users=extra_users)

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

        d.addErrback(log_failure)

        yield federation_handler.handle_new_event(
            event, destinations=destinations,
        )
コード例 #11
0
ファイル: test_presence.py プロジェクト: heavenlyhash/synapse
    def setUp(self):
        self.mock_resource = MockHttpResource(prefix=PATH_PREFIX)

        hs = yield setup_test_homeserver(
            datastore=Mock(spec=[
                "has_presence_state",
                "get_presence_state",
                "allow_presence_visible",
                "is_presence_visible",
                "add_presence_list_pending",
                "set_presence_list_accepted",
                "del_presence_list",
                "get_presence_list",
                "insert_client_ip",
            ]),
            http_client=None,
            resource_for_client=self.mock_resource,
            resource_for_federation=self.mock_resource,
        )
        hs.handlers = JustPresenceHandlers(hs)

        self.datastore = hs.get_datastore()
        self.datastore.get_app_service_by_token = Mock(return_value=None)

        def has_presence_state(user_localpart):
            return defer.succeed(
                user_localpart in ("apple", "banana",)
            )
        self.datastore.has_presence_state = has_presence_state

        def _get_user_by_token(token=None):
            return {
                "user": UserID.from_string(myid),
                "admin": False,
                "device_id": None,
                "token_id": 1,
            }

        hs.handlers.room_member_handler = Mock(
            spec=[
                "get_joined_rooms_for_user",
            ]
        )

        hs.get_v1auth().get_user_by_token = _get_user_by_token

        presence.register_servlets(hs, self.mock_resource)

        self.u_apple = UserID.from_string("@apple:test")
        self.u_banana = UserID.from_string("@banana:test")
コード例 #12
0
ファイル: typing.py プロジェクト: 0-T-0/synapse
    def _recv_edu(self, origin, content):
        room_id = content["room_id"]
        user_id = content["user_id"]

        # Check that the string is a valid user id
        UserID.from_string(user_id)

        domains = yield self.store.get_joined_hosts_for_room(room_id)

        if self.server_name in domains:
            self._push_update_local(
                room_id=room_id,
                user_id=user_id,
                typing=content["typing"]
            )
コード例 #13
0
ファイル: test_stream.py プロジェクト: rrix/synapse
    def setUp(self):
        hs = yield setup_test_homeserver(resource_for_federation=Mock(), http_client=None)

        self.store = hs.get_datastore()
        self.event_builder_factory = hs.get_event_builder_factory()
        self.handlers = hs.get_handlers()
        self.message_handler = self.handlers.message_handler

        self.u_alice = UserID.from_string("@alice:test")
        self.u_bob = UserID.from_string("@bob:test")

        self.room1 = RoomID.from_string("!abc123:test")
        self.room2 = RoomID.from_string("!xyx987:test")

        self.depth = 1
コード例 #14
0
ファイル: admin.py プロジェクト: mebjas/synapse
    def on_POST(self, request, target_user_id):
        UserID.from_string(target_user_id)
        requester = yield self.auth.get_user_by_req(request)
        is_admin = yield self.auth.is_server_admin(requester.user)

        if not is_admin:
            raise AuthError(403, "You are not a server admin")

        # FIXME: Theoretically there is a race here wherein user resets password
        # using threepid.
        yield self.store.user_delete_access_tokens(target_user_id)
        yield self.store.user_delete_threepids(target_user_id)
        yield self.store.user_set_password_hash(target_user_id, None)

        defer.returnValue((200, {}))
コード例 #15
0
ファイル: test_state.py プロジェクト: matrix-org/synapse
    def setUp(self):
        hs = yield tests.utils.setup_test_homeserver(self.addCleanup)

        self.store = hs.get_datastore()
        self.event_builder_factory = hs.get_event_builder_factory()
        self.event_creation_handler = hs.get_event_creation_handler()

        self.u_alice = UserID.from_string("@alice:test")
        self.u_bob = UserID.from_string("@bob:test")

        self.room = RoomID.from_string("!abc123:test")

        yield self.store.store_room(
            self.room.to_string(), room_creator_user_id="@creator:text", is_public=True
        )
コード例 #16
0
ファイル: test_presence.py プロジェクト: roblabla/synapse
    def test_invited_remote_nonexistant(self):
        # Use a different destination, otherwise retry logic might fail the
        # request
        u_rocket = UserID.from_string("@rocket:sun")

        put_json = self.mock_http_client.put_json
        put_json.expect_call_and_return(
            call("sun",
                path="/_matrix/federation/v1/send/1000000/",
                data=_expect_edu("sun", "m.presence_deny",
                    content={
                        "observer_user": "******",
                        "observed_user": "******",
                    }
                ),
                json_data_callback=ANY,
                long_retries=True,
            ),
            defer.succeed((200, "OK"))
        )

        yield self.mock_federation_resource.trigger("PUT",
            "/_matrix/federation/v1/send/1000000/",
            _make_edu_json("sun", "m.presence_invite",
                content={
                    "observer_user": "******",
                    "observed_user": "******",
                }
            )
        )

        yield put_json.await_calls()
コード例 #17
0
ファイル: test_auth.py プロジェクト: mebjas/synapse
    def test_get_user_from_macaroon_with_valid_duration(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"}
        )

        self.store.get_user_by_access_token = Mock(
            return_value={"name": "@baldrick:matrix.org"}
        )

        user_id = "@baldrick:matrix.org"
        macaroon = pymacaroons.Macaroon(
            location=self.hs.config.server_name,
            identifier="key",
            key=self.hs.config.macaroon_secret_key)
        macaroon.add_first_party_caveat("gen = 1")
        macaroon.add_first_party_caveat("type = access")
        macaroon.add_first_party_caveat("user_id = %s" % (user_id,))
        macaroon.add_first_party_caveat("time < 900000000")  # ms

        self.hs.clock.now = 5000  # seconds
        self.hs.config.expire_access_token = True

        user_info = yield self.auth.get_user_from_macaroon(macaroon.serialize())
        user = user_info["user"]
        self.assertEqual(UserID.from_string(user_id), user)
コード例 #18
0
ファイル: test_rooms.py プロジェクト: heavenlyhash/synapse
 def _get_user_by_token(token=None):
     return {
         "user": UserID.from_string(self.auth_user_id),
         "admin": False,
         "device_id": None,
         "token_id": 1,
     }
コード例 #19
0
ファイル: room.py プロジェクト: roblabla/synapse
    def get_inviter(self, event):
        # TODO(markjh): get prev_state from snapshot
        prev_state = yield self.store.get_room_member(
            event.user_id, event.room_id
        )

        if prev_state and prev_state.membership == Membership.INVITE:
            defer.returnValue(UserID.from_string(prev_state.user_id))
            return
        elif "third_party_invite" in event.content:
            if "sender" in event.content["third_party_invite"]:
                inviter = UserID.from_string(
                    event.content["third_party_invite"]["sender"]
                )
                defer.returnValue(inviter)
        defer.returnValue(None)
コード例 #20
0
ファイル: presence.py プロジェクト: roblabla/synapse
    def on_PUT(self, request, user_id):
        auth_user, _, _ = yield self.auth.get_user_by_req(request)
        user = UserID.from_string(user_id)

        state = {}
        try:
            content = json.loads(request.content.read())

            state["presence"] = content.pop("presence")

            if "status_msg" in content:
                state["status_msg"] = content.pop("status_msg")
                if not isinstance(state["status_msg"], basestring):
                    raise SynapseError(400, "status_msg must be a string.")

            if content:
                raise KeyError()
        except SynapseError as e:
            raise e
        except:
            raise SynapseError(400, "Unable to parse state")

        yield self.handlers.presence_handler.set_state(
            target_user=user, auth_user=auth_user, state=state)

        defer.returnValue((200, {}))
コード例 #21
0
ファイル: test_auth.py プロジェクト: mebjas/synapse
    def test_get_user_from_macaroon(self):
        # TODO(danielwh): Remove this mock when we remove the
        # get_user_by_access_token fallback.
        self.store.get_user_by_access_token = Mock(
            return_value={
                "name": "@baldrick:matrix.org",
                "device_id": "device",
            }
        )

        user_id = "@baldrick:matrix.org"
        macaroon = pymacaroons.Macaroon(
            location=self.hs.config.server_name,
            identifier="key",
            key=self.hs.config.macaroon_secret_key)
        macaroon.add_first_party_caveat("gen = 1")
        macaroon.add_first_party_caveat("type = access")
        macaroon.add_first_party_caveat("user_id = %s" % (user_id,))
        user_info = yield self.auth.get_user_from_macaroon(macaroon.serialize())
        user = user_info["user"]
        self.assertEqual(UserID.from_string(user_id), user)

        # TODO: device_id should come from the macaroon, but currently comes
        # from the db.
        self.assertEqual(user_info["device_id"], "device")
コード例 #22
0
    def test_filter_room_state_no_match(self):
        user_filter_json = {
            "room": {
                "state": {
                    "types": ["m.*"]
                }
            }
        }
        user = UserID.from_string("@" + user_localpart + ":test")
        filter_id = yield self.datastore.add_user_filter(
            user_localpart=user_localpart,
            user_filter=user_filter_json,
        )
        event = MockEvent(
            sender="@foo:bar",
            type="org.matrix.custom.event",
            room_id="!foo:bar"
        )
        events = [event]

        user_filter = yield self.filtering.get_user_filter(
            user_localpart=user_localpart,
            filter_id=filter_id,
        )

        results = user_filter.filter_room_state(events)
        self.assertEquals([], results)
コード例 #23
0
ファイル: auth.py プロジェクト: rrix/synapse
    def get_user_by_token(self, token):
        """ Get a registered user's ID.

        Args:
            token (str): The access token to get the user by.
        Returns:
            dict : dict that includes the user, device_id, and whether the
                user is a server admin.
        Raises:
            AuthError if no user by that token exists or the token is invalid.
        """
        ret = yield self.store.get_user_by_token(token)
        if not ret:
            raise AuthError(
                self.TOKEN_NOT_FOUND_HTTP_STATUS, "Unrecognised access token.",
                errcode=Codes.UNKNOWN_TOKEN
            )
        user_info = {
            "admin": bool(ret.get("admin", False)),
            "device_id": ret.get("device_id"),
            "user": UserID.from_string(ret.get("name")),
            "token_id": ret.get("token_id", None),
        }

        defer.returnValue(user_info)
コード例 #24
0
ファイル: send_event.py プロジェクト: DoubleMalt/synapse
    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"]
            internal_metadata = content["internal_metadata"]
            rejected_reason = content["rejected_reason"]
            event = FrozenEvent(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, {}))
コード例 #25
0
    def test_filter_public_user_data_no_match(self):
        user_filter_json = {
            "public_user_data": {
                "types": ["m.*"]
            }
        }
        user = UserID.from_string("@" + user_localpart + ":test")
        filter_id = yield self.datastore.add_user_filter(
            user_localpart=user_localpart,
            user_filter=user_filter_json,
        )
        event = MockEvent(
            sender="@foo:bar",
            type="custom.avatar.3d.crazy",
            room_id="!foo:bar"
        )
        events = [event]

        user_filter = yield self.filtering.get_user_filter(
            user_localpart=user_localpart,
            filter_id=filter_id,
        )

        results = user_filter.filter_public_user_data(events=events)
        self.assertEquals([], results)
コード例 #26
0
ファイル: room_member.py プロジェクト: 0-T-0/synapse
    def do_3pid_invite(
            self,
            room_id,
            inviter,
            medium,
            address,
            id_server,
            requester,
            txn_id
    ):
        invitee = yield self._lookup_3pid(
            id_server, medium, address
        )

        if invitee:
            yield self.update_membership(
                requester,
                UserID.from_string(invitee),
                room_id,
                "invite",
                txn_id=txn_id,
            )
        else:
            yield self._make_and_store_3pid_invite(
                requester,
                id_server,
                medium,
                address,
                room_id,
                inviter,
                txn_id=txn_id
            )
コード例 #27
0
ファイル: test_presence.py プロジェクト: roblabla/synapse
    def test_invite_remote(self):
        # Use a different destination, otherwise retry logic might fail the
        # request
        u_rocket = UserID.from_string("@rocket:there")

        put_json = self.mock_http_client.put_json
        put_json.expect_call_and_return(
            call("there",
                path="/_matrix/federation/v1/send/1000000/",
                data=_expect_edu("there", "m.presence_invite",
                    content={
                        "observer_user": "******",
                        "observed_user": "******",
                    }
                ),
                json_data_callback=ANY,
                long_retries=True,
            ),
            defer.succeed((200, "OK"))
        )

        yield self.handler.send_presence_invite(
                observer_user=self.u_apple, observed_user=u_rocket)

        self.assertEquals(
            [{"observed_user_id": "@rocket:there", "accepted": 0}],
            (yield self.datastore.get_presence_list(self.u_apple.localpart))
        )

        yield put_json.await_calls()
コード例 #28
0
ファイル: room_member.py プロジェクト: 0-T-0/synapse
 def get_inviter(self, user_id, room_id):
     invite = yield self.store.get_invite_for_user_in_room(
         user_id=user_id,
         room_id=room_id,
     )
     if invite:
         defer.returnValue(UserID.from_string(invite.sender))
コード例 #29
0
ファイル: presence.py プロジェクト: Xe/synapse
    def get_presence_list(self, observer_user, accepted=None):
        """Get the presence list for a local user. The retured list includes
        the current presence state for each user listed.

        Args:
            observer_user(UserID): The local user whose presence list to fetch.
            accepted(bool or None): If not none then only include users who
                have or have not accepted the presence invite request.
        Returns:
            A Deferred list of presence state events.
        """
        if not self.hs.is_mine(observer_user):
            raise SynapseError(400, "User is not hosted on this Home Server")

        presence_list = yield self.store.get_presence_list(
            observer_user.localpart, accepted=accepted
        )

        results = []
        for row in presence_list:
            observed_user = UserID.from_string(row["observed_user_id"])
            result = {
                "observed_user": observed_user, "accepted": row["accepted"]
            }
            result.update(
                self._get_or_offline_usercache(observed_user).get_state()
            )
            if "last_active" in result:
                result["last_active_ago"] = int(
                    self.clock.time_msec() - result.pop("last_active")
                )
            results.append(result)

        defer.returnValue(results)
コード例 #30
0
ファイル: presence.py プロジェクト: matrix-org/synapse
    def on_PUT(self, request, user_id):
        requester = yield self.auth.get_user_by_req(request)
        user = UserID.from_string(user_id)

        if requester.user != user:
            raise AuthError(403, "Can only set your own presence state")

        state = {}

        content = parse_json_object_from_request(request)

        try:
            state["presence"] = content.pop("presence")

            if "status_msg" in content:
                state["status_msg"] = content.pop("status_msg")
                if not isinstance(state["status_msg"], string_types):
                    raise SynapseError(400, "status_msg must be a string.")

            if content:
                raise KeyError()
        except SynapseError as e:
            raise e
        except Exception:
            raise SynapseError(400, "Unable to parse state")

        if self.hs.config.use_presence:
            yield self.presence_handler.set_state(user, state)

        defer.returnValue((200, {}))
コード例 #31
0
ファイル: users.py プロジェクト: yalamber/synapse
    async def on_PUT(self, request, user_id):
        requester = await self.auth.get_user_by_req(request)
        await assert_user_is_admin(self.auth, requester.user)

        target_user = UserID.from_string(user_id)
        body = parse_json_object_from_request(request)

        if not self.hs.is_mine(target_user):
            raise SynapseError(400, "This endpoint can only be used with local users")

        user = await self.admin_handler.get_user(target_user)
        user_id = target_user.to_string()

        if user:  # modify user
            if "displayname" in body:
                await self.profile_handler.set_displayname(
                    target_user, requester, body["displayname"], True
                )

            if "threepids" in body:
                # check for required parameters for each threepid
                for threepid in body["threepids"]:
                    assert_params_in_dict(threepid, ["medium", "address"])

                # remove old threepids from user
                threepids = await self.store.user_get_threepids(user_id)
                for threepid in threepids:
                    try:
                        await self.auth_handler.delete_threepid(
                            user_id, threepid["medium"], threepid["address"], None
                        )
                    except Exception:
                        logger.exception("Failed to remove threepids")
                        raise SynapseError(500, "Failed to remove threepids")

                # add new threepids to user
                current_time = self.hs.get_clock().time_msec()
                for threepid in body["threepids"]:
                    await self.auth_handler.add_threepid(
                        user_id, threepid["medium"], threepid["address"], current_time
                    )

            if "avatar_url" in body and type(body["avatar_url"]) == str:
                await self.profile_handler.set_avatar_url(
                    target_user, requester, body["avatar_url"], True
                )

            if "admin" in body:
                set_admin_to = bool(body["admin"])
                if set_admin_to != user["admin"]:
                    auth_user = requester.user
                    if target_user == auth_user and not set_admin_to:
                        raise SynapseError(400, "You may not demote yourself.")

                    await self.store.set_server_admin(target_user, set_admin_to)

            if "password" in body:
                if (
                    not isinstance(body["password"], text_type)
                    or len(body["password"]) > 512
                ):
                    raise SynapseError(400, "Invalid password")
                else:
                    new_password = body["password"]
                    logout_devices = True

                    new_password_hash = await self.auth_handler.hash(new_password)

                    await self.set_password_handler.set_password(
                        target_user.to_string(),
                        new_password_hash,
                        logout_devices,
                        requester,
                    )

            if "deactivated" in body:
                deactivate = body["deactivated"]
                if not isinstance(deactivate, bool):
                    raise SynapseError(
                        400, "'deactivated' parameter is not of type boolean"
                    )

                if deactivate and not user["deactivated"]:
                    await self.deactivate_account_handler.deactivate_account(
                        target_user.to_string(), False
                    )

            user = await self.admin_handler.get_user(target_user)
            return 200, user

        else:  # create user
            password = body.get("password")
            password_hash = None
            if password is not None:
                if not isinstance(password, text_type) or len(password) > 512:
                    raise SynapseError(400, "Invalid password")
                password_hash = await self.auth_handler.hash(password)

            admin = body.get("admin", None)
            user_type = body.get("user_type", None)
            displayname = body.get("displayname", None)
            threepids = body.get("threepids", None)

            if user_type is not None and user_type not in UserTypes.ALL_USER_TYPES:
                raise SynapseError(400, "Invalid user type")

            user_id = await self.registration_handler.register_user(
                localpart=target_user.localpart,
                password_hash=password_hash,
                admin=bool(admin),
                default_display_name=displayname,
                user_type=user_type,
            )

            if "threepids" in body:
                # check for required parameters for each threepid
                for threepid in body["threepids"]:
                    assert_params_in_dict(threepid, ["medium", "address"])

                current_time = self.hs.get_clock().time_msec()
                for threepid in body["threepids"]:
                    await self.auth_handler.add_threepid(
                        user_id, threepid["medium"], threepid["address"], current_time
                    )

            if "avatar_url" in body and type(body["avatar_url"]) == str:
                await self.profile_handler.set_avatar_url(
                    user_id, requester, body["avatar_url"], True
                )

            ret = await self.admin_handler.get_user(target_user)

            return 201, ret
コード例 #32
0
ファイル: room.py プロジェクト: walle303/synapse
    def create_room(self, requester, config, ratelimit=True):
        """ Creates a new room.

        Args:
            requester (Requester): The user who requested the room creation.
            config (dict) : A dict of configuration options.
        Returns:
            The new room ID.
        Raises:
            SynapseError if the room ID couldn't be stored, or something went
            horribly wrong.
        """
        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")

        if ratelimit:
            yield self.ratelimit(requester)

        if "room_alias_name" in config:
            for wchar in string.whitespace:
                if wchar in config["room_alias_name"]:
                    raise SynapseError(400, "Invalid characters in room alias")

            room_alias = RoomAlias(
                config["room_alias_name"],
                self.hs.hostname,
            )
            mapping = yield self.store.get_association_from_room_alias(
                room_alias)

            if mapping:
                raise SynapseError(400, "Room alias already taken")
        else:
            room_alias = None

        invite_list = config.get("invite", [])
        for i in invite_list:
            try:
                UserID.from_string(i)
            except Exception:
                raise SynapseError(400, "Invalid user_id: %s" % (i, ))

        invite_3pid_list = config.get("invite_3pid", [])

        visibility = config.get("visibility", None)
        is_public = visibility == "public"

        # autogen room IDs and try to create it. We may clash, so just
        # try a few times till one goes through, giving up eventually.
        attempts = 0
        room_id = None
        while attempts < 5:
            try:
                random_string = stringutils.random_string(18)
                gen_room_id = RoomID(
                    random_string,
                    self.hs.hostname,
                )
                yield self.store.store_room(room_id=gen_room_id.to_string(),
                                            room_creator_user_id=user_id,
                                            is_public=is_public)
                room_id = gen_room_id.to_string()
                break
            except StoreError:
                attempts += 1
        if not room_id:
            raise StoreError(500, "Couldn't generate a room ID.")

        if room_alias:
            directory_handler = self.hs.get_handlers().directory_handler
            yield directory_handler.create_association(
                user_id=user_id,
                room_id=room_id,
                room_alias=room_alias,
                servers=[self.hs.hostname],
            )

        preset_config = config.get(
            "preset", RoomCreationPreset.PRIVATE_CHAT
            if visibility == "private" else RoomCreationPreset.PUBLIC_CHAT)

        raw_initial_state = config.get("initial_state", [])

        initial_state = OrderedDict()
        for val in raw_initial_state:
            initial_state[(val["type"], val.get("state_key",
                                                ""))] = val["content"]

        creation_content = config.get("creation_content", {})

        msg_handler = self.hs.get_handlers().message_handler
        room_member_handler = self.hs.get_handlers().room_member_handler

        yield self._send_events_for_new_room(
            requester,
            room_id,
            msg_handler,
            room_member_handler,
            preset_config=preset_config,
            invite_list=invite_list,
            initial_state=initial_state,
            creation_content=creation_content,
            room_alias=room_alias,
            power_level_content_override=config.get(
                "power_level_content_override", {}))

        if "name" in config:
            name = config["name"]
            yield msg_handler.create_and_send_nonmember_event(
                requester, {
                    "type": EventTypes.Name,
                    "room_id": room_id,
                    "sender": user_id,
                    "state_key": "",
                    "content": {
                        "name": name
                    },
                },
                ratelimit=False)

        if "topic" in config:
            topic = config["topic"]
            yield msg_handler.create_and_send_nonmember_event(
                requester, {
                    "type": EventTypes.Topic,
                    "room_id": room_id,
                    "sender": user_id,
                    "state_key": "",
                    "content": {
                        "topic": topic
                    },
                },
                ratelimit=False)

        for invitee in invite_list:
            content = {}
            is_direct = config.get("is_direct", None)
            if is_direct:
                content["is_direct"] = is_direct

            yield room_member_handler.update_membership(
                requester,
                UserID.from_string(invitee),
                room_id,
                "invite",
                ratelimit=False,
                content=content,
            )

        for invite_3pid in invite_3pid_list:
            id_server = invite_3pid["id_server"]
            address = invite_3pid["address"]
            medium = invite_3pid["medium"]
            yield self.hs.get_handlers().room_member_handler.do_3pid_invite(
                room_id,
                requester.user,
                medium,
                address,
                id_server,
                requester,
                txn_id=None,
            )

        result = {"room_id": room_id}

        if room_alias:
            result["room_alias"] = room_alias.to_string()
            yield directory_handler.send_room_alias_update_event(
                requester, user_id, room_id)

        defer.returnValue(result)
コード例 #33
0
ファイル: client.py プロジェクト: xianliangjiang/synapse
    async def on_rdata(
        self, stream_name: str, instance_name: str, token: int, rows: list
    ):
        """Called to handle a batch of replication data with a given stream token.

        By default this just pokes the slave store. Can be overridden in subclasses to
        handle more.

        Args:
            stream_name: name of the replication stream for this batch of rows
            instance_name: the instance that wrote the rows.
            token: stream token for this batch of rows
            rows: a list of Stream.ROW_TYPE objects as returned by Stream.parse_row.
        """
        self.store.process_replication_rows(stream_name, instance_name, token, rows)

        if self.send_handler:
            await self.send_handler.process_replication_rows(stream_name, token, rows)

        if stream_name == TypingStream.NAME:
            self._typing_handler.process_replication_rows(token, rows)
            self.notifier.on_new_event(
                "typing_key", token, rooms=[row.room_id for row in rows]
            )
        elif stream_name == PushRulesStream.NAME:
            self.notifier.on_new_event(
                "push_rules_key", token, users=[row.user_id for row in rows]
            )
        elif stream_name in (AccountDataStream.NAME, TagAccountDataStream.NAME):
            self.notifier.on_new_event(
                "account_data_key", token, users=[row.user_id for row in rows]
            )
        elif stream_name == ReceiptsStream.NAME:
            self.notifier.on_new_event(
                "receipt_key", token, rooms=[row.room_id for row in rows]
            )
            await self._pusher_pool.on_new_receipts(
                token, token, {row.room_id for row in rows}
            )
        elif stream_name == ToDeviceStream.NAME:
            entities = [row.entity for row in rows if row.entity.startswith("@")]
            if entities:
                self.notifier.on_new_event("to_device_key", token, users=entities)
        elif stream_name == DeviceListsStream.NAME:
            all_room_ids = set()  # type: Set[str]
            for row in rows:
                if row.entity.startswith("@"):
                    room_ids = await self.store.get_rooms_for_user(row.entity)
                    all_room_ids.update(room_ids)
            self.notifier.on_new_event("device_list_key", token, rooms=all_room_ids)
        elif stream_name == GroupServerStream.NAME:
            self.notifier.on_new_event(
                "groups_key", token, users=[row.user_id for row in rows]
            )
        elif stream_name == PushersStream.NAME:
            for row in rows:
                if row.deleted:
                    self.stop_pusher(row.user_id, row.app_id, row.pushkey)
                else:
                    await self.start_pusher(row.user_id, row.app_id, row.pushkey)
        elif stream_name == EventsStream.NAME:
            # We shouldn't get multiple rows per token for events stream, so
            # we don't need to optimise this for multiple rows.
            for row in rows:
                if row.type != EventsStreamEventRow.TypeId:
                    continue
                assert isinstance(row, EventsStreamRow)
                assert isinstance(row.data, EventsStreamEventRow)

                if row.data.rejected:
                    continue

                extra_users = ()  # type: Tuple[UserID, ...]
                if row.data.type == EventTypes.Member and row.data.state_key:
                    extra_users = (UserID.from_string(row.data.state_key),)

                max_token = self.store.get_room_max_token()
                event_pos = PersistedEventPosition(instance_name, token)
                self.notifier.on_new_room_event_args(
                    event_pos=event_pos,
                    max_room_stream_token=max_token,
                    extra_users=extra_users,
                    room_id=row.data.room_id,
                    event_type=row.data.type,
                    state_key=row.data.state_key,
                    membership=row.data.membership,
                )

        await self._presence_handler.process_replication_rows(
            stream_name, instance_name, token, rows
        )

        # Notify any waiting deferreds. The list is ordered by position so we
        # just iterate through the list until we reach a position that is
        # greater than the received row position.
        waiting_list = self._streams_to_waiters.get(stream_name, [])

        # Index of first item with a position after the current token, i.e we
        # have called all deferreds before this index. If not overwritten by
        # loop below means either a) no items in list so no-op or b) all items
        # in list were called and so the list should be cleared. Setting it to
        # `len(list)` works for both cases.
        index_of_first_deferred_not_called = len(waiting_list)

        for idx, (position, deferred) in enumerate(waiting_list):
            if position <= token:
                try:
                    with PreserveLoggingContext():
                        deferred.callback(None)
                except Exception:
                    # The deferred has been cancelled or timed out.
                    pass
            else:
                # The list is sorted by position so we don't need to continue
                # checking any further entries in the list.
                index_of_first_deferred_not_called = idx
                break

        # Drop all entries in the waiting list that were called in the above
        # loop. (This maintains the order so no need to resort)
        waiting_list[:] = waiting_list[index_of_first_deferred_not_called:]
コード例 #34
0
    def get_messages(self, user_id=None, room_id=None, pagin_config=None,
                     as_client_event=True, is_guest=False):
        """Get messages in a room.

        Args:
            user_id (str): The user requesting messages.
            room_id (str): The room they want messages from.
            pagin_config (synapse.api.streams.PaginationConfig): The pagination
                config rules to apply, if any.
            as_client_event (bool): True to get events in client-server format.
            is_guest (bool): Whether the requesting user is a guest (as opposed
                to a fully registered user).
        Returns:
            dict: Pagination API results
        """
        data_source = self.hs.get_event_sources().sources["room"]

        if pagin_config.from_token:
            room_token = pagin_config.from_token.room_key
        else:
            pagin_config.from_token = (
                yield self.hs.get_event_sources().get_current_token(
                    direction='b'
                )
            )
            room_token = pagin_config.from_token.room_key

        room_token = RoomStreamToken.parse(room_token)
        if room_token.topological is None:
            raise SynapseError(400, "Invalid token")

        pagin_config.from_token = pagin_config.from_token.copy_and_replace(
            "room_key", str(room_token)
        )

        source_config = pagin_config.get_source_config("room")

        if not is_guest:
            member_event = yield self.auth.check_user_was_in_room(room_id, user_id)
            if member_event.membership == Membership.LEAVE:
                # If they have left the room then clamp the token to be before
                # they left the room.
                # If they're a guest, we'll just 403 them if they're asking for
                # events they can't see.
                leave_token = yield self.store.get_topological_token_for_event(
                    member_event.event_id
                )
                leave_token = RoomStreamToken.parse(leave_token)
                if leave_token.topological < room_token.topological:
                    source_config.from_key = str(leave_token)

                if source_config.direction == "f":
                    if source_config.to_key is None:
                        source_config.to_key = str(leave_token)
                    else:
                        to_token = RoomStreamToken.parse(source_config.to_key)
                        if leave_token.topological < to_token.topological:
                            source_config.to_key = str(leave_token)

        yield self.hs.get_handlers().federation_handler.maybe_backfill(
            room_id, room_token.topological
        )

        user = UserID.from_string(user_id)

        events, next_key = yield data_source.get_pagination_rows(
            user, source_config, room_id
        )

        next_token = pagin_config.from_token.copy_and_replace(
            "room_key", next_key
        )

        if not events:
            defer.returnValue({
                "chunk": [],
                "start": pagin_config.from_token.to_string(),
                "end": next_token.to_string(),
            })

        events = yield self._filter_events_for_client(user_id, events, is_guest=is_guest)

        time_now = self.clock.time_msec()

        chunk = {
            "chunk": [
                serialize_event(e, time_now, as_client_event)
                for e in events
            ],
            "start": pagin_config.from_token.to_string(),
            "end": next_token.to_string(),
        }

        defer.returnValue(chunk)
コード例 #35
0
    async def on_POST(self, request: SynapseRequest,
                      room_identifier: str) -> Tuple[int, JsonDict]:
        # This will always be set by the time Twisted calls us.
        assert request.args is not None

        requester = await self.auth.get_user_by_req(request)
        await assert_user_is_admin(self.auth, requester.user)

        content = parse_json_object_from_request(request)

        assert_params_in_dict(content, ["user_id"])
        target_user = UserID.from_string(content["user_id"])

        if not self.hs.is_mine(target_user):
            raise SynapseError(
                400, "This endpoint can only be used with local users")

        if not await self.admin_handler.get_user(target_user):
            raise NotFoundError("User not found")

        # Get the room ID from the identifier.
        try:
            remote_room_hosts: Optional[List[str]] = [
                x.decode("ascii") for x in request.args[b"server_name"]
            ]
        except Exception:
            remote_room_hosts = None
        room_id, remote_room_hosts = await self.resolve_room_id(
            room_identifier, remote_room_hosts)

        fake_requester = create_requester(
            target_user, authenticated_entity=requester.authenticated_entity)

        # send invite if room has "JoinRules.INVITE"
        room_state = await self.state_handler.get_current_state(room_id)
        join_rules_event = room_state.get((EventTypes.JoinRules, ""))
        if join_rules_event:
            if not (join_rules_event.content.get("join_rule")
                    == JoinRules.PUBLIC):
                # update_membership with an action of "invite" can raise a
                # ShadowBanError. This is not handled since it is assumed that
                # an admin isn't going to call this API with a shadow-banned user.
                await self.room_member_handler.update_membership(
                    requester=requester,
                    target=fake_requester.user,
                    room_id=room_id,
                    action="invite",
                    remote_room_hosts=remote_room_hosts,
                    ratelimit=False,
                )

        await self.room_member_handler.update_membership(
            requester=fake_requester,
            target=fake_requester.user,
            room_id=room_id,
            action="join",
            remote_room_hosts=remote_room_hosts,
            ratelimit=False,
        )

        return 200, {"room_id": room_id}
コード例 #36
0
ファイル: test_types.py プロジェクト: tchen0123/synapse
    def test_parse(self):
        user = UserID.from_string("@1234abcd:my.domain")

        self.assertEquals("1234abcd", user.localpart)
        self.assertEquals("my.domain", user.domain)
        self.assertEquals(True, mock_homeserver.is_mine(user))
コード例 #37
0
    def _snapshot_all_rooms(self,
                            user_id=None,
                            pagin_config=None,
                            as_client_event=True,
                            include_archived=False):

        memberships = [Membership.INVITE, Membership.JOIN]
        if include_archived:
            memberships.append(Membership.LEAVE)

        room_list = yield self.store.get_rooms_for_user_where_membership_is(
            user_id=user_id, membership_list=memberships)

        user = UserID.from_string(user_id)

        rooms_ret = []

        now_token = yield self.hs.get_event_sources().get_current_token()

        presence_stream = self.hs.get_event_sources().sources["presence"]
        pagination_config = PaginationConfig(from_token=now_token)
        presence, _ = yield presence_stream.get_pagination_rows(
            user, pagination_config.get_source_config("presence"), None)

        receipt_stream = self.hs.get_event_sources().sources["receipt"]
        receipt, _ = yield receipt_stream.get_pagination_rows(
            user, pagination_config.get_source_config("receipt"), None)

        tags_by_room = yield self.store.get_tags_for_user(user_id)

        account_data, account_data_by_room = (
            yield self.store.get_account_data_for_user(user_id))

        public_room_ids = yield self.store.get_public_room_ids()

        limit = pagin_config.limit
        if limit is None:
            limit = 10

        @defer.inlineCallbacks
        def handle_room(event):
            d = {
                "room_id":
                event.room_id,
                "membership":
                event.membership,
                "visibility":
                ("public" if event.room_id in public_room_ids else "private"),
            }

            if event.membership == Membership.INVITE:
                time_now = self.clock.time_msec()
                d["inviter"] = event.sender

                invite_event = yield self.store.get_event(event.event_id)
                d["invite"] = serialize_event(invite_event, time_now,
                                              as_client_event)

            rooms_ret.append(d)

            if event.membership not in (Membership.JOIN, Membership.LEAVE):
                return

            try:
                if event.membership == Membership.JOIN:
                    room_end_token = now_token.room_key
                    deferred_room_state = self.state_handler.get_current_state(
                        event.room_id)
                elif event.membership == Membership.LEAVE:
                    room_end_token = "s%d" % (event.stream_ordering, )
                    deferred_room_state = self.store.get_state_for_events(
                        [event.event_id], None)
                    deferred_room_state.addCallback(
                        lambda states: states[event.event_id])

                (messages,
                 token), current_state = yield preserve_context_over_deferred(
                     defer.gatherResults([
                         preserve_fn(self.store.get_recent_events_for_room)(
                             event.room_id,
                             limit=limit,
                             end_token=room_end_token,
                         ),
                         deferred_room_state,
                     ])).addErrback(unwrapFirstError)

                messages = yield filter_events_for_client(
                    self.store, user_id, messages)

                start_token = now_token.copy_and_replace("room_key", token[0])
                end_token = now_token.copy_and_replace("room_key", token[1])
                time_now = self.clock.time_msec()

                d["messages"] = {
                    "chunk": [
                        serialize_event(m, time_now, as_client_event)
                        for m in messages
                    ],
                    "start":
                    start_token.to_string(),
                    "end":
                    end_token.to_string(),
                }

                d["state"] = [
                    serialize_event(c, time_now, as_client_event)
                    for c in current_state.values()
                ]

                account_data_events = []
                tags = tags_by_room.get(event.room_id)
                if tags:
                    account_data_events.append({
                        "type": "m.tag",
                        "content": {
                            "tags": tags
                        },
                    })

                account_data = account_data_by_room.get(event.room_id, {})
                for account_data_type, content in account_data.items():
                    account_data_events.append({
                        "type": account_data_type,
                        "content": content,
                    })

                d["account_data"] = account_data_events
            except:
                logger.exception("Failed to get snapshot")

        yield concurrently_execute(handle_room, room_list, 10)

        account_data_events = []
        for account_data_type, content in account_data.items():
            account_data_events.append({
                "type": account_data_type,
                "content": content,
            })

        ret = {
            "rooms": rooms_ret,
            "presence": presence,
            "account_data": account_data_events,
            "receipts": receipt,
            "end": now_token.to_string(),
        }

        defer.returnValue(ret)
コード例 #38
0
 def get_user_by_req(request, allow_guest=False, rights="access"):
     return synapse.types.create_requester(
         UserID.from_string(self.USER_ID), 1, False, None)
コード例 #39
0
    def create_and_send_event(self, event_dict, ratelimit=True,
                              token_id=None, txn_id=None, is_guest=False):
        """ Given a dict from a client, create and handle a new event.

        Creates an FrozenEvent object, filling out auth_events, prev_events,
        etc.

        Adds display names to Join membership events.

        Persists and notifies local clients and federation.

        Args:
            event_dict (dict): An entire event
        """
        builder = self.event_builder_factory.new(event_dict)

        self.validator.validate_new(builder)

        if ratelimit:
            self.ratelimit(builder.user_id)
        # TODO(paul): Why does 'event' not have a 'user' object?
        user = UserID.from_string(builder.user_id)
        assert self.hs.is_mine(user), "User must be our own: %s" % (user,)

        if builder.type == EventTypes.Member:
            membership = builder.content.get("membership", None)
            if membership == Membership.JOIN:
                joinee = UserID.from_string(builder.state_key)
                # If event doesn't include a display name, add one.
                yield collect_presencelike_data(
                    self.distributor, joinee, builder.content
                )

        if token_id is not None:
            builder.internal_metadata.token_id = token_id

        if txn_id is not None:
            builder.internal_metadata.txn_id = txn_id

        event, context = yield self._create_new_client_event(
            builder=builder,
        )

        if event.is_state():
            prev_state = context.current_state.get((event.type, event.state_key))
            if prev_state and event.user_id == prev_state.user_id:
                prev_content = encode_canonical_json(prev_state.content)
                next_content = encode_canonical_json(event.content)
                if prev_content == next_content:
                    # Duplicate suppression for state updates with same sender
                    # and content.
                    defer.returnValue(prev_state)

        if event.type == EventTypes.Member:
            member_handler = self.hs.get_handlers().room_member_handler
            yield member_handler.change_membership(event, context, is_guest=is_guest)
        else:
            yield self.handle_new_client_event(
                event=event,
                context=context,
            )

        if event.type == EventTypes.Message:
            presence = self.hs.get_handlers().presence_handler
            with PreserveLoggingContext():
                presence.bump_presence_active_time(user)

        defer.returnValue(event)
コード例 #40
0
 async def get_user_by_access_token(token=None, allow_guest=False):
     return {
         "user": UserID.from_string(self.helper.auth_user_id),
         "token_id": token_id,
         "is_guest": False,
     }
コード例 #41
0
    async def on_POST(self, request: SynapseRequest,
                      room_identifier: str) -> Tuple[int, JsonDict]:
        requester = await self.auth.get_user_by_req(request)
        await assert_user_is_admin(self.auth, requester.user)
        content = parse_json_object_from_request(request,
                                                 allow_empty_body=True)

        room_id, _ = await self.resolve_room_id(room_identifier)

        # Which user to grant room admin rights to.
        user_to_add = content.get("user_id", requester.user.to_string())

        # Figure out which local users currently have power in the room, if any.
        room_state = await self.state_handler.get_current_state(room_id)
        if not room_state:
            raise SynapseError(400, "Server not in room")

        create_event = room_state[(EventTypes.Create, "")]
        power_levels = room_state.get((EventTypes.PowerLevels, ""))

        if power_levels is not None:
            # We pick the local user with the highest power.
            user_power = power_levels.content.get("users", {})
            admin_users = [
                user_id for user_id in user_power if self.is_mine_id(user_id)
            ]
            admin_users.sort(key=lambda user: user_power[user])

            if not admin_users:
                raise SynapseError(400, "No local admin user in room")

            admin_user_id = None

            for admin_user in reversed(admin_users):
                (
                    current_membership_type,
                    _,
                ) = await self.store.get_local_current_membership_for_user_in_room(
                    admin_user, room_id)
                if current_membership_type == "join":
                    admin_user_id = admin_user
                    break

            if not admin_user_id:
                raise SynapseError(
                    400,
                    "No local admin user in room",
                )

            pl_content = power_levels.content
        else:
            # If there is no power level events then the creator has rights.
            pl_content = {}
            admin_user_id = create_event.sender
            if not self.is_mine_id(admin_user_id):
                raise SynapseError(
                    400,
                    "No local admin user in room",
                )

        # Grant the user power equal to the room admin by attempting to send an
        # updated power level event.
        new_pl_content = dict(pl_content)
        new_pl_content["users"] = dict(pl_content.get("users", {}))
        new_pl_content["users"][user_to_add] = new_pl_content["users"][
            admin_user_id]

        fake_requester = create_requester(
            admin_user_id,
            authenticated_entity=requester.authenticated_entity,
        )

        try:
            await self.event_creation_handler.create_and_send_nonmember_event(
                fake_requester,
                event_dict={
                    "content": new_pl_content,
                    "sender": admin_user_id,
                    "type": EventTypes.PowerLevels,
                    "state_key": "",
                    "room_id": room_id,
                },
            )
        except AuthError:
            # The admin user we found turned out not to have enough power.
            raise SynapseError(
                400,
                "No local admin user in room with power to update power levels."
            )

        # Now we check if the user we're granting admin rights to is already in
        # the room. If not and it's not a public room we invite them.
        member_event = room_state.get((EventTypes.Member, user_to_add))
        is_joined = False
        if member_event:
            is_joined = member_event.content["membership"] in (
                Membership.JOIN,
                Membership.INVITE,
            )

        if is_joined:
            return 200, {}

        join_rules = room_state.get((EventTypes.JoinRules, ""))
        is_public = False
        if join_rules:
            is_public = join_rules.content.get("join_rule") == JoinRules.PUBLIC

        if is_public:
            return 200, {}

        await self.room_member_handler.update_membership(
            fake_requester,
            target=UserID.from_string(user_to_add),
            room_id=room_id,
            action=Membership.INVITE,
        )

        return 200, {}
コード例 #42
0
ファイル: groups_server.py プロジェクト: syamgk/synapse
    def create_group(self, group_id, requester_user_id, content):
        group = yield self.check_group_is_ours(group_id, requester_user_id)

        logger.info("Attempting to create group with ID: %r", group_id)

        # parsing the id into a GroupID validates it.
        group_id_obj = GroupID.from_string(group_id)

        if group:
            raise SynapseError(400, "Group already exists")

        is_admin = yield self.auth.is_server_admin(
            UserID.from_string(requester_user_id))
        if not is_admin:
            if not self.hs.config.enable_group_creation:
                raise SynapseError(
                    403,
                    "Only a server admin can create groups on this server")
            localpart = group_id_obj.localpart
            if not localpart.startswith(self.hs.config.group_creation_prefix):
                raise SynapseError(
                    400,
                    "Can only create groups with prefix %r on this server" %
                    (self.hs.config.group_creation_prefix, ),
                )

        profile = content.get("profile", {})
        name = profile.get("name")
        avatar_url = profile.get("avatar_url")
        short_description = profile.get("short_description")
        long_description = profile.get("long_description")
        user_profile = content.get("user_profile", {})

        yield self.store.create_group(
            group_id,
            requester_user_id,
            name=name,
            avatar_url=avatar_url,
            short_description=short_description,
            long_description=long_description,
        )

        if not self.hs.is_mine_id(requester_user_id):
            remote_attestation = content["attestation"]

            yield self.attestations.verify_attestation(
                remote_attestation,
                user_id=requester_user_id,
                group_id=group_id)

            local_attestation = self.attestations.create_attestation(
                group_id, requester_user_id)
        else:
            local_attestation = None
            remote_attestation = None

        yield self.store.add_user_to_group(
            group_id,
            requester_user_id,
            is_admin=True,
            is_public=True,  # TODO
            local_attestation=local_attestation,
            remote_attestation=remote_attestation,
        )

        if not self.hs.is_mine_id(requester_user_id):
            yield self.store.add_remote_profile_cache(
                requester_user_id,
                displayname=user_profile.get("displayname"),
                avatar_url=user_profile.get("avatar_url"),
            )

        return {"group_id": group_id}
コード例 #43
0
ファイル: test_profile.py プロジェクト: timoschwarzer/synapse
    def setUp(self):
        hs = yield setup_test_homeserver(self.addCleanup)

        self.store = ProfileStore(None, hs)

        self.u_frank = UserID.from_string("@frank:test")
コード例 #44
0
ファイル: groups_server.py プロジェクト: syamgk/synapse
    def delete_group(self, group_id, requester_user_id):
        """Deletes a group, kicking out all current members.

        Only group admins or server admins can call this request

        Args:
            group_id (str)
            request_user_id (str)

        Returns:
            Deferred
        """

        yield self.check_group_is_ours(group_id,
                                       requester_user_id,
                                       and_exists=True)

        # Only server admins or group admins can delete groups.

        is_admin = yield self.store.is_user_admin_in_group(
            group_id, requester_user_id)

        if not is_admin:
            is_admin = yield self.auth.is_server_admin(
                UserID.from_string(requester_user_id))

        if not is_admin:
            raise SynapseError(403, "User is not an admin")

        # Before deleting the group lets kick everyone out of it
        users = yield self.store.get_users_in_group(group_id,
                                                    include_private=True)

        @defer.inlineCallbacks
        def _kick_user_from_group(user_id):
            if self.hs.is_mine_id(user_id):
                groups_local = self.hs.get_groups_local_handler()
                yield groups_local.user_removed_from_group(
                    group_id, user_id, {})
            else:
                yield self.transport_client.remove_user_from_group_notification(
                    get_domain_from_id(user_id), group_id, user_id, {})
                yield self.store.maybe_delete_remote_profile_cache(user_id)

        # We kick users out in the order of:
        #   1. Non-admins
        #   2. Other admins
        #   3. The requester
        #
        # This is so that if the deletion fails for some reason other admins or
        # the requester still has auth to retry.
        non_admins = []
        admins = []
        for u in users:
            if u["user_id"] == requester_user_id:
                continue
            if u["is_admin"]:
                admins.append(u["user_id"])
            else:
                non_admins.append(u["user_id"])

        yield concurrently_execute(_kick_user_from_group, non_admins, 10)
        yield concurrently_execute(_kick_user_from_group, admins, 10)
        yield _kick_user_from_group(requester_user_id)

        yield self.store.delete_group(group_id)
コード例 #45
0
ファイル: room.py プロジェクト: ocd-shepherd/synapse
    def create_room(self, user_id, room_id, config):
        """ Creates a new room.

        Args:
            user_id (str): The ID of the user creating the new room.
            room_id (str): The proposed ID for the new room. Can be None, in
            which case one will be created for you.
            config (dict) : A dict of configuration options.
        Returns:
            The new room ID.
        Raises:
            SynapseError if the room ID was taken, couldn't be stored, or
            something went horribly wrong.
        """
        self.ratelimit(user_id)

        if "room_alias_name" in config:
            for wchar in string.whitespace:
                if wchar in config["room_alias_name"]:
                    raise SynapseError(400, "Invalid characters in room alias")

            room_alias = RoomAlias.create(
                config["room_alias_name"],
                self.hs.hostname,
            )
            mapping = yield self.store.get_association_from_room_alias(
                room_alias)

            if mapping:
                raise SynapseError(400, "Room alias already taken")
        else:
            room_alias = None

        invite_list = config.get("invite", [])
        for i in invite_list:
            try:
                UserID.from_string(i)
            except:
                raise SynapseError(400, "Invalid user_id: %s" % (i, ))

        is_public = config.get("visibility", None) == "public"

        if room_id:
            # Ensure room_id is the correct type
            room_id_obj = RoomID.from_string(room_id)
            if not self.hs.is_mine(room_id_obj):
                raise SynapseError(400, "Room id must be local")

            yield self.store.store_room(room_id=room_id,
                                        room_creator_user_id=user_id,
                                        is_public=is_public)
        else:
            # autogen room IDs and try to create it. We may clash, so just
            # try a few times till one goes through, giving up eventually.
            attempts = 0
            room_id = None
            while attempts < 5:
                try:
                    random_string = stringutils.random_string(18)
                    gen_room_id = RoomID.create(
                        random_string,
                        self.hs.hostname,
                    )
                    yield self.store.store_room(
                        room_id=gen_room_id.to_string(),
                        room_creator_user_id=user_id,
                        is_public=is_public)
                    room_id = gen_room_id.to_string()
                    break
                except StoreError:
                    attempts += 1
            if not room_id:
                raise StoreError(500, "Couldn't generate a room ID.")

        if room_alias:
            directory_handler = self.hs.get_handlers().directory_handler
            yield directory_handler.create_association(
                user_id=user_id,
                room_id=room_id,
                room_alias=room_alias,
                servers=[self.hs.hostname],
            )

        preset_config = config.get(
            "preset", RoomCreationPreset.PUBLIC_CHAT
            if is_public else RoomCreationPreset.PRIVATE_CHAT)

        raw_initial_state = config.get("initial_state", [])

        initial_state = OrderedDict()
        for val in raw_initial_state:
            initial_state[(val["type"], val.get("state_key",
                                                ""))] = val["content"]

        user = UserID.from_string(user_id)
        creation_events = self._create_events_for_new_room(
            user,
            room_id,
            preset_config=preset_config,
            invite_list=invite_list,
            initial_state=initial_state,
        )

        msg_handler = self.hs.get_handlers().message_handler

        for event in creation_events:
            yield msg_handler.create_and_send_event(event, ratelimit=False)

        if "name" in config:
            name = config["name"]
            yield msg_handler.create_and_send_event(
                {
                    "type": EventTypes.Name,
                    "room_id": room_id,
                    "sender": user_id,
                    "state_key": "",
                    "content": {
                        "name": name
                    },
                },
                ratelimit=False)

        if "topic" in config:
            topic = config["topic"]
            yield msg_handler.create_and_send_event(
                {
                    "type": EventTypes.Topic,
                    "room_id": room_id,
                    "sender": user_id,
                    "state_key": "",
                    "content": {
                        "topic": topic
                    },
                },
                ratelimit=False)

        for invitee in invite_list:
            yield msg_handler.create_and_send_event(
                {
                    "type": EventTypes.Member,
                    "state_key": invitee,
                    "room_id": room_id,
                    "sender": user_id,
                    "content": {
                        "membership": Membership.INVITE
                    },
                },
                ratelimit=False)

        result = {"room_id": room_id}

        if room_alias:
            result["room_alias"] = room_alias.to_string()
            yield directory_handler.send_room_alias_update_event(
                user_id, room_id)

        defer.returnValue(result)
コード例 #46
0
ファイル: test_profile.py プロジェクト: localguru/synapse.LG
    def setUp(self):
        hs = yield setup_test_homeserver(self.addCleanup)

        self.store = hs.get_datastore()

        self.u_frank = UserID.from_string("@frank:test")
コード例 #47
0
ファイル: room.py プロジェクト: ocd-shepherd/synapse
    def get_room_members(self, room_id):
        users = yield self.store.get_users_in_room(room_id)

        defer.returnValue([UserID.from_string(u) for u in users])
コード例 #48
0
    def __init__(self, hs):
        """

        Args:
            hs (synapse.server.HomeServer):
        """
        self.hs = hs
        self.is_mine = hs.is_mine
        self.is_mine_id = hs.is_mine_id
        self.clock = hs.get_clock()
        self.store = hs.get_datastore()
        self.wheel_timer = WheelTimer()
        self.notifier = hs.get_notifier()
        self.federation = hs.get_federation_sender()
        self.state = hs.get_state_handler()

        federation_registry = hs.get_federation_registry()

        federation_registry.register_edu_handler("m.presence",
                                                 self.incoming_presence)
        federation_registry.register_edu_handler(
            "m.presence_invite", lambda origin, content: self.invite_presence(
                observed_user=UserID.from_string(content["observed_user"]),
                observer_user=UserID.from_string(content["observer_user"]),
            ))
        federation_registry.register_edu_handler(
            "m.presence_accept", lambda origin, content: self.accept_presence(
                observed_user=UserID.from_string(content["observed_user"]),
                observer_user=UserID.from_string(content["observer_user"]),
            ))
        federation_registry.register_edu_handler(
            "m.presence_deny", lambda origin, content: self.deny_presence(
                observed_user=UserID.from_string(content["observed_user"]),
                observer_user=UserID.from_string(content["observer_user"]),
            ))

        distributor = hs.get_distributor()
        distributor.observe("user_joined_room", self.user_joined_room)

        active_presence = self.store.take_presence_startup_info()

        # A dictionary of the current state of users. This is prefilled with
        # non-offline presence from the DB. We should fetch from the DB if
        # we can't find a users presence in here.
        self.user_to_current_state = {
            state.user_id: state
            for state in active_presence
        }

        LaterGauge("synapse_handlers_presence_user_to_current_state_size", "",
                   [], lambda: len(self.user_to_current_state))

        now = self.clock.time_msec()
        for state in active_presence:
            self.wheel_timer.insert(
                now=now,
                obj=state.user_id,
                then=state.last_active_ts + IDLE_TIMER,
            )
            self.wheel_timer.insert(
                now=now,
                obj=state.user_id,
                then=state.last_user_sync_ts + SYNC_ONLINE_TIMEOUT,
            )
            if self.is_mine_id(state.user_id):
                self.wheel_timer.insert(
                    now=now,
                    obj=state.user_id,
                    then=state.last_federation_update_ts +
                    FEDERATION_PING_INTERVAL,
                )
            else:
                self.wheel_timer.insert(
                    now=now,
                    obj=state.user_id,
                    then=state.last_federation_update_ts + FEDERATION_TIMEOUT,
                )

        # Set of users who have presence in the `user_to_current_state` that
        # have not yet been persisted
        self.unpersisted_users_changes = set()

        hs.get_reactor().addSystemEventTrigger("before", "shutdown",
                                               self._on_shutdown)

        self.serial_to_user = {}
        self._next_serial = 1

        # Keeps track of the number of *ongoing* syncs on this process. While
        # this is non zero a user will never go offline.
        self.user_to_num_current_syncs = {}

        # Keeps track of the number of *ongoing* syncs on other processes.
        # While any sync is ongoing on another process the user will never
        # go offline.
        # Each process has a unique identifier and an update frequency. If
        # no update is received from that process within the update period then
        # we assume that all the sync requests on that process have stopped.
        # Stored as a dict from process_id to set of user_id, and a dict of
        # process_id to millisecond timestamp last updated.
        self.external_process_to_current_syncs = {}
        self.external_process_last_updated_ms = {}
        self.external_sync_linearizer = Linearizer(
            name="external_sync_linearizer")

        # Start a LoopingCall in 30s that fires every 5s.
        # The initial delay is to allow disconnected clients a chance to
        # reconnect before we treat them as offline.
        self.clock.call_later(
            30,
            self.clock.looping_call,
            self._handle_timeouts,
            5000,
        )

        self.clock.call_later(
            60,
            self.clock.looping_call,
            self._persist_unpersisted_changes,
            60 * 1000,
        )

        LaterGauge("synapse_handlers_presence_wheel_timer_size", "", [],
                   lambda: len(self.wheel_timer))
コード例 #49
0
    def on_send_join_request(self, origin, pdu):
        """ We have received a join event for a room. Fully process it and
        respond with the current state and auth chains.
        """
        event = pdu

        logger.debug(
            "on_send_join_request: Got event: %s, signatures: %s",
            event.event_id,
            event.signatures,
        )

        event.internal_metadata.outlier = False

        context, event_stream_id, max_stream_id = yield self._handle_new_event(
            origin, event)

        logger.debug(
            "on_send_join_request: After _handle_new_event: %s, sigs: %s",
            event.event_id,
            event.signatures,
        )

        extra_users = []
        if event.type == EventTypes.Member:
            target_user_id = event.state_key
            target_user = UserID.from_string(target_user_id)
            extra_users.append(target_user)

        with PreserveLoggingContext():
            d = self.notifier.on_new_room_event(event,
                                                event_stream_id,
                                                max_stream_id,
                                                extra_users=extra_users)

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

        d.addErrback(log_failure)

        if event.type == EventTypes.Member:
            if event.content["membership"] == Membership.JOIN:
                user = UserID.from_string(event.state_key)
                yield self.distributor.fire("user_joined_room",
                                            user=user,
                                            room_id=event.room_id)

        new_pdu = event

        destinations = set()

        for k, s in context.current_state.items():
            try:
                if k[0] == EventTypes.Member:
                    if s.content["membership"] == Membership.JOIN:
                        destinations.add(
                            UserID.from_string(s.state_key).domain)
            except:
                logger.warn("Failed to get destination from event %s",
                            s.event_id)

        destinations.discard(origin)

        logger.debug(
            "on_send_join_request: Sending event: %s, signatures: %s",
            event.event_id,
            event.signatures,
        )

        self.replication_layer.send_pdu(new_pdu, destinations)

        state_ids = [e.event_id for e in context.current_state.values()]
        auth_chain = yield self.store.get_auth_chain(
            set([event.event_id] + state_ids))

        defer.returnValue({
            "state": context.current_state.values(),
            "auth_chain": auth_chain,
        })
コード例 #50
0
ファイル: room.py プロジェクト: ocd-shepherd/synapse
    def _do_join(self, event, context, room_hosts=None, do_auth=True):
        joinee = UserID.from_string(event.state_key)
        # room_id = RoomID.from_string(event.room_id, self.hs)
        room_id = event.room_id

        # XXX: We don't do an auth check if we are doing an invite
        # join dance for now, since we're kinda implicitly checking
        # that we are allowed to join when we decide whether or not we
        # need to do the invite/join dance.

        is_host_in_room = yield self.auth.check_host_in_room(
            event.room_id, self.hs.hostname)
        if not is_host_in_room:
            # is *anyone* in the room?
            room_member_keys = [
                v for (k, v) in context.current_state.keys()
                if (k == "m.room.member")
            ]
            if len(room_member_keys) == 0:
                # has the room been created so we can join it?
                create_event = context.current_state.get(("m.room.create", ""))
                if create_event:
                    is_host_in_room = True

        if is_host_in_room:
            should_do_dance = False
        elif room_hosts:  # TODO: Shouldn't this be remote_room_host?
            should_do_dance = True
        else:
            # TODO(markjh): get prev_state from snapshot
            prev_state = yield self.store.get_room_member(
                joinee.to_string(), room_id)

            if prev_state and prev_state.membership == Membership.INVITE:
                inviter = UserID.from_string(prev_state.user_id)

                should_do_dance = not self.hs.is_mine(inviter)
                room_hosts = [inviter.domain]
            else:
                # return the same error as join_room_alias does
                raise SynapseError(404, "No known servers")

        if should_do_dance:
            handler = self.hs.get_handlers().federation_handler
            yield handler.do_invite_join(
                room_hosts,
                room_id,
                event.user_id,
                event.content,  # FIXME To get a non-frozen dict
                context)
        else:
            logger.debug("Doing normal join")

            yield self._do_local_membership_update(
                event,
                membership=event.content["membership"],
                context=context,
                do_auth=do_auth,
            )

        user = UserID.from_string(event.user_id)
        yield self.distributor.fire("user_joined_room",
                                    user=user,
                                    room_id=room_id)
コード例 #51
0
ファイル: devicemessage.py プロジェクト: ZOE-Cash/zoe-matrix
    async def send_device_message(
        self,
        requester: Requester,
        message_type: str,
        messages: Dict[str, Dict[str, JsonDict]],
    ) -> None:
        sender_user_id = requester.user.to_string()

        set_tag("number_of_messages", len(messages))
        set_tag("sender", sender_user_id)
        local_messages = {}
        remote_messages = {}  # type: Dict[str, Dict[str, Dict[str, JsonDict]]]
        for user_id, by_device in messages.items():
            # Ratelimit local cross-user key requests by the sending device.
            if (message_type == EduTypes.RoomKeyRequest
                    and user_id != sender_user_id
                    and self._ratelimiter.can_do_action(
                        (sender_user_id, requester.device_id))):
                continue

            # we use UserID.from_string to catch invalid user ids
            if self.is_mine(UserID.from_string(user_id)):
                messages_by_device = {
                    device_id: {
                        "content": message_content,
                        "type": message_type,
                        "sender": sender_user_id,
                    }
                    for device_id, message_content in by_device.items()
                }
                if messages_by_device:
                    local_messages[user_id] = messages_by_device
            else:
                destination = get_domain_from_id(user_id)
                remote_messages.setdefault(destination,
                                           {})[user_id] = by_device

        message_id = random_string(16)

        context = get_active_span_text_map()

        remote_edu_contents = {}
        for destination, messages in remote_messages.items():
            with start_active_span("to_device_for_user"):
                set_tag("destination", destination)
                remote_edu_contents[destination] = {
                    "messages": messages,
                    "sender": sender_user_id,
                    "type": message_type,
                    "message_id": message_id,
                    "org.matrix.opentracing_context":
                    json_encoder.encode(context),
                }

        log_kv({"local_messages": local_messages})
        stream_id = await self.store.add_messages_to_device_inbox(
            local_messages, remote_edu_contents)

        self.notifier.on_new_event("to_device_key",
                                   stream_id,
                                   users=local_messages.keys())

        log_kv({"remote_messages": remote_messages})
        if self.federation_sender:
            for destination in remote_messages.keys():
                # Enqueue a new federation transaction to send the new
                # device messages to each remote destination.
                self.federation_sender.send_device_messages(destination)
コード例 #52
0
    def prepare(self, reactor: MemoryReactor, clock: Clock, hs: HomeServer) -> None:
        self.store = hs.get_datastore()

        self.u_frank = UserID.from_string("@frank:test")
コード例 #53
0
    def on_receive_pdu(self,
                       origin,
                       pdu,
                       backfilled,
                       state=None,
                       auth_chain=None):
        """ Called by the ReplicationLayer when we have a new pdu. We need to
        do auth checks and put it through the StateHandler.
        """
        event = pdu

        logger.debug("Got event: %s", event.event_id)

        # If we are currently in the process of joining this room, then we
        # queue up events for later processing.
        if event.room_id in self.room_queues:
            self.room_queues[event.room_id].append((pdu, origin))
            return

        logger.debug("Processing event: %s", event.event_id)

        logger.debug("Event: %s", event)

        # FIXME (erikj): Awful hack to make the case where we are not currently
        # in the room work
        current_state = None
        is_in_room = yield self.auth.check_host_in_room(
            event.room_id, self.server_name)
        if not is_in_room and not event.internal_metadata.is_outlier():
            logger.debug("Got event for room we're not in.")
            current_state = state

        event_ids = set()
        if state:
            event_ids |= {e.event_id for e in state}
        if auth_chain:
            event_ids |= {e.event_id for e in auth_chain}

        seen_ids = set((yield self.store.have_events(event_ids)).keys())

        if state and auth_chain is not None:
            # If we have any state or auth_chain given to us by the replication
            # layer, then we should handle them (if we haven't before.)

            event_infos = []

            for e in itertools.chain(auth_chain, state):
                if e.event_id in seen_ids:
                    continue
                e.internal_metadata.outlier = True
                auth_ids = [e_id for e_id, _ in e.auth_events]
                auth = {(e.type, e.state_key): e
                        for e in auth_chain if e.event_id in auth_ids}
                event_infos.append({
                    "event": e,
                    "auth_events": auth,
                })
                seen_ids.add(e.event_id)

            yield self._handle_new_events(origin, event_infos, outliers=True)

        try:
            _, event_stream_id, max_stream_id = yield self._handle_new_event(
                origin,
                event,
                state=state,
                backfilled=backfilled,
                current_state=current_state,
            )
        except AuthError as e:
            raise FederationError(
                "ERROR",
                e.code,
                e.msg,
                affected=event.event_id,
            )

        # if we're receiving valid events from an origin,
        # it's probably a good idea to mark it as not in retry-state
        # for sending (although this is a bit of a leap)
        retry_timings = yield self.store.get_destination_retry_timings(origin)
        if retry_timings and retry_timings["retry_last_ts"]:
            self.store.set_destination_retry_timings(origin, 0, 0)

        room = yield self.store.get_room(event.room_id)

        if not room:
            try:
                yield self.store.store_room(
                    room_id=event.room_id,
                    room_creator_user_id="",
                    is_public=False,
                )
            except StoreError:
                logger.exception("Failed to store room.")

        if not backfilled:
            extra_users = []
            if event.type == EventTypes.Member:
                target_user_id = event.state_key
                target_user = UserID.from_string(target_user_id)
                extra_users.append(target_user)

            with PreserveLoggingContext():
                d = self.notifier.on_new_room_event(event,
                                                    event_stream_id,
                                                    max_stream_id,
                                                    extra_users=extra_users)

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

            d.addErrback(log_failure)

        if event.type == EventTypes.Member:
            if event.membership == Membership.JOIN:
                user = UserID.from_string(event.state_key)
                yield self.distributor.fire("user_joined_room",
                                            user=user,
                                            room_id=event.room_id)
コード例 #54
0
ファイル: filtering.py プロジェクト: lxndrbnsv/synapse
def matrix_user_id_validator(user_id_str: str) -> UserID:
    return UserID.from_string(user_id_str)
コード例 #55
0
 def test_pase_empty(self):
     with self.assertRaises(SynapseError):
         UserID.from_string("")
コード例 #56
0
    def _register_user(
        self,
        txn,
        user_id,
        password_hash,
        was_guest,
        make_guest,
        appservice_id,
        create_profile_with_displayname,
        admin,
        user_type,
    ):
        user_id_obj = UserID.from_string(user_id)

        now = int(self.clock.time())

        try:
            if was_guest:
                # Ensure that the guest user actually exists
                # ``allow_none=False`` makes this raise an exception
                # if the row isn't in the database.
                self._simple_select_one_txn(
                    txn,
                    "users",
                    keyvalues={
                        "name": user_id,
                        "is_guest": 1
                    },
                    retcols=("name", ),
                    allow_none=False,
                )

                self._simple_update_one_txn(
                    txn,
                    "users",
                    keyvalues={
                        "name": user_id,
                        "is_guest": 1
                    },
                    updatevalues={
                        "password_hash": password_hash,
                        "upgrade_ts": now,
                        "is_guest": 1 if make_guest else 0,
                        "appservice_id": appservice_id,
                        "admin": 1 if admin else 0,
                        "user_type": user_type,
                    },
                )
            else:
                self._simple_insert_txn(
                    txn,
                    "users",
                    values={
                        "name": user_id,
                        "password_hash": password_hash,
                        "creation_ts": now,
                        "is_guest": 1 if make_guest else 0,
                        "appservice_id": appservice_id,
                        "admin": 1 if admin else 0,
                        "user_type": user_type,
                    },
                )

        except self.database_engine.module.IntegrityError:
            raise StoreError(400,
                             "User ID already taken.",
                             errcode=Codes.USER_IN_USE)

        if self._account_validity.enabled:
            self.set_expiration_date_for_user_txn(txn, user_id)

        if create_profile_with_displayname:
            # set a default displayname serverside to avoid ugly race
            # between auto-joins and clients trying to set displaynames
            #
            # *obviously* the 'profiles' table uses localpart for user_id
            # while everything else uses the full mxid.
            txn.execute(
                "INSERT INTO profiles(user_id, displayname) VALUES (?,?)",
                (user_id_obj.localpart, create_profile_with_displayname),
            )

        self._invalidate_cache_and_stream(txn, self.get_user_by_id,
                                          (user_id, ))
        txn.call_after(self.is_guest.invalidate, (user_id, ))
コード例 #57
0
ファイル: room_member.py プロジェクト: meharimg/swarm-im
    def send_membership_event(
        self,
        requester,
        event,
        context,
        remote_room_hosts=None,
        ratelimit=True,
    ):
        """
        Change the membership status of a user in a room.

        Args:
            requester (Requester): The local user who requested the membership
                event. If None, certain checks, like whether this homeserver can
                act as the sender, will be skipped.
            event (SynapseEvent): The membership event.
            context: The context of the event.
            is_guest (bool): Whether the sender is a guest.
            room_hosts ([str]): Homeservers which are likely to already be in
                the room, and could be danced with in order to join this
                homeserver for the first time.
            ratelimit (bool): Whether to rate limit this request.
        Raises:
            SynapseError if there was a problem changing the membership.
        """
        remote_room_hosts = remote_room_hosts or []

        target_user = UserID.from_string(event.state_key)
        room_id = event.room_id

        if requester is not None:
            sender = UserID.from_string(event.sender)
            assert sender == requester.user, (
                "Sender (%s) must be same as requester (%s)" %
                (sender, requester.user))
            assert self.hs.is_mine(
                sender), "Sender must be our own: %s" % (sender, )
        else:
            requester = synapse.types.create_requester(target_user)

        message_handler = self.hs.get_handlers().message_handler
        prev_event = yield message_handler.deduplicate_state_event(
            event, context)
        if prev_event is not None:
            return

        if event.membership == Membership.JOIN:
            if requester.is_guest:
                guest_can_join = yield self._can_guest_join(
                    context.prev_state_ids)
                if not guest_can_join:
                    # This should be an auth check, but guests are a local concept,
                    # so don't really fit into the general auth process.
                    raise AuthError(403, "Guest access not allowed")

        if event.membership not in (Membership.LEAVE, Membership.BAN):
            is_blocked = yield self.store.is_room_blocked(room_id)
            if is_blocked:
                raise SynapseError(
                    403, "This room has been blocked on this server")

        yield message_handler.handle_new_client_event(
            requester,
            event,
            context,
            extra_users=[target_user],
            ratelimit=ratelimit,
        )

        prev_member_event_id = context.prev_state_ids.get(
            (EventTypes.Member, event.state_key), None)

        if event.membership == Membership.JOIN:
            # Only fire user_joined_room if the user has acutally joined the
            # room. Don't bother if the user is just changing their profile
            # info.
            newly_joined = True
            if prev_member_event_id:
                prev_member_event = yield self.store.get_event(
                    prev_member_event_id)
                newly_joined = prev_member_event.membership != Membership.JOIN
            if newly_joined:
                yield user_joined_room(self.distributor, target_user, room_id)
        elif event.membership == Membership.LEAVE:
            if prev_member_event_id:
                prev_member_event = yield self.store.get_event(
                    prev_member_event_id)
                if prev_member_event.membership == Membership.JOIN:
                    user_left_room(self.distributor, target_user, room_id)
コード例 #58
0
    def handle_new_client_event(self,
                                requester,
                                event,
                                context,
                                ratelimit=True,
                                extra_users=[]):
        # We now need to go and hit out to wherever we need to hit out to.

        if ratelimit:
            self.ratelimit(requester)

        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

        yield self.maybe_kick_guest_users(event, context)

        if event.type == EventTypes.CanonicalAlias:
            # Check the alias is acually valid (at this time at least)
            room_alias_str = event.content.get("alias", None)
            if room_alias_str:
                room_alias = RoomAlias.from_string(room_alias_str)
                directory_handler = self.hs.get_handlers().directory_handler
                mapping = yield directory_handler.get_association(room_alias)

                if mapping["room_id"] != event.room_id:
                    raise SynapseError(
                        400, "Room alias %s does not point to the room" %
                        (room_alias_str, ))

        federation_handler = self.hs.get_handlers().federation_handler

        if event.type == EventTypes.Member:
            if event.content["membership"] == Membership.INVITE:

                def is_inviter_member_event(e):
                    return (e.type == EventTypes.Member
                            and e.sender == event.sender)

                state_to_include_ids = [
                    e_id for k, e_id in context.current_state_ids.items()
                    if k[0] in self.hs.config.room_invite_state_types
                    or k[0] == EventTypes.Member and k[1] == event.sender
                ]

                state_to_include = yield self.store.get_events(
                    state_to_include_ids)

                event.unsigned["invite_room_state"] = [{
                    "type": e.type,
                    "state_key": e.state_key,
                    "content": e.content,
                    "sender": e.sender,
                } for e in state_to_include.values()]

                invitee = UserID.from_string(event.state_key)
                if not self.hs.is_mine(invitee):
                    # TODO: Can we add signature from remote server in a nicer
                    # way? If we have been invited by a remote server, we need
                    # to get them to sign the event.

                    returned_invite = yield federation_handler.send_invite(
                        invitee.domain,
                        event,
                    )

                    event.unsigned.pop("room_state", None)

                    # TODO: Make sure the signatures actually are correct.
                    event.signatures.update(returned_invite.signatures)

        if event.type == EventTypes.Redaction:
            auth_events_ids = yield self.auth.compute_auth_events(
                event,
                context.prev_state_ids,
                for_verification=True,
            )
            auth_events = yield self.store.get_events(auth_events_ids)
            auth_events = {(e.type, e.state_key): e
                           for e in auth_events.values()}
            if self.auth.check_redaction(event, auth_events=auth_events):
                original_event = yield self.store.get_event(
                    event.redacts,
                    check_redacted=False,
                    get_prev_content=False,
                    allow_rejected=False,
                    allow_none=False)
                if event.user_id != original_event.user_id:
                    raise AuthError(
                        403, "You don't have permission to redact events")

        if event.type == EventTypes.Create and context.prev_state_ids:
            raise AuthError(
                403,
                "Changing the room create event is forbidden",
            )

        action_generator = ActionGenerator(self.hs)
        yield action_generator.handle_push_actions_for_event(event, context)

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

        # this intentionally does not yield: we don't care about the result
        # and don't need to wait for it.
        preserve_fn(self.hs.get_pusherpool().on_new_notifications)(
            event_stream_id, max_stream_id)

        users_in_room = yield self.store.get_joined_users_from_context(
            event, context)

        destinations = [
            get_domain_from_id(user_id) for user_id in users_in_room
            if not self.hs.is_mine_id(user_id)
        ]

        @defer.inlineCallbacks
        def _notify():
            yield run_on_reactor()
            yield self.notifier.on_new_room_event(event,
                                                  event_stream_id,
                                                  max_stream_id,
                                                  extra_users=extra_users)

        preserve_fn(_notify)()

        # If invite, remove room_state from unsigned before sending.
        event.unsigned.pop("invite_room_state", None)

        preserve_fn(federation_handler.handle_new_event)(
            event,
            destinations=destinations,
        )
コード例 #59
0
 def get_user_by_access_token(token=None, allow_guest=False):
     return {
         "user": UserID.from_string(self.USER_ID),
         "token_id": 1,
         "is_guest": False,
     }
コード例 #60
0
    def _room_initial_sync_joined(self, user_id, room_id, pagin_config,
                                  membership, is_guest):
        current_state = yield self.state.get_current_state(
            room_id=room_id,
        )

        # TODO(paul): I wish I was called with user objects not user_id
        #   strings...
        auth_user = UserID.from_string(user_id)

        # TODO: These concurrently
        time_now = self.clock.time_msec()
        state = [
            serialize_event(x, time_now)
            for x in current_state.values()
        ]

        now_token = yield self.hs.get_event_sources().get_current_token()

        limit = pagin_config.limit if pagin_config else None
        if limit is None:
            limit = 10

        room_members = [
            m for m in current_state.values()
            if m.type == EventTypes.Member
            and m.content["membership"] == Membership.JOIN
        ]

        presence_handler = self.hs.get_handlers().presence_handler

        @defer.inlineCallbacks
        def get_presence():
            states = yield presence_handler.get_states(
                target_users=[UserID.from_string(m.user_id) for m in room_members],
                auth_user=auth_user,
                as_event=True,
                check_auth=False,
            )

            defer.returnValue(states.values())

        @defer.inlineCallbacks
        def get_receipts():
            receipts_handler = self.hs.get_handlers().receipts_handler
            receipts = yield receipts_handler.get_receipts_for_room(
                room_id,
                now_token.receipt_key
            )
            defer.returnValue(receipts)

        presence, receipts, (messages, token) = yield defer.gatherResults(
            [
                get_presence(),
                get_receipts(),
                self.store.get_recent_events_for_room(
                    room_id,
                    limit=limit,
                    end_token=now_token.room_key,
                )
            ],
            consumeErrors=True,
        ).addErrback(unwrapFirstError)

        messages = yield self._filter_events_for_client(
            user_id, messages, is_guest=is_guest, require_all_visible_for_guests=False
        )

        start_token = now_token.copy_and_replace("room_key", token[0])
        end_token = now_token.copy_and_replace("room_key", token[1])

        time_now = self.clock.time_msec()

        ret = {
            "room_id": room_id,
            "messages": {
                "chunk": [serialize_event(m, time_now) for m in messages],
                "start": start_token.to_string(),
                "end": end_token.to_string(),
            },
            "state": state,
            "presence": presence,
            "receipts": receipts,
        }
        if not is_guest:
            ret["membership"] = membership

        defer.returnValue(ret)