From 40a48d12a29fdf87e3eac3d13cb88ebd88af5f49 Mon Sep 17 00:00:00 2001 From: Andrew Ferrazzutti Date: Thu, 17 Jun 2021 23:32:45 -0400 Subject: [PATCH] Don't view groups/rooms when possible, via MSC2409 Use the sidebar to sync non-DM messages, just like what's done for DM messages. However, since sidebar messages don't say who sent a message, this requires scanning read receipts with MSC2409: when a non-DM sidebar message is seen, the bridge bot sends that message. Only when that placeholder is viewed in Matrix does Puppeteer actually view the non-DM chat to find who really sent the message. Then the bridgebot redacts its message, and the message gets re-sent by the puppet of the LINE user who really sent it. --- matrix_puppeteer_line/portal.py | 58 +++++++++++++++++++-------------- puppet/src/puppet.js | 11 +++---- 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/matrix_puppeteer_line/portal.py b/matrix_puppeteer_line/portal.py index 5f252b7..19dee16 100644 --- a/matrix_puppeteer_line/portal.py +++ b/matrix_puppeteer_line/portal.py @@ -190,10 +190,10 @@ class Portal(DBPortal, BasePortal): f"cleaning up and deleting...") await self.cleanup_and_delete() - async def _bridge_own_message_pm(self, source: 'u.User', sender: Optional['p.Puppet'], mid: str, + async def _bridge_own_message_pm(self, source: 'u.User', puppet: Optional['p.Puppet'], mid: str, invite: bool = True) -> Optional[IntentAPI]: - intent = sender.intent if sender else (await source.get_own_puppet()).intent - if self.is_direct and (sender is None or sender.mid == source.mid and not sender.is_real_user): + intent = puppet.intent if puppet else (await source.get_own_puppet()).intent + if self.is_direct and (not puppet or puppet.mid == source.mid and not puppet.is_real_user): if self.invite_own_puppet_to_pm and invite: try: await intent.ensure_joined(self.mxid) @@ -216,44 +216,54 @@ class Portal(DBPortal, BasePortal): self.log.debug(f"Ignoring duplicate message {evt.id}") return - is_preseen = evt.id != None and await DBMessage.get_num_noid_msgs(self.mxid) > 0 - if evt.is_outgoing: if source.intent: - sender = None intent = source.intent else: if not self.invite_own_puppet_to_pm: self.log.warning(f"Ignoring message {evt.id}: double puppeting isn't enabled") return - sender = await p.Puppet.get_by_mid(evt.sender.id) if evt.sender else None - intent = await self._bridge_own_message_pm(source, sender, f"message {evt.id}") + puppet = await p.Puppet.get_by_mid(evt.sender.id) if evt.sender else None + intent = await self._bridge_own_message_pm(source, puppet, f"message {evt.id}") if not intent: return else: - sender = await p.Puppet.get_by_mid(self.other_user if self.is_direct else evt.sender.id) - # TODO Respond to name/avatar changes of users in a DM - if not self.is_direct: - if sender: - await sender.update_info(evt.sender, source.client) + if self.is_direct: + # TODO Respond to name/avatar changes of users in a DM + intent = (await p.Puppet.get_by_mid(self.other_user)).intent + elif evt.sender: + puppet = await p.Puppet.get_by_mid(evt.sender.id) + if puppet: + await puppet.update_info(evt.sender, source.client) else: - self.log.warning(f"Could not find ID of LINE user who sent event {evt.id or 'with no ID'}") - sender = await p.Puppet.get_by_profile(evt.sender, source.client) - intent = sender.intent + self.log.warning(f"Could not find ID of LINE user who sent message {evt.id or 'with no ID'}") + puppet = await p.Puppet.get_by_profile(evt.sender, source.client) + intent = puppet.intent + else: + self.log.info(f"Using bridgebot for unknown sender of message {evt.id or 'with no ID'}") + intent = self.az.intent await intent.ensure_joined(self.mxid) - if is_preseen: + if evt.id: msg = await DBMessage.get_next_noid_msg(self.mxid) - if msg: - self.log.debug(f"Found ID {evt.id} of preseen message in chat {self.mxid}: {msg.mxid}") - prev_event_id = msg.mxid + if not msg: + self.log.info(f"Handling new message {evt.id} in chat {self.mxid}") + prev_event_id = None else: - self.log.error(f"Could not find an existing event for a message with no ID in chat {self.mxid}") - return + self.log.info(f"Handling preseen message {evt.id} in chat {self.mxid}: {msg.mxid}") + if not self.is_direct: + # Non-DM previews are always sent by bridgebot. + # Must delete the bridgebot message and send a new message from the correct puppet. + await self.az.intent.redact(self.mxid, msg.mxid, "Found actual sender") + prev_event_id = None + else: + prev_event_id = msg.mxid else: + self.log.info(f"Handling new message with no ID in chat {self.mxid}") + msg = None prev_event_id = None - if is_preseen and evt.html: + if prev_event_id and evt.html: # No need to update a previewed text message, as their previews are accurate event_id = prev_event_id elif evt.image and evt.image.url: @@ -364,7 +374,7 @@ class Portal(DBPortal, BasePortal): if evt.is_outgoing and evt.receipt_count: await self._handle_receipt(event_id, evt.receipt_count) - if not is_preseen: + if not msg: msg = DBMessage(mxid=event_id, mx_room=self.mxid, mid=evt.id, chat_id=self.chat_id) try: await msg.insert() diff --git a/puppet/src/puppet.js b/puppet/src/puppet.js index c6f0e40..6a3c954 100644 --- a/puppet/src/puppet.js +++ b/puppet/src/puppet.js @@ -771,18 +771,17 @@ export default class MessagesPuppeteer { } const mustSync = - // Can only use previews for DMs, because sender can't be found otherwise! - // TODO For non-DMs, send fake messages from bridgebot and delete them. - chatListInfo.id.charAt(0) != 'u' // If >1, a notification was missed. Only way to get them is to view the chat. // If == 0, might be own message...or just a shuffled chat, or something else. // To play it safe, just sync them. Should be no harm, as they're viewed already. - || diffNumNotifications != 1 + diffNumNotifications != 1 // Without placeholders, some messages require visiting their chat to be synced. || !this.sendPlaceholders && ( + // Can only use previews for DMs, because sender can't be found otherwise! + chatListInfo.id.charAt(0) != 'u' // Sync when lastMsg is a canned message for a non-previewable message type. - chatListInfo.lastMsg.endsWith(" sent a photo.") + || chatListInfo.lastMsg.endsWith(" sent a photo.") || chatListInfo.lastMsg.endsWith(" sent a sticker.") || chatListInfo.lastMsg.endsWith(" sent a location.") // TODO More? @@ -795,7 +794,7 @@ export default class MessagesPuppeteer { id: null, // because sidebar messages have no ID timestamp: null, // because this message was sent right now is_outgoing: false, // because there's no reliable way to detect own messages... - sender: null, // because only DM messages are handled + sender: null, // because there's no way to tell who sent a message html: chatListInfo.lastMsg, }] this.numChatNotifications.set(chatID, chatListInfo.notificationCount)