3333 MemberStateEventContent ,
3434 MessageEvent ,
3535 MessageEventContent ,
36+ MessageStatus ,
3637 MessageStatusReason ,
3738 MessageType ,
3839 PresenceEvent ,
9394)
9495
9596
97+ class UnencryptedMessageError (DecryptionError ):
98+ def __init__ (self ) -> None :
99+ super ().__init__ ("unencrypted message" )
100+
101+ @property
102+ def human_message (self ) -> str :
103+ return "the message is not encrypted"
104+
105+
106+ class EncryptionUnsupportedError (DecryptionError ):
107+ def __init__ (self ) -> None :
108+ super ().__init__ ("encryption is not supported" )
109+
110+ @property
111+ def human_message (self ) -> str :
112+ return "the bridge is not configured to support encryption"
113+
114+
115+ class DeviceUntrustedError (DecryptionError ):
116+ def __init__ (self , trust : TrustState ) -> None :
117+ explanation = {
118+ TrustState .BLACKLISTED : "device is blacklisted" ,
119+ TrustState .UNVERIFIED : "unverified" ,
120+ TrustState .UNKNOWN_DEVICE : "device info not found" ,
121+ TrustState .FORWARDED : "keys were forwarded from an unknown device" ,
122+ TrustState .CROSS_SIGNED_UNTRUSTED : (
123+ "cross-signing keys changed after setting up the bridge"
124+ ),
125+ }.get (trust )
126+ base = "your device is not trusted"
127+ self .message = f"{ base } ({ explanation } )" if explanation else base
128+ super ().__init__ (self .message )
129+
130+ @property
131+ def human_message (self ) -> str :
132+ return self .message
133+
134+
96135class BaseMatrixHandler :
97136 log : TraceLogger = logging .getLogger ("mau.mx" )
98137 az : AppService
@@ -506,23 +545,23 @@ def is_command(self, message: MessageEventContent) -> tuple[bool, str]:
506545 async def _send_crypto_status_error (
507546 self ,
508547 evt : Event ,
509- err : Exception | str | None = None ,
548+ err : DecryptionError | None = None ,
510549 retry_num : int = 0 ,
511550 is_final : bool = True ,
512551 edit : EventID | None = None ,
513552 wait_for : int | None = None ,
514553 ) -> EventID | None :
515554 msg = str (err )
516- if isinstance (err , SessionNotFound ):
517- msg = "the bridge hasn't received the decryption keys"
555+ if isinstance (err , ( SessionNotFound , UnencryptedMessageError ) ):
556+ msg = err . human_message
518557 self ._send_message_checkpoint (
519558 evt , MessageSendCheckpointStep .DECRYPTED , msg , permanent = is_final , retry_num = retry_num
520559 )
521560
522561 if wait_for :
523562 msg += f". The bridge will retry for { wait_for } seconds"
524- full_msg = f"\u26a0 \ufe0f Your message was not bridged: { msg } ."
525- if msg == "encryption is not supported" :
563+ full_msg = f"\u26a0 Your message was not bridged: { msg } ."
564+ if isinstance ( err , EncryptionUnsupportedError ) :
526565 full_msg = "🔒️ This bridge has not been configured to support encryption"
527566 event_id = None
528567 if self .config .get ("bridge.delivery_error_reports" , True ):
@@ -544,12 +583,12 @@ async def _send_crypto_status_error(
544583 status_content = BeeperMessageStatusEventContent (
545584 network = "" , # TODO set network properly
546585 relates_to = RelatesTo (rel_type = RelationType .REFERENCE , event_id = evt .event_id ),
547- success = False ,
548- is_certain = True ,
549- can_retry = True ,
586+ status = MessageStatus .RETRIABLE if is_final else MessageStatus .PENDING ,
550587 reason = MessageStatusReason .UNDECRYPTABLE ,
551588 error = msg ,
589+ message = err .human_message if err else None ,
552590 )
591+ status_content .fill_legacy_booleans ()
553592 await self .az .intent .send_message_event (
554593 evt .room_id , EventType .BEEPER_MESSAGE_STATUS , status_content
555594 )
@@ -564,7 +603,7 @@ async def handle_message(self, evt: MessageEvent, was_encrypted: bool = False) -
564603
565604 if not was_encrypted and self .require_e2ee :
566605 self .log .warning (f"Dropping { event_id } from { user_id } as it's not encrypted!" )
567- await self ._send_crypto_status_error (evt , "unencrypted message" , 0 )
606+ await self ._send_crypto_status_error (evt , UnencryptedMessageError () , 0 )
568607 return
569608
570609 sender = await self .bridge .get_user (user_id )
@@ -714,19 +753,6 @@ async def try_handle_sync_event(self, evt: Event) -> None:
714753 except Exception :
715754 self .log .exception ("Error handling manually received Matrix event" )
716755
717- @staticmethod
718- def _device_unverified_explanation (trust : TrustState ) -> str :
719- explanation = {
720- TrustState .BLACKLISTED : "device is blacklisted" ,
721- TrustState .UNKNOWN_DEVICE : "device info not found" ,
722- TrustState .FORWARDED : "keys were forwarded from an unknown device" ,
723- TrustState .CROSS_SIGNED_UNTRUSTED : (
724- "cross-signing keys changed after setting up the bridge"
725- ),
726- }.get (trust )
727- base = "your device is not trusted"
728- return f"{ base } ({ explanation } )" if explanation else base
729-
730756 async def _post_decrypt (
731757 self , evt : Event , retry_num : int = 0 , error_event_id : EventID | None = None
732758 ) -> None :
@@ -739,7 +765,7 @@ async def _post_decrypt(
739765 await self ._send_crypto_status_error (
740766 evt ,
741767 retry_num = retry_num ,
742- err = self . _device_unverified_explanation (trust_state ),
768+ err = DeviceUntrustedError (trust_state ),
743769 edit = error_event_id ,
744770 )
745771 return
@@ -758,7 +784,7 @@ async def handle_encrypted(self, evt: EncryptedEvent) -> None:
758784 evt .event_id ,
759785 evt .sender ,
760786 )
761- await self ._send_crypto_status_error (evt , "encryption is not supported" )
787+ await self ._send_crypto_status_error (evt , EncryptionUnsupportedError () )
762788 return
763789 try :
764790 decrypted = await self .e2ee .decrypt (evt , wait_session_timeout = 3 )
0 commit comments