Exemplo n.º 1
0
async def message_router(receive_queue, send_queue, proxies):
    """Find the recipient of a message and forward it to the right proxy."""
    def find_proxy_by_user(user):
        # type: (str) -> Optional[ProxyDaemon]
        for proxy in proxies:
            if user in proxy.pan_clients:
                return proxy

        return None

    async def send_info(message_id, pan_user, code, string):
        message = DaemonResponse(message_id, pan_user, code, string)
        await send_queue.put(message)

    while True:
        message = await receive_queue.get()
        logger.debug(f"Router got message {message}")

        proxy = find_proxy_by_user(message.pan_user)

        if not proxy:
            msg = f"No pan client found for {message.pan_user}."
            logger.warn(msg)
            await send_info(message.message_id, message.pan_user,
                            "m.unknown_client", msg)

        await proxy.receive_message(message)
Exemplo n.º 2
0
    def decrypt_messages_body(self, body, ignore_failures=True):
        # type: (Dict[Any, Any], bool) -> Dict[Any, Any]
        """Go through a messages response and decrypt megolm encrypted events.

        Args:
            body (Dict[Any, Any]): The dictionary of a Sync response.

        Returns the json response with decrypted events.
        """
        if "chunk" not in body:
            return body

        logger.info("Decrypting room messages")

        for event in body["chunk"]:
            if "type" not in event:
                continue

            if event["type"] != "m.room.encrypted":
                logger.debug("Event is not encrypted: " "\n{}".format(pformat(event)))
                continue

            self.pan_decrypt_event(event, ignore_failures=ignore_failures)

        return body
Exemplo n.º 3
0
    def pan_decrypt_event(self,
                          event_dict,
                          room_id=None,
                          ignore_failures=True):
        # type: (Dict[Any, Any], Optional[str], bool) -> (bool)
        event = Event.parse_encrypted_event(event_dict)

        if not isinstance(event, MegolmEvent):
            logger.warn("Encrypted event is not a megolm event:"
                        "\n{}".format(pformat(event_dict)))
            return False

        if not event.room_id:
            event.room_id = room_id

        try:
            decrypted_event = self.decrypt_event(event)
            logger.debug("Decrypted event: {}".format(decrypted_event))
            logger.info("Decrypted event from {} in {}, event id: {}".format(
                decrypted_event.sender,
                decrypted_event.room_id,
                decrypted_event.event_id,
            ))

            if isinstance(decrypted_event, RoomEncryptedMedia):
                self.store_event_media(decrypted_event)

                decrypted_event.source["content"]["url"] = decrypted_event.url

                if decrypted_event.thumbnail_url:
                    decrypted_event.source["content"]["info"][
                        "thumbnail_url"] = decrypted_event.thumbnail_url

            event_dict.update(decrypted_event.source)
            event_dict["decrypted"] = True
            event_dict["verified"] = decrypted_event.verified

            return True

        except EncryptionError as error:
            logger.warn(error)

            if ignore_failures:
                event_dict.update(self.unable_to_decrypt)
            else:
                raise

            return False
Exemplo n.º 4
0
    async def fetcher_loop(self):
        assert INDEXING_ENABLED

        for t in self.pan_store.load_fetcher_tasks(self.server_name, self.user_id):
            await self.history_fetch_queue.put(t)

        while True:
            self.fetch_loop_event.set()
            self.fetch_loop_event.clear()

            try:
                await asyncio.sleep(self.pan_conf.history_fetch_delay)
                fetch_task = await self.history_fetch_queue.get()

                try:
                    room = self.rooms[fetch_task.room_id]
                except KeyError:
                    # The room is missing from our client, we probably left the
                    # room.
                    self.delete_fetcher_task(fetch_task)
                    continue

                try:
                    logger.debug(
                        f"Fetching room history for {room.display_name} "
                        f"({room.room_id}), token {fetch_task.token}."
                    )
                    response = await self.room_messages(
                        fetch_task.room_id,
                        fetch_task.token,
                        limit=self.pan_conf.indexing_batch_size,
                    )
                except ClientConnectionError as e:
                    logger.debug("Error fetching room history: ", e)
                    await self.history_fetch_queue.put(fetch_task)

                # The chunk was empty, we're at the start of the timeline.
                if not response.chunk:
                    self.delete_fetcher_task(fetch_task)
                    continue

                for event in response.chunk:
                    if not isinstance(
                        event,
                        (
                            RoomMessageText,
                            RoomMessageMedia,
                            RoomEncryptedMedia,
                            RoomTopicEvent,
                            RoomNameEvent,
                        ),
                    ):
                        continue

                    display_name = room.user_name(event.sender)
                    avatar_url = room.avatar_url(event.sender)
                    self.index.add_event(event, room.room_id, display_name, avatar_url)

                last_event = response.chunk[-1]

                if not self.index.event_in_store(last_event.event_id, room.room_id):
                    # There may be even more events to fetch, add a new task to
                    # the queue.
                    task = FetchTask(room.room_id, response.end)
                    self.pan_store.replace_fetcher_task(
                        self.server_name, self.user_id, fetch_task, task
                    )
                    await self.history_fetch_queue.put(task)
                    self.new_fetch_task.set()
                    self.new_fetch_task.clear()
                else:
                    await self.index.commit_events()
                    self.delete_fetcher_task(fetch_task)

            except (asyncio.CancelledError, KeyboardInterrupt):
                return
Exemplo n.º 5
0
        def message_callback(self):
            try:
                message = self.receive_queue.get_nowait()
            except Empty:
                return True

            logger.debug(f"UI loop received message {message}")

            if isinstance(message, UpdateDevicesMessage):
                self.device_if.update_devices(message)

            elif isinstance(message, UpdateUsersMessage):
                self.control_if.update_users(message)

            elif isinstance(message, UnverifiedDevicesSignal):
                self.control_if.UnverifiedDevices(message.pan_user,
                                                  message.room_id,
                                                  message.room_display_name)

                if self.notifications:
                    self.unverified_notification(message)

            elif isinstance(message, InviteSasSignal):
                self.device_if.VerificationInvite(
                    message.pan_user,
                    message.user_id,
                    message.device_id,
                    message.transaction_id,
                )

                if self.notifications:
                    self.sas_invite_notification(message)

            elif isinstance(message, ShowSasSignal):
                self.device_if.VerificationString(
                    message.pan_user,
                    message.user_id,
                    message.device_id,
                    message.transaction_id,
                    message.emoji,
                )

                if self.notifications:
                    self.sas_show_notification(message)

            elif isinstance(message, SasDoneSignal):
                self.device_if.VerificationDone(
                    message.pan_user,
                    message.user_id,
                    message.device_id,
                    message.transaction_id,
                )

                if self.notifications:
                    self.sas_done_notification(message)

            elif isinstance(message, DaemonResponse):
                self.control_if.Response(
                    message.message_id,
                    message.pan_user,
                    {
                        "code": message.code,
                        "message": message.message
                    },
                )

            elif isinstance(message, KeyRequestMessage):
                self.device_if.update_key_requests(message)

            self.receive_queue.task_done()
            return True