Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0384.py @ 3240:d85b68e44297
plugin XEP-0384: fixed /omemo_reset + device ID type:
- the workflow done with /omemo_reset is now using the right methods
(encryptRatchetForwardingMessage and decryptRatchetForwardingMessage)
- fixed type error with device when calling python-omemo methods: a mix of str and int
was leading to two caches being created, and random bugs
author | Goffi <goffi@goffi.org> |
---|---|
date | Mon, 30 Mar 2020 19:59:17 +0200 |
parents | b0c57c9a4bd8 |
children | be6d91572633 |
comparison
equal
deleted
inserted
replaced
3239:4396bf14f5fc | 3240:d85b68e44297 |
---|---|
140 """ | 140 """ |
141 deferred.addCallback(partial(callback, True)) | 141 deferred.addCallback(partial(callback, True)) |
142 deferred.addErrback(partial(callback, False)) | 142 deferred.addErrback(partial(callback, False)) |
143 | 143 |
144 def _checkJid(self, bare_jid): | 144 def _checkJid(self, bare_jid): |
145 """Check if jid is know, and store it if not | 145 """Check if jid is known, and store it if not |
146 | 146 |
147 @param bare_jid(unicode): bare jid to check | 147 @param bare_jid(unicode): bare jid to check |
148 @return (D): Deferred fired when jid is stored | 148 @return (D): Deferred fired when jid is stored |
149 """ | 149 """ |
150 if bare_jid in self.all_jids: | 150 if bare_jid in self.all_jids: |
327 get_devices_p = self._session.getDevices(bare_jid=bare_jid) | 327 get_devices_p = self._session.getDevices(bare_jid=bare_jid) |
328 return promise2Deferred(get_devices_p) | 328 return promise2Deferred(get_devices_p) |
329 | 329 |
330 def buildSession(self, bare_jid, device, bundle): | 330 def buildSession(self, bare_jid, device, bundle): |
331 bare_jid = bare_jid.userhost() | 331 bare_jid = bare_jid.userhost() |
332 build_session_p = self._session.buildSession(bare_jid, device, bundle) | 332 build_session_p = self._session.buildSession(bare_jid, int(device), bundle) |
333 return promise2Deferred(build_session_p) | 333 return promise2Deferred(build_session_p) |
334 | 334 |
335 def deleteSession(self, bare_jid, device): | 335 def deleteSession(self, bare_jid, device): |
336 bare_jid = bare_jid.userhost() | 336 bare_jid = bare_jid.userhost() |
337 delete_session_p = self._session.deleteSession(bare_jid=bare_jid, device=device) | 337 delete_session_p = self._session.deleteSession( |
338 bare_jid=bare_jid, device=int(device)) | |
338 return promise2Deferred(delete_session_p) | 339 return promise2Deferred(delete_session_p) |
339 | 340 |
340 def encryptMessage(self, bare_jids, message, bundles=None, expect_problems=None): | 341 def encryptMessage(self, bare_jids, message, bundles=None, expect_problems=None): |
341 """Encrypt a message | 342 """Encrypt a message |
342 | 343 |
354 plaintext=message.encode(), | 355 plaintext=message.encode(), |
355 bundles=bundles, | 356 bundles=bundles, |
356 expect_problems=expect_problems) | 357 expect_problems=expect_problems) |
357 return promise2Deferred(encrypt_mess_p) | 358 return promise2Deferred(encrypt_mess_p) |
358 | 359 |
360 def encryptRatchetForwardingMessage( | |
361 self, bare_jids, bundles=None, expect_problems=None): | |
362 bare_jids = [e.userhost() for e in bare_jids] | |
363 if bundles is not None: | |
364 bundles = {e.userhost(): v for e, v in bundles.items()} | |
365 encrypt_ratchet_fwd_p = self._session.encryptRatchetForwardingMessage( | |
366 bare_jids=bare_jids, | |
367 bundles=bundles, | |
368 expect_problems=expect_problems) | |
369 return promise2Deferred(encrypt_ratchet_fwd_p) | |
370 | |
359 def decryptMessage(self, bare_jid, device, iv, message, is_pre_key_message, | 371 def decryptMessage(self, bare_jid, device, iv, message, is_pre_key_message, |
360 ciphertext, additional_information=None, allow_untrusted=False): | 372 ciphertext, additional_information=None, allow_untrusted=False): |
361 bare_jid = bare_jid.userhost() | 373 bare_jid = bare_jid.userhost() |
362 decrypt_mess_p = self._session.decryptMessage( | 374 decrypt_mess_p = self._session.decryptMessage( |
363 bare_jid=bare_jid, | 375 bare_jid=bare_jid, |
364 device=device, | 376 device=int(device), |
365 iv=iv, | 377 iv=iv, |
366 message=message, | 378 message=message, |
367 is_pre_key_message=is_pre_key_message, | 379 is_pre_key_message=is_pre_key_message, |
368 ciphertext=ciphertext, | 380 ciphertext=ciphertext, |
369 additional_information=additional_information, | 381 additional_information=additional_information, |
370 allow_untrusted=allow_untrusted | 382 allow_untrusted=allow_untrusted |
371 ) | 383 ) |
372 return promise2Deferred(decrypt_mess_p) | 384 return promise2Deferred(decrypt_mess_p) |
373 | 385 |
386 def decryptRatchetForwardingMessage( | |
387 self, bare_jid, device, iv, message, is_pre_key_message, | |
388 additional_information=None, allow_untrusted=False): | |
389 bare_jid = bare_jid.userhost() | |
390 decrypt_ratchet_fwd_p = self._session.decryptRatchetForwardingMessage( | |
391 bare_jid=bare_jid, | |
392 device=int(device), | |
393 iv=iv, | |
394 message=message, | |
395 is_pre_key_message=is_pre_key_message, | |
396 additional_information=additional_information, | |
397 allow_untrusted=allow_untrusted | |
398 ) | |
399 return promise2Deferred(decrypt_ratchet_fwd_p) | |
400 | |
374 def setTrust(self, bare_jid, device, key, trusted): | 401 def setTrust(self, bare_jid, device, key, trusted): |
375 bare_jid = bare_jid.userhost() | 402 bare_jid = bare_jid.userhost() |
376 setTrust_p = self._session.setTrust( | 403 setTrust_p = self._session.setTrust( |
377 bare_jid=bare_jid, | 404 bare_jid=bare_jid, |
378 device=device, | 405 device=int(device), |
379 key=key, | 406 key=key, |
380 trusted=trusted, | 407 trusted=trusted, |
381 ) | 408 ) |
382 return promise2Deferred(setTrust_p) | 409 return promise2Deferred(setTrust_p) |
383 | 410 |
384 def resetTrust(self, bare_jid, device): | 411 def resetTrust(self, bare_jid, device): |
385 bare_jid = bare_jid.userhost() | 412 bare_jid = bare_jid.userhost() |
386 resetTrust_p = self._session.resetTrust( | 413 resetTrust_p = self._session.resetTrust( |
387 bare_jid=bare_jid, | 414 bare_jid=bare_jid, |
388 device=device, | 415 device=int(device), |
389 ) | 416 ) |
390 return promise2Deferred(resetTrust_p) | 417 return promise2Deferred(resetTrust_p) |
391 | 418 |
392 def getTrustForJID(self, bare_jid): | 419 def getTrustForJID(self, bare_jid): |
393 bare_jid = bare_jid.userhost() | 420 bare_jid = bare_jid.userhost() |
672 xmlui.addEmpty() | 699 xmlui.addEmpty() |
673 xmlui.addEmpty() | 700 xmlui.addEmpty() |
674 | 701 |
675 return xmlui | 702 return xmlui |
676 | 703 |
677 @defer.inlineCallbacks | 704 async def profileConnected(self, client): |
678 def profileConnected(self, client): | |
679 if self._m is not None: | 705 if self._m is not None: |
680 # we keep plain text message for MUC messages we send | 706 # we keep plain text message for MUC messages we send |
681 # as we can't encrypt for our own device | 707 # as we can't encrypt for our own device |
682 client._xep_0384_muc_cache = {} | 708 client._xep_0384_muc_cache = {} |
683 # and we keep them only for some time, in case something goes wrong | 709 # and we keep them only for some time, in case something goes wrong |
689 client._xep_0384_ready = defer.Deferred() | 715 client._xep_0384_ready = defer.Deferred() |
690 # we first need to get devices ids (including our own) | 716 # we first need to get devices ids (including our own) |
691 persistent_dict = persistent.LazyPersistentBinaryDict("XEP-0384", client.profile) | 717 persistent_dict = persistent.LazyPersistentBinaryDict("XEP-0384", client.profile) |
692 client._xep_0384_data = persistent_dict | 718 client._xep_0384_data = persistent_dict |
693 # all known devices of profile | 719 # all known devices of profile |
694 devices = yield self.getDevices(client) | 720 devices = await self.getDevices(client) |
695 # and our own device id | 721 # and our own device id |
696 device_id = yield persistent_dict.get(KEY_DEVICE_ID) | 722 device_id = await persistent_dict.get(KEY_DEVICE_ID) |
697 if device_id is None: | 723 if device_id is None: |
698 log.info(_("We have no identity for this device yet, let's generate one")) | 724 log.info(_("We have no identity for this device yet, let's generate one")) |
699 # we have a new device, we create device_id | 725 # we have a new device, we create device_id |
700 device_id = random.randint(1, 2**31-1) | 726 device_id = random.randint(1, 2**31-1) |
701 # we check that it's really unique | 727 # we check that it's really unique |
707 log.debug(f"our OMEMO device id is {device_id}") | 733 log.debug(f"our OMEMO device id is {device_id}") |
708 | 734 |
709 if device_id not in devices: | 735 if device_id not in devices: |
710 log.debug(f"our device id ({device_id}) is not in the list, adding it") | 736 log.debug(f"our device id ({device_id}) is not in the list, adding it") |
711 devices.add(device_id) | 737 devices.add(device_id) |
712 yield defer.ensureDeferred(self.setDevices(client, devices)) | 738 await defer.ensureDeferred(self.setDevices(client, devices)) |
713 | 739 |
714 all_jids = yield persistent_dict.get(KEY_ALL_JIDS, set()) | 740 all_jids = await persistent_dict.get(KEY_ALL_JIDS, set()) |
715 | 741 |
716 omemo_storage = OmemoStorage(client, device_id, all_jids) | 742 omemo_storage = OmemoStorage(client, device_id, all_jids) |
717 omemo_session = yield OmemoSession.create(client, omemo_storage, device_id) | 743 omemo_session = await OmemoSession.create(client, omemo_storage, device_id) |
718 client._xep_0384_cache = {} | 744 client._xep_0384_cache = {} |
719 client._xep_0384_session = omemo_session | 745 client._xep_0384_session = omemo_session |
720 client._xep_0384_device_id = device_id | 746 client._xep_0384_device_id = device_id |
721 yield omemo_session.newDeviceList(client.jid, devices) | 747 await omemo_session.newDeviceList(client.jid, devices) |
722 if omemo_session.republish_bundle: | 748 if omemo_session.republish_bundle: |
723 log.info(_("Saving public bundle for this device ({device_id})").format( | 749 log.info(_("Saving public bundle for this device ({device_id})").format( |
724 device_id=device_id)) | 750 device_id=device_id)) |
725 yield defer.ensureDeferred( | 751 await defer.ensureDeferred( |
726 self.setBundle(client, omemo_session.public_bundle, device_id) | 752 self.setBundle(client, omemo_session.public_bundle, device_id) |
727 ) | 753 ) |
728 client._xep_0384_ready.callback(None) | 754 client._xep_0384_ready.callback(None) |
729 del client._xep_0384_ready | 755 del client._xep_0384_ready |
756 | |
730 | 757 |
731 ## XMPP PEP nodes manipulation | 758 ## XMPP PEP nodes manipulation |
732 | 759 |
733 # devices | 760 # devices |
734 | 761 |
1124 msg = _("Too many iterations in encryption loop") | 1151 msg = _("Too many iterations in encryption loop") |
1125 log.error(msg) | 1152 log.error(msg) |
1126 raise exceptions.InternalError(msg) | 1153 raise exceptions.InternalError(msg) |
1127 # encryptMessage may fail, in case of e.g. trust issue or missing bundle | 1154 # encryptMessage may fail, in case of e.g. trust issue or missing bundle |
1128 try: | 1155 try: |
1129 encrypted = await omemo_session.encryptMessage( | 1156 if not message: |
1130 entity_bare_jids, | 1157 encrypted = await omemo_session.encryptRatchetForwardingMessage( |
1131 message, | 1158 entity_bare_jids, |
1132 bundles, | 1159 bundles, |
1133 expect_problems = expect_problems) | 1160 expect_problems = expect_problems) |
1161 else: | |
1162 encrypted = await omemo_session.encryptMessage( | |
1163 entity_bare_jids, | |
1164 message, | |
1165 bundles, | |
1166 expect_problems = expect_problems) | |
1134 except omemo_excpt.EncryptionProblemsException as e: | 1167 except omemo_excpt.EncryptionProblemsException as e: |
1135 # we know the problem to solve, we can try to fix them | 1168 # we know the problem to solve, we can try to fix them |
1136 await self.handleProblems( | 1169 await self.handleProblems( |
1137 client, | 1170 client, |
1138 feedback_jid=feedback_jid, | 1171 feedback_jid=feedback_jid, |
1273 "bare_jid": from_jid.userhostJID(), | 1306 "bare_jid": from_jid.userhostJID(), |
1274 "device": s_device_id, | 1307 "device": s_device_id, |
1275 "iv": base64.b64decode(bytes(iv_elt)), | 1308 "iv": base64.b64decode(bytes(iv_elt)), |
1276 "message": base64.b64decode(bytes(key_elt)), | 1309 "message": base64.b64decode(bytes(key_elt)), |
1277 "is_pre_key_message": is_pre_key, | 1310 "is_pre_key_message": is_pre_key, |
1278 "ciphertext": base64.b64decode(bytes(payload_elt)) | |
1279 if payload_elt is not None else None, | |
1280 "additional_information": additional_information, | 1311 "additional_information": additional_information, |
1281 } | 1312 } |
1282 | 1313 |
1283 try: | 1314 try: |
1284 try: | 1315 if payload_elt is None: |
1285 plaintext = yield omemo_session.decryptMessage(**kwargs) | 1316 omemo_session.decryptRatchetForwardingMessage(**kwargs) |
1286 except omemo_excpt.TrustException: | 1317 plaintext = None |
1287 post_treat.addCallback(client.encryption.markAsUntrusted) | |
1288 kwargs['allow_untrusted'] = True | |
1289 plaintext = yield omemo_session.decryptMessage(**kwargs) | |
1290 else: | 1318 else: |
1291 post_treat.addCallback(client.encryption.markAsTrusted) | 1319 kwargs["ciphertext"] = base64.b64decode(bytes(payload_elt)) |
1292 plaintext = plaintext.decode() | 1320 try: |
1321 plaintext = yield omemo_session.decryptMessage(**kwargs) | |
1322 except omemo_excpt.TrustException: | |
1323 post_treat.addCallback(client.encryption.markAsUntrusted) | |
1324 kwargs['allow_untrusted'] = True | |
1325 plaintext = yield omemo_session.decryptMessage(**kwargs) | |
1326 else: | |
1327 post_treat.addCallback(client.encryption.markAsTrusted) | |
1328 plaintext = plaintext.decode() | |
1293 except Exception as e: | 1329 except Exception as e: |
1294 log.warning(_("Can't decrypt message: {reason}\n{xml}").format( | 1330 log.warning(_("Can't decrypt message: {reason}\n{xml}").format( |
1295 reason=e, xml=message_elt.toXml())) | 1331 reason=e, xml=message_elt.toXml())) |
1296 user_msg = (D_( | 1332 user_msg = (D_( |
1297 "An OMEMO message from {sender} can't be decrypted: {reason}") | 1333 "An OMEMO message from {sender} can't be decrypted: {reason}") |