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
This commit is contained in:
Goffi 2020-03-11 20:44:49 +01:00
commit 1faa5e82da

View file

@ -23,7 +23,7 @@ from sat.core import exceptions
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 @@ class OMEMO(object):
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 @@ class OMEMO(object):
# 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 @@ class OMEMO(object):
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 @@ class OMEMO(object):
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 @@ class OMEMO(object):
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 @@ class OMEMO(object):
.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 @@ class OMEMO(object):
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 @@ class OMEMO(object):
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 @@ class OMEMO(object):
# 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: