async def _download_matrix_media(self, message: MediaMessageEventContent) -> str: if message.file: data = await self.main_intent.download_media(message.file.url) data = decrypt_attachment(data, message.file.key.key, message.file.hashes.get("sha256"), message.file.iv) else: data = await self.main_intent.download_media(message.url) filename = f"mautrix-signal-{str(uuid4())}" attachment_dir = self.config["signal.outgoing_attachment_dir"] path = os.path.join(attachment_dir, filename) with open(path, "wb") as file: file.write(data) # The bridge and signald can share files but have different filepaths. This can happen in # a Docker deployment when signald and this bridge are in different containers. In this # case, convert the file path from one context to another signald_relative_attachment_dir = self.config[ "signal.incoming_attachment_dir"] if signald_relative_attachment_dir is None: # Return the path in the context of the bridge return path self.log.debug( f"Changing attachment directory from {attachment_dir} to {signald_relative_attachment_dir}" ) # Return the path in the context of signald return os.path.join(signald_relative_attachment_dir, filename)
async def _handle_matrix_image(self, sender: 'u.User', message: MediaMessageEventContent) -> Optional[str]: if message.file and decrypt_attachment: data = await self.main_intent.download_media(message.file.url) data = decrypt_attachment(data, message.file.key.key, message.file.hashes.get("sha256"), message.file.iv) elif message.url: data = await self.main_intent.download_media(message.url) else: return None image = await sender.client.upload_image(io.BytesIO(data), filename=message.body) return await sender.send_image(self.gid, image)
async def _download_matrix_media(self, message: MediaMessageEventContent) -> str: if message.file: data = await self.main_intent.download_media(message.file.url) data = decrypt_attachment(data, message.file.key.key, message.file.hashes.get("sha256"), message.file.iv) else: data = await self.main_intent.download_media(message.url) path = os.path.join(self.config["signal.outgoing_attachment_dir"], f"mautrix-signal-{str(uuid4())}") with open(path, "wb") as file: file.write(data) return path
async def handle_matrix_message(self, sender: 'u.User', message: MessageEventContent, event_id: EventID) -> None: if not sender.client: self.log.debug( f"Ignoring message {event_id} as user is not connected") return elif ((message.get(self.bridge.real_user_content_key, False) and await p.Puppet.get_by_custom_mxid(sender.mxid))): self.log.debug( f"Ignoring puppet-sent message by confirmed puppet user {sender.mxid}" ) return request_id = str(sender.client.new_request_id()) self._reqid_dedup.add(request_id) text = message.body media_id = None if message.msgtype == MessageType.EMOTE: text = f"/me {text}" elif message.msgtype.is_media: if message.file and decrypt_attachment: data = await self.main_intent.download_media(message.file.url) data = decrypt_attachment(data, message.file.key.key, message.file.hashes.get("sha256"), message.file.iv) else: data = await self.main_intent.download_media(message.url) mime_type = message.info.mimetype or magic.from_buffer(data, mime=True) # TODO this will throw errors if the mime type is not supported # those errors should be sent back to the client upload_resp = await sender.client.upload(data, mime_type=mime_type) media_id = upload_resp.media_id text = "" resp = await sender.client.conversation(self.twid ).send(text, media_id=media_id, request_id=request_id) resp_msg_id = int(resp.entries[0].message.id) self._msgid_dedup.appendleft(resp_msg_id) msg = DBMessage(mxid=event_id, mx_room=self.mxid, twid=resp_msg_id, receiver=self.receiver) await msg.insert() self._reqid_dedup.remove(request_id) await self._send_delivery_receipt(event_id) self.log.debug(f"Handled Matrix message {event_id} -> {resp_msg_id}")
async def _handle_matrix_message(self, sender: 'u.User', message: MessageEventContent, event_id: EventID) -> None: request_id = str(sender.client.new_request_id()) self._reqid_dedup.add(request_id) text = message.body media_id = None if message.msgtype == MessageType.EMOTE: text = f"/me {text}" elif message.msgtype.is_media: if message.file and decrypt_attachment: data = await self.main_intent.download_media(message.file.url) data = decrypt_attachment(data, message.file.key.key, message.file.hashes.get("sha256"), message.file.iv) else: data = await self.main_intent.download_media(message.url) mime_type = message.info.mimetype or magic.from_buffer(data, mime=True) upload_resp = await sender.client.upload(data, mime_type=mime_type) media_id = upload_resp.media_id text = "" resp = await sender.client.conversation(self.twid ).send(text, media_id=media_id, request_id=request_id) await self._send_delivery_receipt(event_id) sender.send_remote_checkpoint( status=MessageSendCheckpointStatus.SUCCESS, event_id=event_id, room_id=self.mxid, event_type=EventType.ROOM_MESSAGE, message_type=message.msgtype, ) resp_msg_id = int(resp.entries[0].message.id) self._msgid_dedup.appendleft(resp_msg_id) msg = DBMessage(mxid=event_id, mx_room=self.mxid, twid=resp_msg_id, receiver=self.receiver) await msg.insert() self._reqid_dedup.remove(request_id) self.log.debug(f"Handled Matrix message {event_id} -> {resp_msg_id}")
async def _handle_matrix_file( self, sender_id: TelegramID, event_id: EventID, space: TelegramID, client: 'MautrixTelegramClient', content: MediaMessageEventContent, reply_to: TelegramID, caption: TextMessageEventContent = None) -> None: mime = content.info.mimetype w, h = content.info.width, content.info.height file_name = content["net.maunium.telegram.internal.filename"] max_image_size = config["bridge.image_as_file_size"] * 1000**2 if config["bridge.parallel_file_transfer"] and content.url: file_handle, file_size = await parallel_transfer_to_telegram( client, self.main_intent, content.url, sender_id) else: if content.file: if not decrypt_attachment: self.log.warning( f"Can't bridge encrypted media event {event_id}:" " matrix-nio not installed") return file = await self.main_intent.download_media(content.file.url) file = decrypt_attachment(file, content.file.key.key, content.file.hashes.get("sha256"), content.file.iv) else: file = await self.main_intent.download_media(content.url) if content.msgtype == MessageType.STICKER: if mime != "image/gif": mime, file, w, h = util.convert_image(file, source_mime=mime, target_type="webp") else: # Remove sticker description file_name = "sticker.gif" file_handle = await client.upload_file(file) file_size = len(file) file_handle.name = file_name attributes = [DocumentAttributeFilename(file_name=file_name)] if w and h: attributes.append(DocumentAttributeImageSize(w, h)) if (mime == "image/png" or mime == "image/jpeg") and file_size < max_image_size: media = InputMediaUploadedPhoto(file_handle) else: media = InputMediaUploadedDocument(file=file_handle, attributes=attributes, mime_type=mime or "application/octet-stream") caption, entities = self._matrix_event_to_entities( caption) if caption else (None, None) async with self.send_lock(sender_id): if await self._matrix_document_edit(client, content, space, caption, media, event_id): return try: response = await client.send_media(self.peer, media, reply_to=reply_to, caption=caption, entities=entities) except (PhotoInvalidDimensionsError, PhotoSaveFileInvalidError, PhotoExtInvalidError): media = InputMediaUploadedDocument(file=media.file, mime_type=mime, attributes=attributes) response = await client.send_media(self.peer, media, reply_to=reply_to, caption=caption, entities=entities) self._add_telegram_message_to_db(event_id, space, 0, response) await self._send_delivery_receipt(event_id)
async def _handle_matrix_message(self, sender: 'u.User', message: MessageEventContent, event_id: EventID) -> None: if ((message.get(self.bridge.real_user_content_key, False) and await p.Puppet.get_by_custom_mxid(sender.mxid))): self.log.debug(f"Ignoring puppet-sent message by confirmed puppet user {sender.mxid}") return elif not sender.is_connected: await self._send_bridge_error("You're not connected to Instagram", confirmed=True) return else: self.log.debug(f"Handling Matrix message {event_id} from {sender.mxid}/{sender.igpk}") request_id = str(uuid4()) self._reqid_dedup.add(request_id) if message.msgtype in (MessageType.EMOTE, MessageType.TEXT): text = message.body if message.msgtype == MessageType.EMOTE: text = f"/me {text}" self.log.trace(f"Sending Matrix text from {event_id} with request ID {request_id}") resp = await sender.mqtt.send_text(self.thread_id, text=text, client_context=request_id) elif message.msgtype.is_media: if message.file and decrypt_attachment: data = await self.main_intent.download_media(message.file.url) data = decrypt_attachment(data, message.file.key.key, message.file.hashes.get("sha256"), message.file.iv) else: data = await self.main_intent.download_media(message.url) mime_type = message.info.mimetype or magic.from_buffer(data, mime=True) if mime_type != "image/jpeg" and mime_type.startswith("image/"): with BytesIO(data) as inp: img = Image.open(inp) with BytesIO() as out: img.convert("RGB").save(out, format="JPEG", quality=80) data = out.getvalue() mime_type = "image/jpeg" if mime_type == "image/jpeg": self.log.trace(f"Uploading photo from {event_id}") upload_resp = await sender.client.upload_jpeg_photo(data) self.log.trace(f"Broadcasting uploaded photo with request ID {request_id}") # TODO is it possible to do this with MQTT? resp = await sender.client.broadcast(self.thread_id, ThreadItemType.CONFIGURE_PHOTO, client_context=request_id, upload_id=upload_resp.upload_id, allow_full_aspect_ratio="1") else: await self._send_bridge_error("Non-image files are currently not supported", confirmed=True) return else: self.log.debug(f"Unhandled Matrix message {event_id}: " f"unknown msgtype {message.msgtype}") return self.log.trace(f"Got response to message send {request_id}: {resp}") if resp.status != "ok": self.log.warning(f"Failed to handle {event_id}: {resp}") await self._send_bridge_error(resp.payload.message) else: self._msgid_dedup.appendleft(resp.payload.item_id) await DBMessage(mxid=event_id, mx_room=self.mxid, item_id=resp.payload.item_id, receiver=self.receiver, sender=sender.igpk).insert() self._reqid_dedup.remove(request_id) await self._send_delivery_receipt(event_id) self.log.debug(f"Handled Matrix message {event_id} -> {resp.payload.item_id}")