Mercurial > libervia-backend
comparison src/plugins/plugin_sec_otr.py @ 2125:ca82c97db195
plugin sec OTR: fixed OTR:
- fixed bridge calls
- use deferred translation
- unicode string fixes
- various other improvments
author | Goffi <goffi@goffi.org> |
---|---|
date | Thu, 26 Jan 2017 20:24:58 +0100 |
parents | 200cd707a46d |
children | aa94f33fd2ad |
comparison
equal
deleted
inserted
replaced
2124:cf63e4209643 | 2125:ca82c97db195 |
---|---|
35 import time | 35 import time |
36 import uuid | 36 import uuid |
37 | 37 |
38 NS_OTR = "otr_plugin" | 38 NS_OTR = "otr_plugin" |
39 PRIVATE_KEY = "PRIVATE KEY" | 39 PRIVATE_KEY = "PRIVATE KEY" |
40 MAIN_MENU = D_('OTR') | 40 OTR_MENU = D_(u'OTR') |
41 AUTH_TXT = D_("To authenticate your correspondent, you need to give your below fingerprint *BY AN EXTERNAL CANAL* (i.e. not in this chat), and check that the one he gives you is the same as below. If there is a mismatch, there can be a spy between you!") | 41 AUTH_TXT = D_(u"To authenticate your correspondent, you need to give your below fingerprint *BY AN EXTERNAL CANAL* (i.e. not in this chat), and check that the one he gives you is the same as below. If there is a mismatch, there can be a spy between you!") |
42 DROP_TXT = D_("You private key is used to encrypt messages for your correspondent, nobody except you must know it, if you are in doubt, you should drop it!\n\nAre you sure you want to drop your private key?") | 42 DROP_TXT = D_(u"You private key is used to encrypt messages for your correspondent, nobody except you must know it, if you are in doubt, you should drop it!\n\nAre you sure you want to drop your private key?") |
43 NO_LOG = D_(u"/!\\Your history is not logged anymore, and most of advanced features are disabled !") # FIXME: not used at the moment | |
43 | 44 |
44 DEFAULT_POLICY_FLAGS = { | 45 DEFAULT_POLICY_FLAGS = { |
45 'ALLOW_V1':False, | 46 'ALLOW_V1':False, |
46 'ALLOW_V2':True, | 47 'ALLOW_V2':True, |
47 'REQUIRE_ENCRYPTION':True, | 48 'REQUIRE_ENCRYPTION':True, |
48 } | 49 } |
50 | |
49 | 51 |
50 PLUGIN_INFO = { | 52 PLUGIN_INFO = { |
51 "name": "OTR", | 53 "name": "OTR", |
52 "import_name": "OTR", | 54 "import_name": "OTR", |
53 "type": "SEC", | 55 "type": "SEC", |
54 "protocols": [], | 56 "protocols": [], |
55 "dependencies": [], | 57 "dependencies": [], |
56 "main": "OTR", | 58 "main": "OTR", |
57 "handler": "no", | 59 "handler": "no", |
58 "description": _("""Implementation of OTR""") | 60 "description": _(u"""Implementation of OTR""") |
59 } | 61 } |
60 | 62 |
61 | 63 |
62 class Context(potr.context.Context): | 64 class Context(potr.context.Context): |
63 def __init__(self, host, account, other_jid): | 65 def __init__(self, host, account, other_jid): |
101 except TypeError: | 103 except TypeError: |
102 trusted = False | 104 trusted = False |
103 trusted_str = _(u"trusted") if trusted else _(u"untrusted") | 105 trusted_str = _(u"trusted") if trusted else _(u"untrusted") |
104 | 106 |
105 if old_state == potr.context.STATE_ENCRYPTED: | 107 if old_state == potr.context.STATE_ENCRYPTED: |
106 feedback = _(u"%(trusted)s OTR conversation with %(other_jid)s REFRESHED") % {'trusted': trusted_str, 'other_jid': self.peer.full()} | 108 feedback = D_(u"{trusted} OTR conversation with {other_jid} REFRESHED").format( |
109 trusted = trusted_str, | |
110 other_jid = self.peer.full()) | |
107 else: | 111 else: |
108 feedback = _(u"%(trusted)s Encrypted OTR conversation started with %(other_jid)s\n/!\\ Your history is not logged anymore, and most of advanced features are disabled !") % {'trusted': trusted_str, 'other_jid': self.peer.full()} | 112 feedback = D_(u"{trusted} Encrypted OTR conversation started with {other_jid}\n{no_log}").format( |
113 trusted = trusted_str, | |
114 other_jid = self.peer.full(), | |
115 no_log = NO_LOG) | |
109 elif state == potr.context.STATE_FINISHED: | 116 elif state == potr.context.STATE_FINISHED: |
110 feedback = _(u"OTR conversation with %(other_jid)s is FINISHED") % {'other_jid': self.peer.full()} | 117 feedback = D_(u"OTR conversation with {other_jid} is FINISHED").format(other_jid = self.peer.full()) |
111 else: | 118 else: |
112 log.error(_(u"Unknown OTR state")) | 119 log.error(D_(u"Unknown OTR state")) |
113 return | 120 return |
114 | 121 |
115 client = self.user.client | 122 client = self.user.client |
116 self.host.bridge.messageNew(client.jid.full(), | 123 self.host.bridge.messageNew(uid=unicode(uuid.uuid4()), |
117 feedback, | 124 timestamp=time.time(), |
125 from_jid=client.jid.full(), | |
126 to_jid=self.peer.full(), | |
127 message={u'': feedback}, | |
128 subject={}, | |
118 mess_type=C.MESS_TYPE_INFO, | 129 mess_type=C.MESS_TYPE_INFO, |
119 to_jid=self.peer.full(), | |
120 extra={}, | 130 extra={}, |
121 profile=client.profile) | 131 profile=client.profile) |
122 # TODO: send signal to frontends | 132 # TODO: send signal to frontends |
123 | 133 |
124 def disconnect(self): | 134 def disconnect(self): |
148 return self.privkey | 158 return self.privkey |
149 | 159 |
150 def savePrivkey(self): | 160 def savePrivkey(self): |
151 log.debug(u"savePrivkey") | 161 log.debug(u"savePrivkey") |
152 if self.privkey is None: | 162 if self.privkey is None: |
153 raise exceptions.InternalError(_("Save is called but privkey is None !")) | 163 raise exceptions.InternalError(_(u"Save is called but privkey is None !")) |
154 priv_key = self.privkey.serializePrivateKey().encode('hex') | 164 priv_key = self.privkey.serializePrivateKey().encode('hex') |
155 d = self.host.memory.encryptValue(priv_key, self.client.profile) | 165 d = self.host.memory.encryptValue(priv_key, self.client.profile) |
156 def save_encrypted_key(encrypted_priv_key): | 166 def save_encrypted_key(encrypted_priv_key): |
157 self.client.otr_data[PRIVATE_KEY] = encrypted_priv_key | 167 self.client.otr_data[PRIVATE_KEY] = encrypted_priv_key |
158 d.addCallback(save_encrypted_key) | 168 d.addCallback(save_encrypted_key) |
208 self.context_managers = {} | 218 self.context_managers = {} |
209 self.skipped_profiles = set() | 219 self.skipped_profiles = set() |
210 host.trigger.add("MessageReceived", self.MessageReceivedTrigger, priority=100000) | 220 host.trigger.add("MessageReceived", self.MessageReceivedTrigger, priority=100000) |
211 host.trigger.add("messageSend", self.messageSendTrigger, priority=100000) | 221 host.trigger.add("messageSend", self.messageSendTrigger, priority=100000) |
212 host.bridge.addMethod("skipOTR", ".plugin", in_sign='s', out_sign='', method=self._skipOTR) # FIXME: must be removed, must be done on per-message basis | 222 host.bridge.addMethod("skipOTR", ".plugin", in_sign='s', out_sign='', method=self._skipOTR) # FIXME: must be removed, must be done on per-message basis |
213 host.importMenu((MAIN_MENU, D_("Start/Refresh")), self._startRefresh, security_limit=0, help_string=D_("Start or refresh an OTR session"), type_=C.MENU_SINGLE) | 223 host.importMenu((OTR_MENU, D_(u"Start/Refresh")), self._otrStartRefresh, security_limit=0, help_string=D_(u"Start or refresh an OTR session"), type_=C.MENU_SINGLE) |
214 host.importMenu((MAIN_MENU, D_("End session")), self._endSession, security_limit=0, help_string=D_("Finish an OTR session"), type_=C.MENU_SINGLE) | 224 host.importMenu((OTR_MENU, D_(u"End session")), self._otrSessionEnd, security_limit=0, help_string=D_(u"Finish an OTR session"), type_=C.MENU_SINGLE) |
215 host.importMenu((MAIN_MENU, D_("Authenticate")), self._authenticate, security_limit=0, help_string=D_("Authenticate user/see your fingerprint"), type_=C.MENU_SINGLE) | 225 host.importMenu((OTR_MENU, D_(u"Authenticate")), self._otrAuthenticate, security_limit=0, help_string=D_(u"Authenticate user/see your fingerprint"), type_=C.MENU_SINGLE) |
216 host.importMenu((MAIN_MENU, D_("Drop private key")), self._dropPrivKey, security_limit=0, type_=C.MENU_SINGLE) | 226 host.importMenu((OTR_MENU, D_(u"Drop private key")), self._dropPrivKey, security_limit=0, type_=C.MENU_SINGLE) |
217 host.trigger.add("presenceReceived", self._presenceReceivedTrigger) | 227 host.trigger.add("presenceReceived", self._presenceReceivedTrigger) |
218 | 228 |
219 def _fixPotr(self): | 229 def _fixPotr(self): |
220 # FIXME: potr fix for bad unicode handling | 230 # FIXME: potr fix for bad unicode handling |
221 # this method monkeypatch it, must be removed when potr | 231 # this method monkeypatch it, must be removed when potr |
268 try: | 278 try: |
269 self.skipped_profiles.remove(profile) | 279 self.skipped_profiles.remove(profile) |
270 except KeyError: | 280 except KeyError: |
271 pass | 281 pass |
272 | 282 |
273 def _startRefresh(self, menu_data, profile): | 283 def _otrStartRefresh(self, menu_data, profile): |
274 """Start or refresh an OTR session | 284 """Start or refresh an OTR session |
275 | 285 |
276 @param menu_data: %(menu_data)s | 286 @param menu_data: %(menu_data)s |
277 @param profile: %(doc_profile)s | 287 @param profile: %(doc_profile)s |
278 """ | 288 """ |
279 client = self.host.getClient(profile) | 289 client = self.host.getClient(profile) |
280 try: | 290 try: |
281 to_jid = jid.JID(menu_data['jid']) | 291 to_jid = jid.JID(menu_data['jid']) |
282 if not to_jid.resource: | 292 except KeyError: |
283 to_jid.resource = self.host.memory.getMainResource(client, to_jid) # FIXME: temporary and unsecure, must be changed when frontends are refactored | 293 log.error(_(u"jid key is not present !")) |
284 except KeyError: | |
285 log.error(_("jid key is not present !")) | |
286 return defer.fail(exceptions.DataError) | 294 return defer.fail(exceptions.DataError) |
287 otrctx = self.context_managers[profile].getContextForUser(to_jid) | 295 self.startRefresh(client, to_jid) |
288 query = otrctx.messageSend(0, '?OTRv?') | 296 return {} |
297 | |
298 def startRefresh(self, client, to_jid): | |
299 """Start or refresh an OTR session | |
300 | |
301 @param to_jid(jid.JID): jid to start encrypted session with | |
302 """ | |
303 if not to_jid.resource: | |
304 to_jid.resource = self.host.memory.getMainResource(client, to_jid) # FIXME: temporary and unsecure, must be changed when frontends are refactored | |
305 otrctx = self.context_managers[client.profile].getContextForUser(to_jid) | |
306 query = otrctx.sendMessage(0, '?OTRv?') | |
289 otrctx.inject(query) | 307 otrctx.inject(query) |
290 return {} | 308 |
291 | 309 def _otrSessionEnd(self, menu_data, profile): |
292 def _endSession(self, menu_data, profile): | |
293 """End an OTR session | 310 """End an OTR session |
294 | 311 |
295 @param menu_data: %(menu_data)s | 312 @param menu_data: %(menu_data)s |
296 @param profile: %(doc_profile)s | 313 @param profile: %(doc_profile)s |
297 """ | 314 """ |
298 client = self.host.getClient(profile) | 315 client = self.host.getClient(profile) |
299 try: | 316 try: |
300 to_jid = jid.JID(menu_data['jid']) | 317 to_jid = jid.JID(menu_data['jid']) |
301 if not to_jid.resource: | 318 except KeyError: |
302 to_jid.resource = self.host.memory.getMainResource(client, to_jid) # FIXME: temporary and unsecure, must be changed when frontends are refactored | 319 log.error(_(u"jid key is not present !")) |
303 except KeyError: | |
304 log.error(_("jid key is not present !")) | |
305 return defer.fail(exceptions.DataError) | 320 return defer.fail(exceptions.DataError) |
306 otrctx = self.context_managers[profile].getContextForUser(to_jid) | 321 self.endSession(client, to_jid) |
322 return {} | |
323 | |
324 def endSession(self, client, to_jid): | |
325 """End an OTR session""" | |
326 if not to_jid.resource: | |
327 to_jid.resource = self.host.memory.getMainResource(client, to_jid) # FIXME: temporary and unsecure, must be changed when frontends are refactored | |
328 otrctx = self.context_managers[client.profile].getContextForUser(to_jid) | |
307 otrctx.disconnect() | 329 otrctx.disconnect() |
308 return {} | 330 return {} |
309 | 331 |
310 def _authenticate(self, menu_data, profile): | 332 def _otrAuthenticate(self, menu_data, profile): |
311 """Authenticate other user and see our own fingerprint | 333 """End an OTR session |
312 | 334 |
313 @param menu_data: %(menu_data)s | 335 @param menu_data: %(menu_data)s |
314 @param profile: %(doc_profile)s | 336 @param profile: %(doc_profile)s |
315 """ | 337 """ |
316 client = self.host.getClient(profile) | 338 client = self.host.getClient(profile) |
317 try: | 339 try: |
318 to_jid = jid.JID(menu_data['jid']) | 340 to_jid = jid.JID(menu_data['jid']) |
319 if not to_jid.resource: | 341 except KeyError: |
320 to_jid.resource = self.host.memory.getMainResource(client, to_jid) # FIXME: temporary and unsecure, must be changed when frontends are refactored | 342 log.error(_(u"jid key is not present !")) |
321 except KeyError: | |
322 log.error(_("jid key is not present !")) | |
323 return defer.fail(exceptions.DataError) | 343 return defer.fail(exceptions.DataError) |
324 ctxMng = self.context_managers[profile] | 344 return self.authenticate(client, to_jid) |
345 | |
346 def authenticate(self, client, to_jid): | |
347 """Authenticate other user and see our own fingerprint""" | |
348 if not to_jid.resource: | |
349 to_jid.resource = self.host.memory.getMainResource(client, to_jid) # FIXME: temporary and unsecure, must be changed when frontends are refactored | |
350 ctxMng = self.context_managers[client.profile] | |
325 otrctx = ctxMng.getContextForUser(to_jid) | 351 otrctx = ctxMng.getContextForUser(to_jid) |
326 priv_key = ctxMng.account.privkey | 352 priv_key = ctxMng.account.privkey |
327 | 353 |
328 if priv_key is None: | 354 if priv_key is None: |
329 # we have no private key yet | 355 # we have no private key yet |
330 dialog = xml_tools.XMLUI(C.XMLUI_DIALOG, | 356 dialog = xml_tools.XMLUI(C.XMLUI_DIALOG, |
331 dialog_opt = {C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_MESSAGE, | 357 dialog_opt = {C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_MESSAGE, |
332 C.XMLUI_DATA_MESS: _("You have no private key yet, start an OTR conversation to have one"), | 358 C.XMLUI_DATA_MESS: _(u"You have no private key yet, start an OTR conversation to have one"), |
333 C.XMLUI_DATA_LVL: C.XMLUI_DATA_LVL_WARNING | 359 C.XMLUI_DATA_LVL: C.XMLUI_DATA_LVL_WARNING |
334 }, | 360 }, |
335 title = _("No private key"), | 361 title = _(u"No private key"), |
336 ) | 362 ) |
337 return {'xmlui': dialog.toXml()} | 363 return {'xmlui': dialog.toXml()} |
338 | 364 |
339 other_fingerprint = otrctx.getCurrentKey() | 365 other_fingerprint = otrctx.getCurrentKey() |
340 | 366 |
341 if other_fingerprint is None: | 367 if other_fingerprint is None: |
342 # we have a private key, but not the fingerprint of our correspondent | 368 # we have a private key, but not the fingerprint of our correspondent |
343 dialog = xml_tools.XMLUI(C.XMLUI_DIALOG, | 369 dialog = xml_tools.XMLUI(C.XMLUI_DIALOG, |
344 dialog_opt = {C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_MESSAGE, | 370 dialog_opt = {C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_MESSAGE, |
345 C.XMLUI_DATA_MESS: _("Your fingerprint is:\n{fingerprint}\n\nStart an OTR conversation to have your correspondent one.").format(fingerprint=priv_key), | 371 C.XMLUI_DATA_MESS: _(u"Your fingerprint is:\n{fingerprint}\n\nStart an OTR conversation to have your correspondent one.").format(fingerprint=priv_key), |
346 C.XMLUI_DATA_LVL: C.XMLUI_DATA_LVL_INFO | 372 C.XMLUI_DATA_LVL: C.XMLUI_DATA_LVL_INFO |
347 }, | 373 }, |
348 title = _("Fingerprint"), | 374 title = _(u"Fingerprint"), |
349 ) | 375 ) |
350 return {'xmlui': dialog.toXml()} | 376 return {'xmlui': dialog.toXml()} |
351 | 377 |
352 def setTrust(raw_data, profile): | 378 def setTrust(raw_data, profile): |
353 # This method is called when authentication form is submited | 379 # This method is called when authentication form is submited |
354 data = xml_tools.XMLUIResult2DataFormResult(raw_data) | 380 data = xml_tools.XMLUIResult2DataFormResult(raw_data) |
355 if data['match'] == 'yes': | 381 if data['match'] == 'yes': |
356 otrctx.setCurrentTrust('verified') | 382 otrctx.setCurrentTrust('verified') |
357 note_msg = _("Your correspondent {correspondent} is now TRUSTED") | 383 note_msg = _(u"Your correspondent {correspondent} is now TRUSTED") |
358 else: | 384 else: |
359 otrctx.setCurrentTrust('') | 385 otrctx.setCurrentTrust('') |
360 note_msg = _("Your correspondent {correspondent} is now UNTRUSTED") | 386 note_msg = _(u"Your correspondent {correspondent} is now UNTRUSTED") |
361 note = xml_tools.XMLUI(C.XMLUI_DIALOG, dialog_opt = { | 387 note = xml_tools.XMLUI(C.XMLUI_DIALOG, dialog_opt = { |
362 C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_NOTE, | 388 C.XMLUI_DATA_TYPE: C.XMLUI_DIALOG_NOTE, |
363 C.XMLUI_DATA_MESS: note_msg.format(correspondent=otrctx.peer)} | 389 C.XMLUI_DATA_MESS: note_msg.format(correspondent=otrctx.peer)} |
364 ) | 390 ) |
365 return {'xmlui': note.toXml()} | 391 return {'xmlui': note.toXml()} |
368 trusted = bool(otrctx.getCurrentTrust()) | 394 trusted = bool(otrctx.getCurrentTrust()) |
369 | 395 |
370 xmlui = xml_tools.XMLUI(C.XMLUI_FORM, title=_('Authentication (%s)') % to_jid.full(), submit_id=submit_id) | 396 xmlui = xml_tools.XMLUI(C.XMLUI_FORM, title=_('Authentication (%s)') % to_jid.full(), submit_id=submit_id) |
371 xmlui.addText(_(AUTH_TXT)) | 397 xmlui.addText(_(AUTH_TXT)) |
372 xmlui.addDivider() | 398 xmlui.addDivider() |
373 xmlui.addText(_("Your own fingerprint is:\n{fingerprint}").format(fingerprint=priv_key)) | 399 xmlui.addText(D_(u"Your own fingerprint is:\n{fingerprint}").format(fingerprint=priv_key)) |
374 xmlui.addText(_("Your correspondent fingerprint should be:\n{fingerprint}").format(fingerprint=other_fingerprint)) | 400 xmlui.addText(D_(u"Your correspondent fingerprint should be:\n{fingerprint}").format(fingerprint=other_fingerprint)) |
375 xmlui.addDivider('blank') | 401 xmlui.addDivider('blank') |
376 xmlui.changeContainer('pairs') | 402 xmlui.changeContainer('pairs') |
377 xmlui.addLabel(_('Is your correspondent fingerprint the same as here ?')) | 403 xmlui.addLabel(D_(u'Is your correspondent fingerprint the same as here ?')) |
378 xmlui.addList("match", [('yes', _('yes')),('no', _('no'))], ['yes' if trusted else 'no']) | 404 xmlui.addList("match", [('yes', _('yes')),('no', _('no'))], ['yes' if trusted else 'no']) |
379 return {'xmlui': xmlui.toXml()} | 405 return {'xmlui': xmlui.toXml()} |
380 | 406 |
381 def _dropPrivKey(self, menu_data, profile): | 407 def _dropPrivKey(self, menu_data, profile): |
382 """Drop our private Key | 408 """Drop our private Key |
388 try: | 414 try: |
389 to_jid = jid.JID(menu_data['jid']) | 415 to_jid = jid.JID(menu_data['jid']) |
390 if not to_jid.resource: | 416 if not to_jid.resource: |
391 to_jid.resource = self.host.memory.getMainResource(client, to_jid) # FIXME: temporary and unsecure, must be changed when frontends are refactored | 417 to_jid.resource = self.host.memory.getMainResource(client, to_jid) # FIXME: temporary and unsecure, must be changed when frontends are refactored |
392 except KeyError: | 418 except KeyError: |
393 log.error(_("jid key is not present !")) | 419 log.error(_(u"jid key is not present !")) |
394 return defer.fail(exceptions.DataError) | 420 return defer.fail(exceptions.DataError) |
395 | 421 |
396 ctxMng = self.context_managers[profile] | 422 ctxMng = self.context_managers[profile] |
397 if ctxMng.account.privkey is None: | 423 if ctxMng.account.privkey is None: |
398 return {'xmlui': xml_tools.note(_("You don't have a private key yet !")).toXml()} | 424 return {'xmlui': xml_tools.note(_(u"You don't have a private key yet !")).toXml()} |
399 | 425 |
400 def dropKey(data, profile): | 426 def dropKey(data, profile): |
401 if C.bool(data['answer']): | 427 if C.bool(data['answer']): |
402 # we end all sessions | 428 # we end all sessions |
403 for context in ctxMng.contexts.values(): | 429 for context in ctxMng.contexts.values(): |
404 context.disconnect() | 430 context.disconnect() |
405 ctxMng.account.privkey = None | 431 ctxMng.account.privkey = None |
406 ctxMng.account.getPrivkey() # as account.privkey is None, getPrivkey will generate a new key, and save it | 432 ctxMng.account.getPrivkey() # as account.privkey is None, getPrivkey will generate a new key, and save it |
407 return {'xmlui': xml_tools.note(_("Your private key has been dropped")).toXml()} | 433 return {'xmlui': xml_tools.note(_(u"Your private key has been dropped")).toXml()} |
408 return {} | 434 return {} |
409 | 435 |
410 submit_id = self.host.registerCallback(dropKey, with_data=True, one_shot=True) | 436 submit_id = self.host.registerCallback(dropKey, with_data=True, one_shot=True) |
411 | 437 |
412 confirm = xml_tools.XMLUI(C.XMLUI_DIALOG, title=_('Confirm private key drop'), dialog_opt = {'type': C.XMLUI_DIALOG_CONFIRM, 'message': _(DROP_TXT)}, submit_id = submit_id) | 438 confirm = xml_tools.XMLUI(C.XMLUI_DIALOG, title=_('Confirm private key drop'), dialog_opt = {'type': C.XMLUI_DIALOG_CONFIRM, 'message': _(DROP_TXT)}, submit_id = submit_id) |
423 res = otrctx.receiveMessage(message.encode('utf-8')) | 449 res = otrctx.receiveMessage(message.encode('utf-8')) |
424 except potr.context.UnencryptedMessage: | 450 except potr.context.UnencryptedMessage: |
425 if otrctx.state == potr.context.STATE_ENCRYPTED: | 451 if otrctx.state == potr.context.STATE_ENCRYPTED: |
426 log.warning(u"Received unencrypted message in an encrypted context (from %(jid)s)" % {'jid': from_jid.full()}) | 452 log.warning(u"Received unencrypted message in an encrypted context (from %(jid)s)" % {'jid': from_jid.full()}) |
427 client = self.host.getClient(profile) | 453 client = self.host.getClient(profile) |
428 self.host.bridge.messageNew(from_jid.full(), | 454 |
429 _(u"WARNING: received unencrypted data in a supposedly encrypted context"), | 455 feedback=D_(u"WARNING: received unencrypted data in a supposedly encrypted context"), |
456 self.host.bridge.messageNew(uid=unicode(uuid.uuid4()), | |
457 timestamp=time.time(), | |
458 from_jid=from_jid.full(), | |
459 to_jid=client.jid.full(), | |
460 message={u'': feedback}, | |
461 subject={}, | |
430 mess_type=C.MESS_TYPE_INFO, | 462 mess_type=C.MESS_TYPE_INFO, |
431 to_jid=client.jid.full(), | |
432 extra={}, | 463 extra={}, |
433 profile=client.profile) | 464 profile=client.profile) |
434 encrypted = False | 465 encrypted = False |
435 except StopIteration: | 466 except StopIteration: |
436 return data | 467 return data |
485 log.warning(u"No message found") | 516 log.warning(u"No message found") |
486 return False | 517 return False |
487 otrctx.sendMessage(0, msg.encode('utf-8')) | 518 otrctx.sendMessage(0, msg.encode('utf-8')) |
488 self.host.messageSendToBridge(mess_data, client) | 519 self.host.messageSendToBridge(mess_data, client) |
489 else: | 520 else: |
490 feedback = D_("Your message was not sent because your correspondent closed the encrypted conversation on his/her side. Either close your own side, or refresh the session.") | 521 feedback = D_(u"Your message was not sent because your correspondent closed the encrypted conversation on his/her side. Either close your own side, or refresh the session.") |
491 self.host.bridge.messageNew(to_jid.full(), | 522 self.host.bridge.messageNew(uid=unicode(uuid.uuid4()), |
492 feedback, | 523 timestamp=time.time(), |
524 from_jid=to_jid.full(), | |
525 to_jid=client.jid.full(), | |
526 message={u'': feedback}, | |
527 subject={}, | |
493 mess_type=C.MESS_TYPE_INFO, | 528 mess_type=C.MESS_TYPE_INFO, |
494 to_jid=client.jid.full(), | |
495 extra={}, | 529 extra={}, |
496 profile=client.profile) | 530 profile=client.profile) |
497 return False | 531 return False |
498 else: | 532 else: |
499 log.debug(u"sending message unencrypted") | 533 log.debug(u"sending message unencrypted") |