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