Pārlūkot izejas kodu

Implement Signal->Matrix message deletions

Tulir Asokan 4 gadi atpakaļ
vecāks
revīzija
2bf3de1ed7
4 mainītis faili ar 33 papildinājumiem un 5 dzēšanām
  1. 2 0
      ROADMAP.md
  2. 10 1
      mausignald/types.py
  3. 19 4
      mautrix_signal/portal.py
  4. 2 0
      mautrix_signal/signal.py

+ 2 - 0
ROADMAP.md

@@ -12,6 +12,7 @@
       * [ ] Locations
       * [ ] Stickers
   * [x] Message reactions
+  * [ ] Message redactions
   * [ ] Group info changes
     * [ ] Name
     * [ ] Avatar
@@ -30,6 +31,7 @@
       * [x] Locations
       * [x] Stickers
   * [x] Message reactions
+  * [x] Remote deletions
   * [ ] Initial profile info
     * [x] User displayname
     * [ ] †User avatar

+ 10 - 1
mausignald/types.py

@@ -172,6 +172,11 @@ class Sticker(SerializableAttrs['Sticker']):
     sticker_id: int = attr.ib(metadata={"json": "stickerID"})
 
 
+@dataclass
+class RemoteDelete(SerializableAttrs['RemoteDelete']):
+    target_sent_timestamp: int = attr.ib(metadata={"json": "targetSentTimestamp"})
+
+
 @dataclass
 class MessageData(SerializableAttrs['MessageData']):
     timestamp: int
@@ -191,12 +196,16 @@ class MessageData(SerializableAttrs['MessageData']):
     profile_key_update: bool = attr.ib(default=False, metadata={"json": "profileKeyUpdate"})
     view_once: bool = attr.ib(default=False, metadata={"json": "viewOnce"})
 
+    remote_delete: Optional[RemoteDelete] = attr.ib(default=None,
+                                                    metadata={"json": "remoteDelete"})
+
 
 @dataclass
 class SentSyncMessage(SerializableAttrs['SentSyncMessage']):
     message: MessageData
     timestamp: int
-    expiration_start_timestamp: Optional[int] = attr.ib(default=None, metadata={"json": "expirationStartTimestamp"})
+    expiration_start_timestamp: Optional[int] = attr.ib(default=None, metadata={
+        "json": "expirationStartTimestamp"})
     is_recipient_update: bool = attr.ib(default=False, metadata={"json": "isRecipientUpdate"})
     unidentified_status: Dict[str, bool] = attr.ib(factory=lambda: {})
     destination: Optional[Address] = None

+ 19 - 4
mautrix_signal/portal.py

@@ -70,9 +70,10 @@ class Portal(DBPortal, BasePortal):
     _reaction_dedup: Deque[Tuple[Address, int, str]]
     _reaction_lock: asyncio.Lock
 
-    def __init__(self, chat_id: Union[GroupID, Address], receiver: str, mxid: Optional[RoomID] = None,
-                 name: Optional[str] = None, avatar_hash: Optional[str] = None,
-                 avatar_url: Optional[ContentURI] = None, encrypted: bool = False) -> None:
+    def __init__(self, chat_id: Union[GroupID, Address], receiver: str,
+                 mxid: Optional[RoomID] = None, name: Optional[str] = None,
+                 avatar_hash: Optional[str] = None, avatar_url: Optional[ContentURI] = None,
+                 encrypted: bool = False) -> None:
         super().__init__(chat_id, receiver, mxid, name, avatar_hash, avatar_url, encrypted)
         self._create_room_lock = asyncio.Lock()
         self.log = self.log.getChild(self.chat_id_str)
@@ -192,7 +193,8 @@ class Portal(DBPortal, BasePortal):
             self.log.trace("Formed outgoing attachment %s", attachment)
         await self.signal.send(username=sender.username, recipient=self.chat_id, body=text,
                                quote=quote, attachments=attachments, timestamp=request_id)
-        msg = DBMessage(mxid=event_id, mx_room=self.mxid, sender=sender.address, timestamp=request_id,
+        msg = DBMessage(mxid=event_id, mx_room=self.mxid, sender=sender.address,
+                        timestamp=request_id,
                         signal_chat_id=self.chat_id, signal_receiver=self.receiver)
         await msg.insert()
         await self._send_delivery_receipt(event_id)
@@ -236,6 +238,8 @@ class Portal(DBPortal, BasePortal):
         if not self.mxid:
             return
 
+        # TODO message redactions after https://gitlab.com/signald/signald/-/issues/37
+
         reaction = await DBReaction.get_by_mxid(event_id, self.mxid)
         if reaction:
             try:
@@ -437,6 +441,17 @@ class Portal(DBPortal, BasePortal):
         self.log.debug(f"{sender.address} reacted to {message.mxid} -> {mxid}")
         await self._upsert_reaction(existing, intent, mxid, sender, message, reaction.emoji)
 
+    async def handle_signal_delete(self, sender: 'p.Puppet', message_ts: int) -> None:
+        message = await DBMessage.get_by_signal_id(sender.address, message_ts,
+                                                   self.chat_id, self.receiver)
+        if not message:
+            return
+        await message.delete()
+        try:
+            await sender.intent_for(self).redact(message.mx_room, message.mxid)
+        except MForbidden:
+            await self.main_intent.redact(message.mx_room, message.mxid)
+
     # endregion
     # region Updating portal info
 

+ 2 - 0
mautrix_signal/signal.py

@@ -97,6 +97,8 @@ class SignalHandler(SignaldClient):
             await portal.handle_signal_message(user, sender, msg)
         if msg.group and msg.group.type == "UPDATE":
             await portal.update_info(msg.group)
+        if msg.remote_delete:
+            await portal.handle_signal_delete(sender, msg.remote_delete.target_sent_timestamp)
 
     @staticmethod
     async def handle_own_receipts(sender: 'pu.Puppet', receipts: List[OwnReadReceipt]) -> None: