comparison sat/plugins/plugin_xep_0384.py @ 3028:ab2696e34d29

Python 3 port: /!\ this is a huge commit /!\ starting from this commit, SàT is needs Python 3.6+ /!\ SàT maybe be instable or some feature may not work anymore, this will improve with time This patch port backend, bridge and frontends to Python 3. Roughly this has been done this way: - 2to3 tools has been applied (with python 3.7) - all references to python2 have been replaced with python3 (notably shebangs) - fixed files not handled by 2to3 (notably the shell script) - several manual fixes - fixed issues reported by Python 3 that where not handled in Python 2 - replaced "async" with "async_" when needed (it's a reserved word from Python 3.7) - replaced zope's "implements" with @implementer decorator - temporary hack to handle data pickled in database, as str or bytes may be returned, to be checked later - fixed hash comparison for password - removed some code which is not needed anymore with Python 3 - deactivated some code which needs to be checked (notably certificate validation) - tested with jp, fixed reported issues until some basic commands worked - ported Primitivus (after porting dependencies like urwid satext) - more manual fixes
author Goffi <goffi@goffi.org>
date Tue, 13 Aug 2019 19:08:41 +0200
parents 03a09e16bf28
children ffcdd93b61fa
comparison
equal deleted inserted replaced
3027:ff5bcb12ae60 3028:ab2696e34d29
1 #!/usr/bin/env python2 1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*- 2 # -*- coding: utf-8 -*-
3 3
4 # SAT plugin for OMEMO encryption 4 # SAT plugin for OMEMO encryption
5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) 5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org)
6 6
37 from omemo.extendedpublicbundle import ExtendedPublicBundle 37 from omemo.extendedpublicbundle import ExtendedPublicBundle
38 from omemo_backend_signal import BACKEND as omemo_backend 38 from omemo_backend_signal import BACKEND as omemo_backend
39 # from omemo import wireformat 39 # from omemo import wireformat
40 except ImportError as e: 40 except ImportError as e:
41 raise exceptions.MissingModule( 41 raise exceptions.MissingModule(
42 u'Missing module omemo, please download/install it. You can use ' 42 'Missing module omemo, please download/install it. You can use '
43 u'"pip install omemo"' 43 '"pip install omemo"'
44 ) 44 )
45 45
46 log = getLogger(__name__) 46 log = getLogger(__name__)
47 47
48 PLUGIN_INFO = { 48 PLUGIN_INFO = {
49 C.PI_NAME: u"OMEMO", 49 C.PI_NAME: "OMEMO",
50 C.PI_IMPORT_NAME: u"XEP-0384", 50 C.PI_IMPORT_NAME: "XEP-0384",
51 C.PI_TYPE: u"SEC", 51 C.PI_TYPE: "SEC",
52 C.PI_PROTOCOLS: [u"XEP-0384"], 52 C.PI_PROTOCOLS: ["XEP-0384"],
53 C.PI_DEPENDENCIES: [u"XEP-0163", u"XEP-0280", u"XEP-0334", u"XEP-0060"], 53 C.PI_DEPENDENCIES: ["XEP-0163", "XEP-0280", "XEP-0334", "XEP-0060"],
54 C.PI_MAIN: u"OMEMO", 54 C.PI_MAIN: "OMEMO",
55 C.PI_HANDLER: u"no", 55 C.PI_HANDLER: "no",
56 C.PI_DESCRIPTION: _(u"""Implementation of OMEMO"""), 56 C.PI_DESCRIPTION: _("""Implementation of OMEMO"""),
57 } 57 }
58 58
59 OMEMO_MIN_VER = (0, 10, 4) 59 OMEMO_MIN_VER = (0, 10, 4)
60 NS_OMEMO = "eu.siacs.conversations.axolotl" 60 NS_OMEMO = "eu.siacs.conversations.axolotl"
61 NS_OMEMO_DEVICES = NS_OMEMO + ".devicelist" 61 NS_OMEMO_DEVICES = NS_OMEMO + ".devicelist"
157 def storeState(self, callback, state): 157 def storeState(self, callback, state):
158 d = self.data.force(KEY_STATE, state) 158 d = self.data.force(KEY_STATE, state)
159 self.setCb(d, callback) 159 self.setCb(d, callback)
160 160
161 def loadSession(self, callback, bare_jid, device_id): 161 def loadSession(self, callback, bare_jid, device_id):
162 key = u'\n'.join([KEY_SESSION, bare_jid, unicode(device_id)]) 162 key = '\n'.join([KEY_SESSION, bare_jid, str(device_id)])
163 d = self.data.get(key) 163 d = self.data.get(key)
164 self.setCb(d, callback) 164 self.setCb(d, callback)
165 165
166 def storeSession(self, callback, bare_jid, device_id, session): 166 def storeSession(self, callback, bare_jid, device_id, session):
167 key = u'\n'.join([KEY_SESSION, bare_jid, unicode(device_id)]) 167 key = '\n'.join([KEY_SESSION, bare_jid, str(device_id)])
168 d = self.data.force(key, session) 168 d = self.data.force(key, session)
169 self.setCb(d, callback) 169 self.setCb(d, callback)
170 170
171 def deleteSession(self, callback, bare_jid, device_id): 171 def deleteSession(self, callback, bare_jid, device_id):
172 key = u'\n'.join([KEY_SESSION, bare_jid, unicode(device_id)]) 172 key = '\n'.join([KEY_SESSION, bare_jid, str(device_id)])
173 d = self.data.remove(key) 173 d = self.data.remove(key)
174 self.setCb(d, callback) 174 self.setCb(d, callback)
175 175
176 def loadActiveDevices(self, callback, bare_jid): 176 def loadActiveDevices(self, callback, bare_jid):
177 key = u'\n'.join([KEY_ACTIVE_DEVICES, bare_jid]) 177 key = '\n'.join([KEY_ACTIVE_DEVICES, bare_jid])
178 d = self.data.get(key, {}) 178 d = self.data.get(key, {})
179 if callback is not None: 179 if callback is not None:
180 self.setCb(d, callback) 180 self.setCb(d, callback)
181 return d 181 return d
182 182
183 def loadInactiveDevices(self, callback, bare_jid): 183 def loadInactiveDevices(self, callback, bare_jid):
184 key = u'\n'.join([KEY_INACTIVE_DEVICES, bare_jid]) 184 key = '\n'.join([KEY_INACTIVE_DEVICES, bare_jid])
185 d = self.data.get(key, {}) 185 d = self.data.get(key, {})
186 if callback is not None: 186 if callback is not None:
187 self.setCb(d, callback) 187 self.setCb(d, callback)
188 return d 188 return d
189 189
190 def storeActiveDevices(self, callback, bare_jid, devices): 190 def storeActiveDevices(self, callback, bare_jid, devices):
191 key = u'\n'.join([KEY_ACTIVE_DEVICES, bare_jid]) 191 key = '\n'.join([KEY_ACTIVE_DEVICES, bare_jid])
192 d = self._checkJid(bare_jid) 192 d = self._checkJid(bare_jid)
193 d.addCallback(lambda _: self.data.force(key, devices)) 193 d.addCallback(lambda _: self.data.force(key, devices))
194 self.setCb(d, callback) 194 self.setCb(d, callback)
195 195
196 def storeInactiveDevices(self, callback, bare_jid, devices): 196 def storeInactiveDevices(self, callback, bare_jid, devices):
197 key = u'\n'.join([KEY_INACTIVE_DEVICES, bare_jid]) 197 key = '\n'.join([KEY_INACTIVE_DEVICES, bare_jid])
198 d = self._checkJid(bare_jid) 198 d = self._checkJid(bare_jid)
199 d.addCallback(lambda _: self.data.force(key, devices)) 199 d.addCallback(lambda _: self.data.force(key, devices))
200 self.setCb(d, callback) 200 self.setCb(d, callback)
201 201
202 def storeTrust(self, callback, bare_jid, device_id, trust): 202 def storeTrust(self, callback, bare_jid, device_id, trust):
203 key = u'\n'.join([KEY_TRUST, bare_jid, unicode(device_id)]) 203 key = '\n'.join([KEY_TRUST, bare_jid, str(device_id)])
204 d = self.data.force(key, trust) 204 d = self.data.force(key, trust)
205 self.setCb(d, callback) 205 self.setCb(d, callback)
206 206
207 def loadTrust(self, callback, bare_jid, device_id): 207 def loadTrust(self, callback, bare_jid, device_id):
208 key = u'\n'.join([KEY_TRUST, bare_jid, unicode(device_id)]) 208 key = '\n'.join([KEY_TRUST, bare_jid, str(device_id)])
209 d = self.data.get(key) 209 d = self.data.get(key)
210 if callback is not None: 210 if callback is not None:
211 self.setCb(d, callback) 211 self.setCb(d, callback)
212 return d 212 return d
213 213
219 219
220 def _deleteJID_logResults(self, results): 220 def _deleteJID_logResults(self, results):
221 failed = [success for success, __ in results if not success] 221 failed = [success for success, __ in results if not success]
222 if failed: 222 if failed:
223 log.warning( 223 log.warning(
224 u"delete JID failed for {failed_count} on {total_count} operations" 224 "delete JID failed for {failed_count} on {total_count} operations"
225 .format(failed_count=len(failed), total_count=len(results))) 225 .format(failed_count=len(failed), total_count=len(results)))
226 else: 226 else:
227 log.info( 227 log.info(
228 u"Delete JID operation succeed ({total_count} operations)." 228 "Delete JID operation succeed ({total_count} operations)."
229 .format(total_count=len(results))) 229 .format(total_count=len(results)))
230 230
231 def _deleteJID_gotDevices(self, results, bare_jid): 231 def _deleteJID_gotDevices(self, results, bare_jid):
232 assert len(results) == 2 232 assert len(results) == 2
233 active_success, active_devices = results[0] 233 active_success, active_devices = results[0]
238 log.warning("Can't retrieve devices for {bare_jid}: {reason}" 238 log.warning("Can't retrieve devices for {bare_jid}: {reason}"
239 .format(bare_jid=bare_jid, reason=active_devices)) 239 .format(bare_jid=bare_jid, reason=active_devices))
240 else: 240 else:
241 for device_id in devices: 241 for device_id in devices:
242 for key in (KEY_SESSION, KEY_TRUST): 242 for key in (KEY_SESSION, KEY_TRUST):
243 k = u'\n'.join([key, bare_jid, unicode(device_id)]) 243 k = '\n'.join([key, bare_jid, str(device_id)])
244 d_list.append(self.data.remove(k)) 244 d_list.append(self.data.remove(k))
245 245
246 d_list.append(self.data.remove(KEY_ACTIVE_DEVICES, bare_jid)) 246 d_list.append(self.data.remove(KEY_ACTIVE_DEVICES, bare_jid))
247 d_list.append(self.data.remove(KEY_INACTIVE_DEVICES, bare_jid)) 247 d_list.append(self.data.remove(KEY_INACTIVE_DEVICES, bare_jid))
248 d_list.append(lambda __: self.all_jids.discard(bare_jid)) 248 d_list.append(lambda __: self.all_jids.discard(bare_jid))
255 255
256 def deleteJID(self, callback, bare_jid): 256 def deleteJID(self, callback, bare_jid):
257 """Retrieve all (in)actives of bare_jid, and delete all related keys""" 257 """Retrieve all (in)actives of bare_jid, and delete all related keys"""
258 d_list = [] 258 d_list = []
259 259
260 key = u'\n'.join([KEY_ACTIVE_DEVICES, bare_jid]) 260 key = '\n'.join([KEY_ACTIVE_DEVICES, bare_jid])
261 d_list.append(self.data.get(key, [])) 261 d_list.append(self.data.get(key, []))
262 262
263 key = u'\n'.join([KEY_INACTIVE_DEVICES, bare_jid]) 263 key = '\n'.join([KEY_INACTIVE_DEVICES, bare_jid])
264 d_inactive = self.data.get(key, {}) 264 d_inactive = self.data.get(key, {})
265 # inactive devices are returned as a dict mapping from devices_id to timestamp 265 # inactive devices are returned as a dict mapping from devices_id to timestamp
266 # but we only need devices ids 266 # but we only need devices ids
267 d_inactive.addCallback(lambda devices: [k for k, __ in devices]) 267 d_inactive.addCallback(lambda devices: [k for k, __ in devices])
268 268
330 if isinstance(bare_jids, jid.JID): 330 if isinstance(bare_jids, jid.JID):
331 bare_jids = bare_jids.userhost() 331 bare_jids = bare_jids.userhost()
332 else: 332 else:
333 bare_jids = [e.userhost() for e in bare_jids] 333 bare_jids = [e.userhost() for e in bare_jids]
334 if bundles is not None: 334 if bundles is not None:
335 bundles = {e.userhost(): v for e, v in bundles.iteritems()} 335 bundles = {e.userhost(): v for e, v in bundles.items()}
336 encrypt_mess_p = self._session.encryptMessage( 336 encrypt_mess_p = self._session.encryptMessage(
337 bare_jids=bare_jids, 337 bare_jids=bare_jids,
338 plaintext=message.encode('utf-8'), 338 plaintext=message.encode('utf-8'),
339 bundles=bundles, 339 bundles=bundles,
340 expect_problems=expect_problems) 340 expect_problems=expect_problems)
378 378
379 379
380 class OMEMO(object): 380 class OMEMO(object):
381 381
382 def __init__(self, host): 382 def __init__(self, host):
383 log.info(_(u"OMEMO plugin initialization (omemo module v{version})").format( 383 log.info(_("OMEMO plugin initialization (omemo module v{version})").format(
384 version=omemo.__version__)) 384 version=omemo.__version__))
385 version = tuple(map(int, omemo.__version__.split(u'.')[:3])) 385 version = tuple(map(int, omemo.__version__.split('.')[:3]))
386 if version < OMEMO_MIN_VER: 386 if version < OMEMO_MIN_VER:
387 log.warning(_( 387 log.warning(_(
388 u"Your version of omemo module is too old: {v[0]}.{v[1]}.{v[2]} is " 388 "Your version of omemo module is too old: {v[0]}.{v[1]}.{v[2]} is "
389 u"minimum required), please update.").format(v=OMEMO_MIN_VER)) 389 "minimum required), please update.").format(v=OMEMO_MIN_VER))
390 raise exceptions.CancelError("module is too old") 390 raise exceptions.CancelError("module is too old")
391 self.host = host 391 self.host = host
392 self._p_hints = host.plugins[u"XEP-0334"] 392 self._p_hints = host.plugins["XEP-0334"]
393 self._p_carbons = host.plugins[u"XEP-0280"] 393 self._p_carbons = host.plugins["XEP-0280"]
394 self._p = host.plugins[u"XEP-0060"] 394 self._p = host.plugins["XEP-0060"]
395 host.trigger.add("MessageReceived", self._messageReceivedTrigger, priority=100050) 395 host.trigger.add("MessageReceived", self._messageReceivedTrigger, priority=100050)
396 host.trigger.add("sendMessageData", self._sendMessageDataTrigger) 396 host.trigger.add("sendMessageData", self._sendMessageDataTrigger)
397 self.host.registerEncryptionPlugin(self, u"OMEMO", NS_OMEMO, 100) 397 self.host.registerEncryptionPlugin(self, "OMEMO", NS_OMEMO, 100)
398 pep = host.plugins['XEP-0163'] 398 pep = host.plugins['XEP-0163']
399 pep.addPEPEvent("OMEMO_DEVICES", NS_OMEMO_DEVICES, self.onNewDevices) 399 pep.addPEPEvent("OMEMO_DEVICES", NS_OMEMO_DEVICES, self.onNewDevices)
400 400
401 @defer.inlineCallbacks 401 @defer.inlineCallbacks
402 def trustUICb(self, xmlui_data, trust_data, expect_problems=None, 402 def trustUICb(self, xmlui_data, trust_data, expect_problems=None,
404 if C.bool(xmlui_data.get('cancelled', 'false')): 404 if C.bool(xmlui_data.get('cancelled', 'false')):
405 defer.returnValue({}) 405 defer.returnValue({})
406 client = self.host.getClient(profile) 406 client = self.host.getClient(profile)
407 session = client._xep_0384_session 407 session = client._xep_0384_session
408 answer = xml_tools.XMLUIResult2DataFormResult(xmlui_data) 408 answer = xml_tools.XMLUIResult2DataFormResult(xmlui_data)
409 for key, value in answer.iteritems(): 409 for key, value in answer.items():
410 if key.startswith(u'trust_'): 410 if key.startswith('trust_'):
411 trust_id = key[6:] 411 trust_id = key[6:]
412 else: 412 else:
413 continue 413 continue
414 data = trust_data[trust_id] 414 data = trust_data[trust_id]
415 trust = C.bool(value) 415 trust = C.bool(value)
416 if trust: 416 if trust:
417 yield session.trust(data[u"jid"], 417 yield session.trust(data["jid"],
418 data[u"device"], 418 data["device"],
419 data[u"ik"]) 419 data["ik"])
420 else: 420 else:
421 yield session.distrust(data[u"jid"], 421 yield session.distrust(data["jid"],
422 data[u"device"], 422 data["device"],
423 data[u"ik"]) 423 data["ik"])
424 if expect_problems is not None: 424 if expect_problems is not None:
425 expect_problems.setdefault(data.bare_jid, set()).add(data.device) 425 expect_problems.setdefault(data.bare_jid, set()).add(data.device)
426 defer.returnValue({}) 426 defer.returnValue({})
427 427
428 428
447 @return D(xmlui): trust management form 447 @return D(xmlui): trust management form
448 """ 448 """
449 # we need entity_jid xor trust_data 449 # we need entity_jid xor trust_data
450 assert entity_jid and not trust_data or not entity_jid and trust_data 450 assert entity_jid and not trust_data or not entity_jid and trust_data
451 if entity_jid and entity_jid.resource: 451 if entity_jid and entity_jid.resource:
452 raise ValueError(u"A bare jid is expected") 452 raise ValueError("A bare jid is expected")
453 453
454 session = client._xep_0384_session 454 session = client._xep_0384_session
455 455
456 if trust_data is None: 456 if trust_data is None:
457 cache = client._xep_0384_cache.setdefault(entity_jid, {}) 457 cache = client._xep_0384_cache.setdefault(entity_jid, {})
458 trust_data = {} 458 trust_data = {}
459 trust_session_data = yield session.getTrustForJID(entity_jid) 459 trust_session_data = yield session.getTrustForJID(entity_jid)
460 bare_jid_s = entity_jid.userhost() 460 bare_jid_s = entity_jid.userhost()
461 for device_id, trust_info in trust_session_data['active'].iteritems(): 461 for device_id, trust_info in trust_session_data['active'].items():
462 if trust_info is None: 462 if trust_info is None:
463 # device has never been (un)trusted, we have to retrieve its 463 # device has never been (un)trusted, we have to retrieve its
464 # fingerprint (i.e. identity key or "ik") through public bundle 464 # fingerprint (i.e. identity key or "ik") through public bundle
465 if device_id not in cache: 465 if device_id not in cache:
466 bundles, missing = yield self.getBundles(client, 466 bundles, missing = yield self.getBundles(client,
467 entity_jid, 467 entity_jid,
468 [device_id]) 468 [device_id])
469 if device_id not in bundles: 469 if device_id not in bundles:
470 log.warning(_( 470 log.warning(_(
471 u"Can't find bundle for device {device_id} of user " 471 "Can't find bundle for device {device_id} of user "
472 u"{bare_jid}, ignoring").format(device_id=device_id, 472 "{bare_jid}, ignoring").format(device_id=device_id,
473 bare_jid=bare_jid_s)) 473 bare_jid=bare_jid_s))
474 continue 474 continue
475 cache[device_id] = bundles[device_id] 475 cache[device_id] = bundles[device_id]
476 # TODO: replace False below by None when undecided 476 # TODO: replace False below by None when undecided
477 # trusts are handled 477 # trusts are handled
478 trust_info = { 478 trust_info = {
479 u"key": cache[device_id].ik, 479 "key": cache[device_id].ik,
480 u"trusted": False 480 "trusted": False
481 } 481 }
482 482
483 ik = trust_info["key"] 483 ik = trust_info["key"]
484 trust_id = unicode(hash((bare_jid_s, device_id, ik))) 484 trust_id = str(hash((bare_jid_s, device_id, ik)))
485 trust_data[trust_id] = { 485 trust_data[trust_id] = {
486 u"jid": entity_jid, 486 "jid": entity_jid,
487 u"device": device_id, 487 "device": device_id,
488 u"ik": ik, 488 "ik": ik,
489 u"trusted": trust_info[u"trusted"], 489 "trusted": trust_info["trusted"],
490 } 490 }
491 491
492 if submit_id is None: 492 if submit_id is None:
493 submit_id = self.host.registerCallback(partial(self.trustUICb, 493 submit_id = self.host.registerCallback(partial(self.trustUICb,
494 trust_data=trust_data), 494 trust_data=trust_data),
495 with_data=True, 495 with_data=True,
496 one_shot=True) 496 one_shot=True)
497 xmlui = xml_tools.XMLUI( 497 xmlui = xml_tools.XMLUI(
498 panel_type = C.XMLUI_FORM, 498 panel_type = C.XMLUI_FORM,
499 title = D_(u"OMEMO trust management"), 499 title = D_("OMEMO trust management"),
500 submit_id = submit_id 500 submit_id = submit_id
501 ) 501 )
502 xmlui.addText(D_( 502 xmlui.addText(D_(
503 u"This is OMEMO trusting system. You'll see below the devices of your " 503 "This is OMEMO trusting system. You'll see below the devices of your "
504 u"contacts, and a checkbox to trust them or not. A trusted device " 504 "contacts, and a checkbox to trust them or not. A trusted device "
505 u"can read your messages in plain text, so be sure to only validate " 505 "can read your messages in plain text, so be sure to only validate "
506 u"devices that you are sure are belonging to your contact. It's better " 506 "devices that you are sure are belonging to your contact. It's better "
507 u"to do this when you are next to your contact and her/his device, so " 507 "to do this when you are next to your contact and her/his device, so "
508 u"you can check the \"fingerprint\" (the number next to the device) " 508 "you can check the \"fingerprint\" (the number next to the device) "
509 u"yourself. Do *not* validate a device if the fingerprint is wrong!")) 509 "yourself. Do *not* validate a device if the fingerprint is wrong!"))
510 510
511 xmlui.changeContainer("label") 511 xmlui.changeContainer("label")
512 xmlui.addLabel(D_(u"This device ID")) 512 xmlui.addLabel(D_("This device ID"))
513 xmlui.addText(unicode(client._xep_0384_device_id)) 513 xmlui.addText(str(client._xep_0384_device_id))
514 xmlui.addLabel(D_(u"This device fingerprint")) 514 xmlui.addLabel(D_("This device fingerprint"))
515 ik_hex = session.public_bundle.ik.encode('hex').upper() 515 ik_hex = session.public_bundle.ik.encode('hex').upper()
516 fp_human = u' '.join([ik_hex[i:i+8] for i in range(0, len(ik_hex), 8)]) 516 fp_human = ' '.join([ik_hex[i:i+8] for i in range(0, len(ik_hex), 8)])
517 xmlui.addText(fp_human) 517 xmlui.addText(fp_human)
518 xmlui.addEmpty() 518 xmlui.addEmpty()
519 xmlui.addEmpty() 519 xmlui.addEmpty()
520 520
521 521
522 for trust_id, data in trust_data.iteritems(): 522 for trust_id, data in trust_data.items():
523 xmlui.addLabel(D_(u"Contact")) 523 xmlui.addLabel(D_("Contact"))
524 xmlui.addJid(data[u'jid']) 524 xmlui.addJid(data['jid'])
525 xmlui.addLabel(D_(u"Device ID")) 525 xmlui.addLabel(D_("Device ID"))
526 xmlui.addText(unicode(data[u'device'])) 526 xmlui.addText(str(data['device']))
527 xmlui.addLabel(D_(u"Fingerprint")) 527 xmlui.addLabel(D_("Fingerprint"))
528 ik_hex = data[u'ik'].encode('hex').upper() 528 ik_hex = data['ik'].encode('hex').upper()
529 fp_human = u' '.join([ik_hex[i:i+8] for i in range(0, len(ik_hex), 8)]) 529 fp_human = ' '.join([ik_hex[i:i+8] for i in range(0, len(ik_hex), 8)])
530 xmlui.addText(fp_human) 530 xmlui.addText(fp_human)
531 xmlui.addLabel(D_(u"Trust this device?")) 531 xmlui.addLabel(D_("Trust this device?"))
532 xmlui.addBool(u"trust_{}".format(trust_id), 532 xmlui.addBool("trust_{}".format(trust_id),
533 value=C.boolConst(data.get(u'trusted', False))) 533 value=C.boolConst(data.get('trusted', False)))
534 534
535 xmlui.addEmpty() 535 xmlui.addEmpty()
536 xmlui.addEmpty() 536 xmlui.addEmpty()
537 537
538 defer.returnValue(xmlui) 538 defer.returnValue(xmlui)
547 # all known devices of profile 547 # all known devices of profile
548 devices = yield self.getDevices(client) 548 devices = yield self.getDevices(client)
549 # and our own device id 549 # and our own device id
550 device_id = yield persistent_dict.get(KEY_DEVICE_ID) 550 device_id = yield persistent_dict.get(KEY_DEVICE_ID)
551 if device_id is None: 551 if device_id is None:
552 log.info(_(u"We have no identity for this device yet, let's generate one")) 552 log.info(_("We have no identity for this device yet, let's generate one"))
553 # we have a new device, we create device_id 553 # we have a new device, we create device_id
554 device_id = random.randint(1, 2**31-1) 554 device_id = random.randint(1, 2**31-1)
555 # we check that it's really unique 555 # we check that it's really unique
556 while device_id in devices: 556 while device_id in devices:
557 device_id = random.randint(1, 2**31-1) 557 device_id = random.randint(1, 2**31-1)
569 client._xep_0384_cache = {} 569 client._xep_0384_cache = {}
570 client._xep_0384_session = omemo_session 570 client._xep_0384_session = omemo_session
571 client._xep_0384_device_id = device_id 571 client._xep_0384_device_id = device_id
572 yield omemo_session.newDeviceList(client.jid, devices) 572 yield omemo_session.newDeviceList(client.jid, devices)
573 if omemo_session.republish_bundle: 573 if omemo_session.republish_bundle:
574 log.info(_(u"Saving public bundle for this device ({device_id})").format( 574 log.info(_("Saving public bundle for this device ({device_id})").format(
575 device_id=device_id)) 575 device_id=device_id))
576 yield self.setBundle(client, omemo_session.public_bundle, device_id) 576 yield self.setBundle(client, omemo_session.public_bundle, device_id)
577 client._xep_0384_ready.callback(None) 577 client._xep_0384_ready.callback(None)
578 del client._xep_0384_ready 578 del client._xep_0384_ready
579 579
587 @param items(iterable[domish.Element]): items as retrieved by getItems 587 @param items(iterable[domish.Element]): items as retrieved by getItems
588 @return set[int]: parsed devices 588 @return set[int]: parsed devices
589 """ 589 """
590 devices = set() 590 devices = set()
591 if len(items) > 1: 591 if len(items) > 1:
592 log.warning(_(u"OMEMO devices list is stored in more that one items, " 592 log.warning(_("OMEMO devices list is stored in more that one items, "
593 u"this is not expected")) 593 "this is not expected"))
594 if items: 594 if items:
595 try: 595 try:
596 list_elt = next(items[0].elements(NS_OMEMO, 'list')) 596 list_elt = next(items[0].elements(NS_OMEMO, 'list'))
597 except StopIteration: 597 except StopIteration:
598 log.warning(_(u"no list element found in OMEMO devices list")) 598 log.warning(_("no list element found in OMEMO devices list"))
599 return 599 return
600 for device_elt in list_elt.elements(NS_OMEMO, 'device'): 600 for device_elt in list_elt.elements(NS_OMEMO, 'device'):
601 try: 601 try:
602 device_id = int(device_elt['id']) 602 device_id = int(device_elt['id'])
603 except KeyError: 603 except KeyError:
604 log.warning(_(u'device element is missing "id" attribute: {elt}') 604 log.warning(_('device element is missing "id" attribute: {elt}')
605 .format(elt=device_elt.toXml())) 605 .format(elt=device_elt.toXml()))
606 except ValueError: 606 except ValueError:
607 log.warning(_(u'invalid device id: {device_id}').format( 607 log.warning(_('invalid device id: {device_id}').format(
608 device_id=device_elt['id'])) 608 device_id=device_elt['id']))
609 else: 609 else:
610 devices.add(device_id) 610 devices.add(device_id)
611 return devices 611 return devices
612 612
622 assert not entity_jid.resource 622 assert not entity_jid.resource
623 try: 623 try:
624 items, metadata = yield self._p.getItems(client, entity_jid, NS_OMEMO_DEVICES) 624 items, metadata = yield self._p.getItems(client, entity_jid, NS_OMEMO_DEVICES)
625 except error.StanzaError as e: 625 except error.StanzaError as e:
626 if e.condition == 'item-not-found': 626 if e.condition == 'item-not-found':
627 log.info(_(u"there is no node to handle OMEMO devices")) 627 log.info(_("there is no node to handle OMEMO devices"))
628 defer.returnValue(set()) 628 defer.returnValue(set())
629 raise e 629 raise e
630 630
631 devices = self.parseDevices(items) 631 devices = self.parseDevices(items)
632 defer.returnValue(devices) 632 defer.returnValue(devices)
633 633
634 def setDevicesEb(self, failure_): 634 def setDevicesEb(self, failure_):
635 log.warning(_(u"Can't set devices: {reason}").format(reason=failure_)) 635 log.warning(_("Can't set devices: {reason}").format(reason=failure_))
636 636
637 def setDevices(self, client, devices): 637 def setDevices(self, client, devices):
638 list_elt = domish.Element((NS_OMEMO, 'list')) 638 list_elt = domish.Element((NS_OMEMO, 'list'))
639 for device in devices: 639 for device in devices:
640 device_elt = list_elt.addElement('device') 640 device_elt = list_elt.addElement('device')
641 device_elt['id'] = unicode(device) 641 device_elt['id'] = str(device)
642 d = self._p.sendItem( 642 d = self._p.sendItem(
643 client, None, NS_OMEMO_DEVICES, list_elt, item_id=self._p.ID_SINGLETON) 643 client, None, NS_OMEMO_DEVICES, list_elt, item_id=self._p.ID_SINGLETON)
644 d.addErrback(self.setDevicesEb) 644 d.addErrback(self.setDevicesEb)
645 return d 645 return d
646 646
664 for device_id in devices_ids: 664 for device_id in devices_ids:
665 node = NS_OMEMO_BUNDLE.format(device_id=device_id) 665 node = NS_OMEMO_BUNDLE.format(device_id=device_id)
666 try: 666 try:
667 items, metadata = yield self._p.getItems(client, entity_jid, node) 667 items, metadata = yield self._p.getItems(client, entity_jid, node)
668 except error.StanzaError as e: 668 except error.StanzaError as e:
669 if e.condition == u"item-not-found": 669 if e.condition == "item-not-found":
670 log.warning(_(u"Bundle missing for device {device_id}") 670 log.warning(_("Bundle missing for device {device_id}")
671 .format(device_id=device_id)) 671 .format(device_id=device_id))
672 missing.add(device_id) 672 missing.add(device_id)
673 continue 673 continue
674 else: 674 else:
675 log.warning(_(u"Can't get bundle for device {device_id}: {reason}") 675 log.warning(_("Can't get bundle for device {device_id}: {reason}")
676 .format(device_id=device_id, reason=e)) 676 .format(device_id=device_id, reason=e))
677 continue 677 continue
678 if not items: 678 if not items:
679 log.warning(_(u"no item found in node {node}, can't get public bundle " 679 log.warning(_("no item found in node {node}, can't get public bundle "
680 u"for device {device_id}").format(node=node, 680 "for device {device_id}").format(node=node,
681 device_id=device_id)) 681 device_id=device_id))
682 continue 682 continue
683 if len(items) > 1: 683 if len(items) > 1:
684 log.warning(_(u"more than one item found in {node}, " 684 log.warning(_("more than one item found in {node}, "
685 u"this is not expected").format(node=node)) 685 "this is not expected").format(node=node))
686 item = items[0] 686 item = items[0]
687 try: 687 try:
688 bundle_elt = next(item.elements(NS_OMEMO, 'bundle')) 688 bundle_elt = next(item.elements(NS_OMEMO, 'bundle'))
689 signedPreKeyPublic_elt = next(bundle_elt.elements( 689 signedPreKeyPublic_elt = next(bundle_elt.elements(
690 NS_OMEMO, 'signedPreKeyPublic')) 690 NS_OMEMO, 'signedPreKeyPublic'))
693 identityKey_elt = next(bundle_elt.elements( 693 identityKey_elt = next(bundle_elt.elements(
694 NS_OMEMO, 'identityKey')) 694 NS_OMEMO, 'identityKey'))
695 prekeys_elt = next(bundle_elt.elements( 695 prekeys_elt = next(bundle_elt.elements(
696 NS_OMEMO, 'prekeys')) 696 NS_OMEMO, 'prekeys'))
697 except StopIteration: 697 except StopIteration:
698 log.warning(_(u"invalid bundle for device {device_id}, ignoring").format( 698 log.warning(_("invalid bundle for device {device_id}, ignoring").format(
699 device_id=device_id)) 699 device_id=device_id))
700 continue 700 continue
701 701
702 try: 702 try:
703 spkPublic = base64.b64decode(unicode(signedPreKeyPublic_elt)) 703 spkPublic = base64.b64decode(str(signedPreKeyPublic_elt))
704 spkSignature = base64.b64decode( 704 spkSignature = base64.b64decode(
705 unicode(signedPreKeySignature_elt)) 705 str(signedPreKeySignature_elt))
706 706
707 ik = base64.b64decode(unicode(identityKey_elt)) 707 ik = base64.b64decode(str(identityKey_elt))
708 spk = { 708 spk = {
709 "key": spkPublic, 709 "key": spkPublic,
710 "id": int(signedPreKeyPublic_elt['signedPreKeyId']) 710 "id": int(signedPreKeyPublic_elt['signedPreKeyId'])
711 } 711 }
712 otpks = [] 712 otpks = []
713 for preKeyPublic_elt in prekeys_elt.elements(NS_OMEMO, 'preKeyPublic'): 713 for preKeyPublic_elt in prekeys_elt.elements(NS_OMEMO, 'preKeyPublic'):
714 preKeyPublic = base64.b64decode(unicode(preKeyPublic_elt)) 714 preKeyPublic = base64.b64decode(str(preKeyPublic_elt))
715 otpk = { 715 otpk = {
716 "key": preKeyPublic, 716 "key": preKeyPublic,
717 "id": int(preKeyPublic_elt['preKeyId']) 717 "id": int(preKeyPublic_elt['preKeyId'])
718 } 718 }
719 otpks.append(otpk) 719 otpks.append(otpk)
720 720
721 except Exception as e: 721 except Exception as e:
722 log.warning(_(u"error while decoding key for device {device_id}: {msg}") 722 log.warning(_("error while decoding key for device {device_id}: {msg}")
723 .format(device_id=device_id, msg=e)) 723 .format(device_id=device_id, msg=e))
724 continue 724 continue
725 725
726 bundles[device_id] = ExtendedPublicBundle.parse(omemo_backend, ik, spk, 726 bundles[device_id] = ExtendedPublicBundle.parse(omemo_backend, ik, spk,
727 spkSignature, otpks) 727 spkSignature, otpks)
728 728
729 defer.returnValue((bundles, missing)) 729 defer.returnValue((bundles, missing))
730 730
731 def setBundleEb(self, failure_): 731 def setBundleEb(self, failure_):
732 log.warning(_(u"Can't set bundle: {reason}").format(reason=failure_)) 732 log.warning(_("Can't set bundle: {reason}").format(reason=failure_))
733 733
734 def setBundle(self, client, bundle, device_id): 734 def setBundle(self, client, bundle, device_id):
735 """Set public bundle for this device. 735 """Set public bundle for this device.
736 736
737 @param bundle(ExtendedPublicBundle): bundle to publish 737 @param bundle(ExtendedPublicBundle): bundle to publish
738 """ 738 """
739 log.debug(_(u"updating bundle for {device_id}").format(device_id=device_id)) 739 log.debug(_("updating bundle for {device_id}").format(device_id=device_id))
740 bundle = bundle.serialize(omemo_backend) 740 bundle = bundle.serialize(omemo_backend)
741 bundle_elt = domish.Element((NS_OMEMO, 'bundle')) 741 bundle_elt = domish.Element((NS_OMEMO, 'bundle'))
742 signedPreKeyPublic_elt = bundle_elt.addElement( 742 signedPreKeyPublic_elt = bundle_elt.addElement(
743 "signedPreKeyPublic", 743 "signedPreKeyPublic",
744 content=b64enc(bundle["spk"]['key'])) 744 content=b64enc(bundle["spk"]['key']))
745 signedPreKeyPublic_elt['signedPreKeyId'] = unicode(bundle["spk"]['id']) 745 signedPreKeyPublic_elt['signedPreKeyId'] = str(bundle["spk"]['id'])
746 746
747 bundle_elt.addElement( 747 bundle_elt.addElement(
748 "signedPreKeySignature", 748 "signedPreKeySignature",
749 content=b64enc(bundle["spk_signature"])) 749 content=b64enc(bundle["spk_signature"]))
750 750
755 prekeys_elt = bundle_elt.addElement('prekeys') 755 prekeys_elt = bundle_elt.addElement('prekeys')
756 for otpk in bundle["otpks"]: 756 for otpk in bundle["otpks"]:
757 preKeyPublic_elt = prekeys_elt.addElement( 757 preKeyPublic_elt = prekeys_elt.addElement(
758 'preKeyPublic', 758 'preKeyPublic',
759 content=b64enc(otpk["key"])) 759 content=b64enc(otpk["key"]))
760 preKeyPublic_elt['preKeyId'] = unicode(otpk['id']) 760 preKeyPublic_elt['preKeyId'] = str(otpk['id'])
761 761
762 node = NS_OMEMO_BUNDLE.format(device_id=device_id) 762 node = NS_OMEMO_BUNDLE.format(device_id=device_id)
763 d = self._p.sendItem(client, None, node, bundle_elt, item_id=self._p.ID_SINGLETON) 763 d = self._p.sendItem(client, None, node, bundle_elt, item_id=self._p.ID_SINGLETON)
764 d.addErrback(self.setBundleEb) 764 d.addErrback(self.setBundleEb)
765 return d 765 return d
780 omemo_session.newDeviceList(entity, devices) 780 omemo_session.newDeviceList(entity, devices)
781 781
782 if entity == client.jid.userhostJID(): 782 if entity == client.jid.userhostJID():
783 own_device = client._xep_0384_device_id 783 own_device = client._xep_0384_device_id
784 if own_device not in devices: 784 if own_device not in devices:
785 log.warning(_(u"Our own device is missing from devices list, fixing it")) 785 log.warning(_("Our own device is missing from devices list, fixing it"))
786 devices.add(own_device) 786 devices.add(own_device)
787 yield self.setDevices(client, devices) 787 yield self.setDevices(client, devices)
788 788
789 ## triggers 789 ## triggers
790 790
807 untrusted = {} 807 untrusted = {}
808 missing_bundles = {} 808 missing_bundles = {}
809 cache = client._xep_0384_cache 809 cache = client._xep_0384_cache
810 for problem in problems: 810 for problem in problems:
811 if isinstance(problem, omemo_excpt.TrustException): 811 if isinstance(problem, omemo_excpt.TrustException):
812 untrusted[unicode(hash(problem))] = problem 812 untrusted[str(hash(problem))] = problem
813 elif isinstance(problem, omemo_excpt.MissingBundleException): 813 elif isinstance(problem, omemo_excpt.MissingBundleException):
814 pb_entity = jid.JID(problem.bare_jid) 814 pb_entity = jid.JID(problem.bare_jid)
815 entity_cache = cache.setdefault(pb_entity, {}) 815 entity_cache = cache.setdefault(pb_entity, {})
816 entity_bundles = bundles.setdefault(pb_entity, {}) 816 entity_bundles = bundles.setdefault(pb_entity, {})
817 if problem.device in entity_cache: 817 if problem.device in entity_cache:
833 else: 833 else:
834 raise problem 834 raise problem
835 else: 835 else:
836 raise problem 836 raise problem
837 837
838 for peer_jid, devices in missing_bundles.iteritems(): 838 for peer_jid, devices in missing_bundles.items():
839 devices_s = [unicode(d) for d in devices] 839 devices_s = [str(d) for d in devices]
840 log.warning( 840 log.warning(
841 _(u"Can't retrieve bundle for device(s) {devices} of entity {peer}, " 841 _("Can't retrieve bundle for device(s) {devices} of entity {peer}, "
842 u"the message will not be readable on this/those device(s)").format( 842 "the message will not be readable on this/those device(s)").format(
843 devices=u", ".join(devices_s), peer=peer_jid.full())) 843 devices=", ".join(devices_s), peer=peer_jid.full()))
844 client.feedback( 844 client.feedback(
845 entity, 845 entity,
846 D_(u"You're destinee {peer} has missing encryption data on some of " 846 D_("You're destinee {peer} has missing encryption data on some of "
847 u"his/her device(s) (bundle on device {devices}), the message won't " 847 "his/her device(s) (bundle on device {devices}), the message won't "
848 u"be readable on this/those device.").format( 848 "be readable on this/those device.").format(
849 peer=peer_jid.full(), devices=u", ".join(devices_s))) 849 peer=peer_jid.full(), devices=", ".join(devices_s)))
850 850
851 if untrusted: 851 if untrusted:
852 trust_data = {} 852 trust_data = {}
853 for trust_id, data in untrusted.iteritems(): 853 for trust_id, data in untrusted.items():
854 trust_data[trust_id] = { 854 trust_data[trust_id] = {
855 'jid': jid.JID(data.bare_jid), 855 'jid': jid.JID(data.bare_jid),
856 'device': data.device, 856 'device': data.device,
857 'ik': data.ik} 857 'ik': data.ik}
858 858
859 user_msg = D_(u"Not all destination devices are trusted, we can't encrypt " 859 user_msg = D_("Not all destination devices are trusted, we can't encrypt "
860 u"message in such a situation. Please indicate if you trust " 860 "message in such a situation. Please indicate if you trust "
861 u"those devices or not in the trust manager before we can " 861 "those devices or not in the trust manager before we can "
862 "send this message") 862 "send this message")
863 client.feedback(entity, user_msg) 863 client.feedback(entity, user_msg)
864 xmlui = yield self.getTrustUI(client, trust_data=trust_data, submit_id=u"") 864 xmlui = yield self.getTrustUI(client, trust_data=trust_data, submit_id="")
865 865
866 answer = yield xml_tools.deferXMLUI( 866 answer = yield xml_tools.deferXMLUI(
867 self.host, 867 self.host,
868 xmlui, 868 xmlui,
869 action_extra={ 869 action_extra={
870 u"meta_encryption_trust": NS_OMEMO, 870 "meta_encryption_trust": NS_OMEMO,
871 }, 871 },
872 profile=client.profile) 872 profile=client.profile)
873 yield self.trustUICb(answer, trust_data, expect_problems, client.profile) 873 yield self.trustUICb(answer, trust_data, expect_problems, client.profile)
874 874
875 @defer.inlineCallbacks 875 @defer.inlineCallbacks
879 bundles = {} 879 bundles = {}
880 loop_idx = 0 880 loop_idx = 0
881 try: 881 try:
882 while True: 882 while True:
883 if loop_idx > 10: 883 if loop_idx > 10:
884 msg = _(u"Too many iterations in encryption loop") 884 msg = _("Too many iterations in encryption loop")
885 log.error(msg) 885 log.error(msg)
886 raise exceptions.InternalError(msg) 886 raise exceptions.InternalError(msg)
887 # encryptMessage may fail, in case of e.g. trust issue or missing bundle 887 # encryptMessage may fail, in case of e.g. trust issue or missing bundle
888 try: 888 try:
889 encrypted = yield omemo_session.encryptMessage( 889 encrypted = yield omemo_session.encryptMessage(
901 problems=e.problems) 901 problems=e.problems)
902 loop_idx += 1 902 loop_idx += 1
903 else: 903 else:
904 break 904 break
905 except Exception as e: 905 except Exception as e:
906 msg = _(u"Can't encrypt message for {entity}: {reason}".format( 906 msg = _("Can't encrypt message for {entity}: {reason}".format(
907 entity=entity_bare_jid.full(), reason=str(e).decode('utf-8', 'replace'))) 907 entity=entity_bare_jid.full(), reason=str(e).decode('utf-8', 'replace')))
908 log.warning(msg) 908 log.warning(msg)
909 extra = {C.MESS_EXTRA_INFO: C.EXTRA_INFO_ENCR_ERR} 909 extra = {C.MESS_EXTRA_INFO: C.EXTRA_INFO_ENCR_ERR}
910 client.feedback(entity_bare_jid, msg, extra) 910 client.feedback(entity_bare_jid, msg, extra)
911 raise e 911 raise e
915 @defer.inlineCallbacks 915 @defer.inlineCallbacks
916 def _messageReceivedTrigger(self, client, message_elt, post_treat): 916 def _messageReceivedTrigger(self, client, message_elt, post_treat):
917 if message_elt.getAttribute("type") == C.MESS_TYPE_GROUPCHAT: 917 if message_elt.getAttribute("type") == C.MESS_TYPE_GROUPCHAT:
918 defer.returnValue(True) 918 defer.returnValue(True)
919 try: 919 try:
920 encrypted_elt = next(message_elt.elements(NS_OMEMO, u"encrypted")) 920 encrypted_elt = next(message_elt.elements(NS_OMEMO, "encrypted"))
921 except StopIteration: 921 except StopIteration:
922 # no OMEMO message here 922 # no OMEMO message here
923 defer.returnValue(True) 923 defer.returnValue(True)
924 924
925 # we have an encrypted message let's decrypt it 925 # we have an encrypted message let's decrypt it
936 yield client._xep_0384_ready 936 yield client._xep_0384_ready
937 omemo_session = client._xep_0384_session 937 omemo_session = client._xep_0384_session
938 938
939 device_id = client._xep_0384_device_id 939 device_id = client._xep_0384_device_id
940 try: 940 try:
941 header_elt = next(encrypted_elt.elements(NS_OMEMO, u'header')) 941 header_elt = next(encrypted_elt.elements(NS_OMEMO, 'header'))
942 iv_elt = next(header_elt.elements(NS_OMEMO, u'iv')) 942 iv_elt = next(header_elt.elements(NS_OMEMO, 'iv'))
943 except StopIteration: 943 except StopIteration:
944 log.warning(_(u"Invalid OMEMO encrypted stanza, ignoring: {xml}") 944 log.warning(_("Invalid OMEMO encrypted stanza, ignoring: {xml}")
945 .format(xml=message_elt.toXml())) 945 .format(xml=message_elt.toXml()))
946 defer.returnValue(False) 946 defer.returnValue(False)
947 try: 947 try:
948 s_device_id = header_elt['sid'] 948 s_device_id = header_elt['sid']
949 except KeyError: 949 except KeyError:
950 log.warning(_(u"Invalid OMEMO encrypted stanza, missing sender device ID, " 950 log.warning(_("Invalid OMEMO encrypted stanza, missing sender device ID, "
951 u"ignoring: {xml}") 951 "ignoring: {xml}")
952 .format(xml=message_elt.toXml())) 952 .format(xml=message_elt.toXml()))
953 defer.returnValue(False) 953 defer.returnValue(False)
954 try: 954 try:
955 key_elt = next((e for e in header_elt.elements(NS_OMEMO, u'key') 955 key_elt = next((e for e in header_elt.elements(NS_OMEMO, 'key')
956 if int(e[u'rid']) == device_id)) 956 if int(e['rid']) == device_id))
957 except StopIteration: 957 except StopIteration:
958 log.warning(_(u"This OMEMO encrypted stanza has not been encrypted " 958 log.warning(_("This OMEMO encrypted stanza has not been encrypted "
959 u"for our device (device_id: {device_id}, fingerprint: " 959 "for our device (device_id: {device_id}, fingerprint: "
960 u"{fingerprint}): {xml}").format( 960 "{fingerprint}): {xml}").format(
961 device_id=device_id, 961 device_id=device_id,
962 fingerprint=omemo_session.public_bundle.ik.encode('hex'), 962 fingerprint=omemo_session.public_bundle.ik.encode('hex'),
963 xml=encrypted_elt.toXml())) 963 xml=encrypted_elt.toXml()))
964 user_msg = (D_(u"An OMEMO message from {sender} has not been encrypted for " 964 user_msg = (D_("An OMEMO message from {sender} has not been encrypted for "
965 u"our device, we can't decrypt it").format( 965 "our device, we can't decrypt it").format(
966 sender=from_jid.full())) 966 sender=from_jid.full()))
967 extra = {C.MESS_EXTRA_INFO: C.EXTRA_INFO_DECR_ERR} 967 extra = {C.MESS_EXTRA_INFO: C.EXTRA_INFO_DECR_ERR}
968 client.feedback(feedback_jid, user_msg, extra) 968 client.feedback(feedback_jid, user_msg, extra)
969 defer.returnValue(False) 969 defer.returnValue(False)
970 except ValueError as e: 970 except ValueError as e:
971 log.warning(_(u"Invalid recipient ID: {msg}".format(msg=e))) 971 log.warning(_("Invalid recipient ID: {msg}".format(msg=e)))
972 defer.returnValue(False) 972 defer.returnValue(False)
973 is_pre_key = C.bool(key_elt.getAttribute('prekey', 'false')) 973 is_pre_key = C.bool(key_elt.getAttribute('prekey', 'false'))
974 payload_elt = next(encrypted_elt.elements(NS_OMEMO, u'payload'), None) 974 payload_elt = next(encrypted_elt.elements(NS_OMEMO, 'payload'), None)
975 additional_information = { 975 additional_information = {
976 "from_storage": bool(message_elt.delay) 976 "from_storage": bool(message_elt.delay)
977 } 977 }
978 978
979 kwargs = { 979 kwargs = {
994 kwargs['allow_untrusted'] = True 994 kwargs['allow_untrusted'] = True
995 plaintext = yield omemo_session.decryptMessage(**kwargs) 995 plaintext = yield omemo_session.decryptMessage(**kwargs)
996 else: 996 else:
997 post_treat.addCallback(client.encryption.markAsTrusted) 997 post_treat.addCallback(client.encryption.markAsTrusted)
998 except Exception as e: 998 except Exception as e:
999 log.warning(_(u"Can't decrypt message: {reason}\n{xml}").format( 999 log.warning(_("Can't decrypt message: {reason}\n{xml}").format(
1000 reason=e, xml=message_elt.toXml())) 1000 reason=e, xml=message_elt.toXml()))
1001 user_msg = (D_(u"An OMEMO message from {sender} can't be decrypted: {reason}") 1001 user_msg = (D_("An OMEMO message from {sender} can't be decrypted: {reason}")
1002 .format(sender=from_jid.full(), reason=e)) 1002 .format(sender=from_jid.full(), reason=e))
1003 extra = {C.MESS_EXTRA_INFO: C.EXTRA_INFO_DECR_ERR} 1003 extra = {C.MESS_EXTRA_INFO: C.EXTRA_INFO_DECR_ERR}
1004 client.feedback(feedback_jid, user_msg, extra) 1004 client.feedback(feedback_jid, user_msg, extra)
1005 defer.returnValue(False) 1005 defer.returnValue(False)
1006 finally: 1006 finally:
1010 # updating the bundle 1010 # updating the bundle
1011 self.setBundle(client, omemo_session.public_bundle, device_id) 1011 self.setBundle(client, omemo_session.public_bundle, device_id)
1012 1012
1013 message_elt.children.remove(encrypted_elt) 1013 message_elt.children.remove(encrypted_elt)
1014 if plaintext: 1014 if plaintext:
1015 message_elt.addElement("body", content=plaintext.decode('utf-8')) 1015 message_elt.addElement("body", content=plaintext)
1016 post_treat.addCallback(client.encryption.markAsEncrypted) 1016 post_treat.addCallback(client.encryption.markAsEncrypted)
1017 defer.returnValue(True) 1017 defer.returnValue(True)
1018 1018
1019 @defer.inlineCallbacks 1019 @defer.inlineCallbacks
1020 def _sendMessageDataTrigger(self, client, mess_data): 1020 def _sendMessageDataTrigger(self, client, mess_data):
1021 encryption = mess_data.get(C.MESS_KEY_ENCRYPTION) 1021 encryption = mess_data.get(C.MESS_KEY_ENCRYPTION)
1022 if encryption is None or encryption['plugin'].namespace != NS_OMEMO: 1022 if encryption is None or encryption['plugin'].namespace != NS_OMEMO:
1023 return 1023 return
1024 message_elt = mess_data["xml"] 1024 message_elt = mess_data["xml"]
1025 to_jid = mess_data["to"].userhostJID() 1025 to_jid = mess_data["to"].userhostJID()
1026 log.debug(u"encrypting message") 1026 log.debug("encrypting message")
1027 body = None 1027 body = None
1028 for child in list(message_elt.children): 1028 for child in list(message_elt.children):
1029 if child.name == "body": 1029 if child.name == "body":
1030 # we remove all unencrypted body, 1030 # we remove all unencrypted body,
1031 # and will only encrypt the first one 1031 # and will only encrypt the first one
1035 elif child.name == "html": 1035 elif child.name == "html":
1036 # we don't want any XHTML-IM element 1036 # we don't want any XHTML-IM element
1037 message_elt.children.remove(child) 1037 message_elt.children.remove(child)
1038 1038
1039 if body is None: 1039 if body is None:
1040 log.warning(u"No message found") 1040 log.warning("No message found")
1041 return 1041 return
1042 1042
1043 encryption_data = yield self.encryptMessage(client, to_jid, unicode(body)) 1043 encryption_data = yield self.encryptMessage(client, to_jid, str(body))
1044 1044
1045 encrypted_elt = message_elt.addElement((NS_OMEMO, 'encrypted')) 1045 encrypted_elt = message_elt.addElement((NS_OMEMO, 'encrypted'))
1046 header_elt = encrypted_elt.addElement('header') 1046 header_elt = encrypted_elt.addElement('header')
1047 header_elt['sid'] = unicode(encryption_data['sid']) 1047 header_elt['sid'] = str(encryption_data['sid'])
1048 bare_jid_s = to_jid.userhost() 1048 bare_jid_s = to_jid.userhost()
1049 1049
1050 for rid, data in encryption_data['keys'][bare_jid_s].iteritems(): 1050 for rid, data in encryption_data['keys'][bare_jid_s].items():
1051 key_elt = header_elt.addElement( 1051 key_elt = header_elt.addElement(
1052 'key', 1052 'key',
1053 content=b64enc(data['data'])) 1053 content=b64enc(data['data']))
1054 key_elt['rid'] = unicode(rid) 1054 key_elt['rid'] = str(rid)
1055 if data['pre_key']: 1055 if data['pre_key']:
1056 key_elt['prekey'] = 'true' 1056 key_elt['prekey'] = 'true'
1057 1057
1058 header_elt.addElement( 1058 header_elt.addElement(
1059 'iv', 1059 'iv',