plugin XEP-0384: better bundle handling + misc improvments
- public bundles are now retrieved only when needed (i.e. on MissingBundleException when encrypting a message) - a feedback is given to user when a message is received but it has not been encrypted for our device - fixed feedback on decryption error if message come from an other device of the client (i.e. it's a carbon copy) - setBundle if called in a "finally" if republish_bundle is set after decrypting a message
This commit is contained in:
parent
fc007dae38
commit
e8e8881016
2 changed files with 54 additions and 59 deletions
|
|
@ -783,35 +783,12 @@ class OMEMO(object):
|
|||
@defer.inlineCallbacks
|
||||
def onNewDevices(self, itemsEvent, profile):
|
||||
client = self.host.getClient(profile)
|
||||
cache = client._xep_0384_cache
|
||||
omemo_session = client._xep_0384_session
|
||||
entity = itemsEvent.sender
|
||||
entity_cache = cache.setdefault(entity, {})
|
||||
|
||||
devices = self.parseDevices(itemsEvent.items)
|
||||
omemo_session.newDeviceList(entity, devices)
|
||||
missing_devices = devices.difference(entity_cache.keys())
|
||||
if missing_devices:
|
||||
bundles, bundles_not_found = yield self.getBundles(
|
||||
client, entity, missing_devices)
|
||||
entity_cache.update(bundles)
|
||||
if bundles_not_found and entity == client.jid.userhostJID():
|
||||
# we have devices announced in our own public list
|
||||
# with missing bundles
|
||||
own_device = client._xep_0384_device_id
|
||||
if own_device in bundles_not_found:
|
||||
log.warning(_(u"Our own device has no attached bundle, fixing it"))
|
||||
bundles_not_found.remove(own_device)
|
||||
yield self.setBundle(client, omemo_session.public_bundle, own_device)
|
||||
|
||||
if bundles_not_found:
|
||||
# some announced devices have no bundle, we update our public
|
||||
# list to remove missing devices.
|
||||
log.warning(_(
|
||||
u"Some devices have missing bundles, cleaning out public "
|
||||
u"devices list"))
|
||||
existing_devices = devices - bundles_not_found
|
||||
yield self.setDevices(client, existing_devices)
|
||||
# we check that our device has not been removed from the list
|
||||
if entity == client.jid.userhostJID():
|
||||
own_device = client._xep_0384_device_id
|
||||
if own_device not in devices:
|
||||
|
|
@ -819,7 +796,6 @@ class OMEMO(object):
|
|||
devices.add(own_device)
|
||||
yield self.setDevices(client, devices)
|
||||
|
||||
|
||||
## triggers
|
||||
|
||||
@defer.inlineCallbacks
|
||||
|
|
@ -837,13 +813,44 @@ class OMEMO(object):
|
|||
"""
|
||||
# FIXME: not all problems are handled yet
|
||||
untrusted = {}
|
||||
missing_bundles = {}
|
||||
expect_problems = {}
|
||||
cache = client._xep_0384_cache
|
||||
for problem in problems:
|
||||
if isinstance(problem, omemo_excpt.UntrustedException):
|
||||
untrusted[unicode(hash(problem))] = problem
|
||||
if isinstance(problem, omemo_excpt.MissingBundleException):
|
||||
pb_entity = jid.JID(problem.bare_jid)
|
||||
entity_cache = cache.setdefault(pb_entity, {})
|
||||
entity_bundles = bundles.setdefault(pb_entity, {})
|
||||
if problem.device in entity_cache:
|
||||
entity_bundles[problem.device] = entity_cache[problem.device]
|
||||
else:
|
||||
found_bundles, missing = yield self.getBundles(
|
||||
client, pb_entity, [problem.device])
|
||||
entity_cache.update(bundles)
|
||||
entity_bundles.update(found_bundles)
|
||||
if problem.device in missing:
|
||||
missing_bundles.setdefault(pb_entity, set()).add(
|
||||
problem.device)
|
||||
expect_problems.setdefault(problem.bare_jid, set()).add(
|
||||
problem.device)
|
||||
elif isinstance(problem, omemo_excpt.NoEligibleDevicesException):
|
||||
pass
|
||||
|
||||
for peer_jid, devices in missing_bundles.iteritems():
|
||||
devices_s = [unicode(d) for d in devices]
|
||||
log.warning(
|
||||
_(u"Can't retrieve bundle for device(s) {devices} of entity {peer}, "
|
||||
u"the message will not be readable on this/those device(s)").format(
|
||||
devices=u", ".join(devices_s), peer=peer_jid.full()))
|
||||
client.feedback(
|
||||
entity,
|
||||
D_(u"You're destinee {peer} has missing encryption data on some of "
|
||||
u"his/her device(s) (bundle on device {devices}), the message won't "
|
||||
u"be readable on this/those device.").format(
|
||||
peer=peer_jid.full(), devices=u", ".join(devices_s)))
|
||||
|
||||
if untrusted:
|
||||
trust_data = {}
|
||||
for trust_id, data in untrusted.iteritems():
|
||||
|
|
@ -873,38 +880,16 @@ class OMEMO(object):
|
|||
@defer.inlineCallbacks
|
||||
def encryptMessage(self, client, entity_bare_jid, message):
|
||||
omemo_session = client._xep_0384_session
|
||||
cache = client._xep_0384_cache
|
||||
try:
|
||||
bundles = {entity_bare_jid: cache[entity_bare_jid]}
|
||||
except KeyError:
|
||||
# No devices know for this entity, let try to find them.
|
||||
# This can happen if the entity is not in our roster, or doesn't handle OMEMO
|
||||
# or if we haven't received the devices from PEP yet.
|
||||
try:
|
||||
devices = yield self.getDevices(client, entity_bare_jid)
|
||||
bundles, __ = yield self.getBundles(client, entity_bare_jid, devices)
|
||||
except Exception as e:
|
||||
raise exceptions.NotFound(
|
||||
_(u"Can retrieve bundles for {entity}: {reason}" .format(
|
||||
entity=entity_bare_jid.full(), reason=e)))
|
||||
else:
|
||||
cache[entity_bare_jid] = bundles
|
||||
bundles = {entity_bare_jid: bundles}
|
||||
|
||||
own_jid = client.jid.userhostJID()
|
||||
if entity_bare_jid != own_jid:
|
||||
# message will be copied to our devices, so we need to add our own bundles
|
||||
bundles[own_jid] = cache[own_jid]
|
||||
|
||||
try:
|
||||
# first try may fail, in case of e.g. trust issue or missing bundle
|
||||
encrypted = yield omemo_session.encryptMessage(
|
||||
entity_bare_jid,
|
||||
message,
|
||||
bundles)
|
||||
message)
|
||||
except omemo_excpt.EncryptionProblemsException as e:
|
||||
# we know the problem to solve, we can try to fix them
|
||||
expect_problems = yield self.handleProblems(client, entity_bare_jid, bundles, e.problems)
|
||||
bundles = {}
|
||||
expect_problems = yield self.handleProblems(client, entity_bare_jid, bundles,
|
||||
e.problems)
|
||||
# and try an encryption again.
|
||||
try:
|
||||
encrypted = yield omemo_session.encryptMessage(
|
||||
|
|
@ -932,6 +917,10 @@ class OMEMO(object):
|
|||
|
||||
# we have an encrypted message let's decrypt it
|
||||
from_jid = jid.JID(message_elt['from'])
|
||||
if from_jid.userhostJID() == client.jid.userhostJID():
|
||||
feedback_jid = jid.JID(message_elt['to'])
|
||||
else:
|
||||
feedback_jid = from_jid
|
||||
try:
|
||||
omemo_session = client._xep_0384_session
|
||||
except AttributeError:
|
||||
|
|
@ -965,6 +954,11 @@ class OMEMO(object):
|
|||
device_id=device_id,
|
||||
fingerprint=omemo_session.public_bundle.ik.encode('hex'),
|
||||
xml=encrypted_elt.toXml()))
|
||||
user_msg = (D_(u"An OMEMO message from {sender} has not been encrypted for "
|
||||
u"our device, we can't decrypt it").format(
|
||||
sender=from_jid.full()))
|
||||
extra = {C.MESS_EXTRA_INFO: C.EXTRA_INFO_DECR_ERR}
|
||||
client.feedback(feedback_jid, user_msg, extra)
|
||||
defer.returnValue(False)
|
||||
except ValueError as e:
|
||||
log.warning(_(u"Invalid recipient ID: {msg}".format(msg=e)))
|
||||
|
|
@ -1000,13 +994,14 @@ class OMEMO(object):
|
|||
user_msg = (D_(u"An OMEMO message from {sender} can't be decrypted: {reason}")
|
||||
.format(sender=from_jid.full(), reason=e))
|
||||
extra = {C.MESS_EXTRA_INFO: C.EXTRA_INFO_DECR_ERR}
|
||||
client.feedback(from_jid, user_msg, extra)
|
||||
client.feedback(feedback_jid, user_msg, extra)
|
||||
defer.returnValue(False)
|
||||
if omemo_session.republish_bundle:
|
||||
# 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)
|
||||
finally:
|
||||
if omemo_session.republish_bundle:
|
||||
# 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)
|
||||
|
||||
message_elt.children.remove(encrypted_elt)
|
||||
if plaintext:
|
||||
|
|
|
|||
2
setup.py
2
setup.py
|
|
@ -50,7 +50,7 @@ install_requires = [
|
|||
'urwid >= 1.2.0',
|
||||
'urwid-satext >= 0.6.1',
|
||||
'wokkel >= 0.7.1',
|
||||
'omemo >= 0.10.3',
|
||||
'omemo == 0.10.3', # FIXME: we block to this version until bêta
|
||||
'omemo_backend_signal',
|
||||
]
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue