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.
This commit is contained in:
Andrew Ferrazzutti 2021-06-17 23:32:45 -04:00
parent 1ae30bcf1b
commit 40a48d12a2
2 changed files with 39 additions and 30 deletions

View File

@ -190,10 +190,10 @@ class Portal(DBPortal, BasePortal):
f"cleaning up and deleting...") f"cleaning up and deleting...")
await self.cleanup_and_delete() 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]: invite: bool = True) -> Optional[IntentAPI]:
intent = sender.intent if sender else (await source.get_own_puppet()).intent intent = puppet.intent if puppet 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): 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: if self.invite_own_puppet_to_pm and invite:
try: try:
await intent.ensure_joined(self.mxid) await intent.ensure_joined(self.mxid)
@ -216,44 +216,54 @@ class Portal(DBPortal, BasePortal):
self.log.debug(f"Ignoring duplicate message {evt.id}") self.log.debug(f"Ignoring duplicate message {evt.id}")
return return
is_preseen = evt.id != None and await DBMessage.get_num_noid_msgs(self.mxid) > 0
if evt.is_outgoing: if evt.is_outgoing:
if source.intent: if source.intent:
sender = None
intent = source.intent intent = source.intent
else: else:
if not self.invite_own_puppet_to_pm: if not self.invite_own_puppet_to_pm:
self.log.warning(f"Ignoring message {evt.id}: double puppeting isn't enabled") self.log.warning(f"Ignoring message {evt.id}: double puppeting isn't enabled")
return return
sender = await p.Puppet.get_by_mid(evt.sender.id) if evt.sender else None puppet = 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}") intent = await self._bridge_own_message_pm(source, puppet, f"message {evt.id}")
if not intent: if not intent:
return return
else: else:
sender = await p.Puppet.get_by_mid(self.other_user if self.is_direct else evt.sender.id) if self.is_direct:
# TODO Respond to name/avatar changes of users in a DM # TODO Respond to name/avatar changes of users in a DM
if not self.is_direct: intent = (await p.Puppet.get_by_mid(self.other_user)).intent
if sender: elif evt.sender:
await sender.update_info(evt.sender, source.client) puppet = await p.Puppet.get_by_mid(evt.sender.id)
if puppet:
await puppet.update_info(evt.sender, source.client)
else: else:
self.log.warning(f"Could not find ID of LINE user who sent event {evt.id or 'with no ID'}") self.log.warning(f"Could not find ID of LINE user who sent message {evt.id or 'with no ID'}")
sender = await p.Puppet.get_by_profile(evt.sender, source.client) puppet = await p.Puppet.get_by_profile(evt.sender, source.client)
intent = sender.intent 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) await intent.ensure_joined(self.mxid)
if is_preseen: if evt.id:
msg = await DBMessage.get_next_noid_msg(self.mxid) msg = await DBMessage.get_next_noid_msg(self.mxid)
if msg: if not msg:
self.log.debug(f"Found ID {evt.id} of preseen message in chat {self.mxid}: {msg.mxid}") self.log.info(f"Handling new message {evt.id} in chat {self.mxid}")
prev_event_id = msg.mxid prev_event_id = None
else: else:
self.log.error(f"Could not find an existing event for a message with no ID in chat {self.mxid}") self.log.info(f"Handling preseen message {evt.id} in chat {self.mxid}: {msg.mxid}")
return 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: else:
self.log.info(f"Handling new message with no ID in chat {self.mxid}")
msg = None
prev_event_id = 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 # No need to update a previewed text message, as their previews are accurate
event_id = prev_event_id event_id = prev_event_id
elif evt.image and evt.image.url: elif evt.image and evt.image.url:
@ -364,7 +374,7 @@ class Portal(DBPortal, BasePortal):
if evt.is_outgoing and evt.receipt_count: if evt.is_outgoing and evt.receipt_count:
await self._handle_receipt(event_id, 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) msg = DBMessage(mxid=event_id, mx_room=self.mxid, mid=evt.id, chat_id=self.chat_id)
try: try:
await msg.insert() await msg.insert()

View File

@ -771,18 +771,17 @@ export default class MessagesPuppeteer {
} }
const mustSync = 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 >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. // 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. // 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. // Without placeholders, some messages require visiting their chat to be synced.
|| !this.sendPlaceholders || !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. // 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 sticker.")
|| chatListInfo.lastMsg.endsWith(" sent a location.") || chatListInfo.lastMsg.endsWith(" sent a location.")
// TODO More? // TODO More?
@ -795,7 +794,7 @@ export default class MessagesPuppeteer {
id: null, // because sidebar messages have no ID id: null, // because sidebar messages have no ID
timestamp: null, // because this message was sent right now timestamp: null, // because this message was sent right now
is_outgoing: false, // because there's no reliable way to detect own messages... 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, html: chatListInfo.lastMsg,
}] }]
this.numChatNotifications.set(chatID, chatListInfo.notificationCount) this.numChatNotifications.set(chatID, chatListInfo.notificationCount)