# HG changeset patch # User Goffi # Date 1583955889 -3600 # Node ID 8d92d4d829fb6070ab63438d2590d2df1c8d14df # Parent c2f958dde5d20a5d77af5ea3c1cc8469f69df85c plugin XEP-0384: use "max_items=1" for devices and bundles nodes: - max_items = 1 is requested with publish-options when publishing the bundle or the devices list. If the constraint is failed, a warning will be shown, and the publication will be done without this option - fixed return values when devices list is badly formed diff -r c2f958dde5d2 -r 8d92d4d829fb sat/plugins/plugin_xep_0384.py --- a/sat/plugins/plugin_xep_0384.py Wed Mar 11 19:15:48 2020 +0100 +++ b/sat/plugins/plugin_xep_0384.py Wed Mar 11 20:44:49 2020 +0100 @@ -23,7 +23,7 @@ from twisted.internet import defer, reactor from twisted.words.xish import domish from twisted.words.protocols.jabber import jid -from twisted.words.protocols.jabber import error +from twisted.words.protocols.jabber import error as jabber_error from sat.memory import persistent from functools import partial from sat.tools import xml_tools @@ -397,7 +397,11 @@ host.trigger.add("sendMessageData", self._sendMessageDataTrigger) self.host.registerEncryptionPlugin(self, "OMEMO", NS_OMEMO, 100) pep = host.plugins['XEP-0163'] - pep.addPEPEvent("OMEMO_DEVICES", NS_OMEMO_DEVICES, self.onNewDevices) + pep.addPEPEvent( + "OMEMO_DEVICES", NS_OMEMO_DEVICES, + lambda itemsEvent, profile: defer.ensureDeferred( + self.onNewDevices(itemsEvent, profile)) + ) @defer.inlineCallbacks def trustUICb(self, xmlui_data, trust_data, expect_problems=None, @@ -570,9 +574,12 @@ # and we save it persistent_dict[KEY_DEVICE_ID] = device_id + log.debug(f"our OMEMO device id is {device_id}") + if device_id not in devices: + log.debug(f"our device id ({device_id}) is not in the list, adding it") devices.add(device_id) - yield self.setDevices(client, devices) + yield defer.ensureDeferred(self.setDevices(client, devices)) all_jids = yield persistent_dict.get(KEY_ALL_JIDS, set()) @@ -585,7 +592,9 @@ if omemo_session.republish_bundle: log.info(_("Saving public bundle for this device ({device_id})").format( device_id=device_id)) - yield self.setBundle(client, omemo_session.public_bundle, device_id) + yield defer.ensureDeferred( + self.setBundle(client, omemo_session.public_bundle, device_id) + ) client._xep_0384_ready.callback(None) del client._xep_0384_ready @@ -608,7 +617,7 @@ list_elt = next(items[0].elements(NS_OMEMO, 'list')) except StopIteration: log.warning(_("no list element found in OMEMO devices list")) - return + return devices for device_elt in list_elt.elements(NS_OMEMO, 'device'): try: device_id = int(device_elt['id']) @@ -641,18 +650,23 @@ devices = self.parseDevices(items) defer.returnValue(devices) - def setDevicesEb(self, failure_): - log.warning(_("Can't set devices: {reason}").format(reason=failure_)) - - def setDevices(self, client, devices): + async def setDevices(self, client, devices): + log.debug(f"setting devices with {', '.join(devices)}") list_elt = domish.Element((NS_OMEMO, 'list')) for device in devices: device_elt = list_elt.addElement('device') device_elt['id'] = str(device) - d = self._p.sendItem( - client, None, NS_OMEMO_DEVICES, list_elt, item_id=self._p.ID_SINGLETON) - d.addErrback(self.setDevicesEb) - return d + try: + await self._p.sendItem( + client, None, NS_OMEMO_DEVICES, list_elt, + item_id=self._p.ID_SINGLETON, + extra={ + self._p.EXTRA_PUBLISH_OPTIONS: {self._p.OPT_MAX_ITEMS: 1}, + self._p.EXTRA_ON_PRECOND_NOT_MET: "publish_without_options", + } + ) + except Exception as e: + log.warning(_("Can't set devices: {reason}").format(reason=e)) # bundles @@ -680,7 +694,7 @@ .format(device_id=device_id)) missing.add(device_id) continue - except error.StanzaError as e: + except jabber_error.StanzaError as e: log.warning(_("Can't get bundle for device {device_id}: {reason}") .format(device_id=device_id, reason=e)) continue @@ -737,10 +751,7 @@ defer.returnValue((bundles, missing)) - def setBundleEb(self, failure_): - log.warning(_("Can't set bundle: {reason}").format(reason=failure_)) - - def setBundle(self, client, bundle, device_id): + async def setBundle(self, client, bundle, device_id): """Set public bundle for this device. @param bundle(ExtendedPublicBundle): bundle to publish @@ -769,31 +780,37 @@ preKeyPublic_elt['preKeyId'] = str(otpk['id']) node = NS_OMEMO_BUNDLE.format(device_id=device_id) - d = self._p.sendItem(client, None, node, bundle_elt, item_id=self._p.ID_SINGLETON) - d.addErrback(self.setBundleEb) - return d + try: + await self._p.sendItem( + client, None, node, bundle_elt, item_id=self._p.ID_SINGLETON, + extra={ + self._p.EXTRA_PUBLISH_OPTIONS: {self._p.OPT_MAX_ITEMS: 1}, + self._p.EXTRA_ON_PRECOND_NOT_MET: "publish_without_options", + } + ) + except Exception as e: + log.warning(_("Can't set bundle: {reason}").format(reason=e)) ## PEP node events callbacks - @defer.inlineCallbacks - def onNewDevices(self, itemsEvent, profile): + async def onNewDevices(self, itemsEvent, profile): client = self.host.getClient(profile) try: omemo_session = client._xep_0384_session except AttributeError: - yield client._xep_0384_ready + await client._xep_0384_ready omemo_session = client._xep_0384_session entity = itemsEvent.sender devices = self.parseDevices(itemsEvent.items) - omemo_session.newDeviceList(entity, devices) + await omemo_session.newDeviceList(entity, devices) if entity == client.jid.userhostJID(): own_device = client._xep_0384_device_id if own_device not in devices: log.warning(_("Our own device is missing from devices list, fixing it")) devices.add(own_device) - yield self.setDevices(client, devices) + await self.setDevices(client, devices) ## triggers @@ -1098,7 +1115,9 @@ # we don't wait for the Deferred (i.e. no yield) on purpose # there is no need to block the whole message workflow while # updating the bundle - self.setBundle(client, omemo_session.public_bundle, device_id) + defer.ensureDeferred( + self.setBundle(client, omemo_session.public_bundle, device_id) + ) message_elt.children.remove(encrypted_elt) if plaintext: