diff sat/plugins/plugin_xep_0384.py @ 3218:806a7936a591

plugin XEP-0384: added "/omemo_reset" text command: this command will delete all sessions with peer entity, and send empty message to trigger a new key exchange.
author Goffi <goffi@goffi.org>
date Wed, 18 Mar 2020 19:56:05 +0100
parents 8d92d4d829fb
children e756e0eb1be4
line wrap: on
line diff
--- a/sat/plugins/plugin_xep_0384.py	Wed Mar 18 19:54:07 2020 +0100
+++ b/sat/plugins/plugin_xep_0384.py	Wed Mar 18 19:56:05 2020 +0100
@@ -55,7 +55,7 @@
     C.PI_TYPE: "SEC",
     C.PI_PROTOCOLS: ["XEP-0384"],
     C.PI_DEPENDENCIES: ["XEP-0163", "XEP-0280", "XEP-0334", "XEP-0060"],
-    C.PI_RECOMMENDATIONS: ["XEP-0045", "XEP-0359"],
+    C.PI_RECOMMENDATIONS: ["XEP-0045", "XEP-0359", C.TEXT_CMDS],
     C.PI_MAIN: "OMEMO",
     C.PI_HANDLER: "no",
     C.PI_DESCRIPTION: _("""Implementation of OMEMO"""),
@@ -318,6 +318,7 @@
         return promise2Deferred(new_device_p)
 
     def getDevices(self, bare_jid=None):
+        bare_jid = bare_jid.userhost()
         get_devices_p = self._session.getDevices(bare_jid=bare_jid)
         return promise2Deferred(get_devices_p)
 
@@ -326,6 +327,11 @@
         build_session_p = self._session.buildSession(bare_jid, device, bundle)
         return promise2Deferred(build_session_p)
 
+    def deleteSession(self, bare_jid, device):
+        bare_jid = bare_jid.userhost()
+        delete_session_p = self._session.deleteSession(bare_jid=bare_jid, device=device)
+        return promise2Deferred(delete_session_p)
+
     def encryptMessage(self, bare_jids, message, bundles=None, expect_problems=None):
         """Encrypt a message
 
@@ -376,7 +382,7 @@
         return promise2Deferred(get_trust_p)
 
 
-class OMEMO(object):
+class OMEMO:
 
     def __init__(self, host):
         log.info(_("OMEMO plugin initialization (omemo module v{version})").format(
@@ -402,6 +408,39 @@
             lambda itemsEvent, profile: defer.ensureDeferred(
                 self.onNewDevices(itemsEvent, profile))
         )
+        try:
+            self.text_cmds = self.host.plugins[C.TEXT_CMDS]
+        except KeyError:
+            log.info(_("Text commands not available"))
+        else:
+            self.text_cmds.registerTextCommands(self)
+
+    # Text commands #
+
+    async def cmd_omemo_reset(self, client, mess_data):
+        """reset OMEMO session (use only if encryption is broken)
+
+        @command(one2one):
+        """
+        if not client.encryption.isEncryptionRequested(mess_data, NS_OMEMO):
+            feedback = _(
+                "You need to have OMEMO encryption activated to reset the session")
+            self.text_cmds.feedBack(client, feedback, mess_data)
+            return False
+        to_jid = mess_data["to"].userhostJID()
+        session = client._xep_0384_session
+        devices = await session.getDevices(to_jid)
+
+        for device in devices['active']:
+            log.debug(f"deleting session for device {device}")
+            await session.deleteSession(to_jid, device=device)
+
+        log.debug("Sending an empty message to trigger key exchange")
+        await client.sendMessage(to_jid, {'': ''})
+
+        feedback = _("OMEMO session has been reset")
+        self.text_cmds.feedBack(client, feedback, mess_data)
+        return False
 
     @defer.inlineCallbacks
     def trustUICb(self, xmlui_data, trust_data, expect_problems=None,
@@ -651,7 +690,7 @@
         defer.returnValue(devices)
 
     async def setDevices(self, client, devices):
-        log.debug(f"setting devices with {', '.join(devices)}")
+        log.debug(f"setting devices with {', '.join(str(d) for d in devices)}")
         list_elt = domish.Element((NS_OMEMO, 'list'))
         for device in devices:
             device_elt = list_elt.addElement('device')
@@ -794,6 +833,7 @@
     ## PEP node events callbacks
 
     async def onNewDevices(self, itemsEvent, profile):
+        log.debug("devices list has been updated")
         client = self.host.getClient(profile)
         try:
             omemo_session = client._xep_0384_session