comparison sat/plugins/plugin_sec_otr.py @ 4037:524856bd7b19

massive refactoring to switch from camelCase to snake_case: historically, Libervia (SàT before) was using camelCase as allowed by PEP8 when using a pre-PEP8 code, to use the same coding style as in Twisted. However, snake_case is more readable and it's better to follow PEP8 best practices, so it has been decided to move on full snake_case. Because Libervia has a huge codebase, this ended with a ugly mix of camelCase and snake_case. To fix that, this patch does a big refactoring by renaming every function and method (including bridge) that are not coming from Twisted or Wokkel, to use fully snake_case. This is a massive change, and may result in some bugs.
author Goffi <goffi@goffi.org>
date Sat, 08 Apr 2023 13:54:42 +0200
parents 967a8e109cda
children c23cad65ae99
comparison
equal deleted inserted replaced
4036:c4464d7ae97b 4037:524856bd7b19
90 90
91 @property 91 @property
92 def _p_carbons(self): 92 def _p_carbons(self):
93 return self.context_manager.parent._p_carbons 93 return self.context_manager.parent._p_carbons
94 94
95 def getPolicy(self, key): 95 def get_policy(self, key):
96 if key in DEFAULT_POLICY_FLAGS: 96 if key in DEFAULT_POLICY_FLAGS:
97 return DEFAULT_POLICY_FLAGS[key] 97 return DEFAULT_POLICY_FLAGS[key]
98 else: 98 else:
99 return False 99 return False
100 100
121 "subject": {}, 121 "subject": {},
122 "type": "chat", 122 "type": "chat",
123 "extra": {}, 123 "extra": {},
124 "timestamp": time.time(), 124 "timestamp": time.time(),
125 } 125 }
126 client.generateMessageXML(mess_data) 126 client.generate_message_xml(mess_data)
127 xml = mess_data['xml'] 127 xml = mess_data['xml']
128 self._p_carbons.setPrivate(xml) 128 self._p_carbons.set_private(xml)
129 self._p_hints.addHintElements(xml, [ 129 self._p_hints.add_hint_elements(xml, [
130 self._p_hints.HINT_NO_COPY, 130 self._p_hints.HINT_NO_COPY,
131 self._p_hints.HINT_NO_PERMANENT_STORE]) 131 self._p_hints.HINT_NO_PERMANENT_STORE])
132 client.send(mess_data["xml"]) 132 client.send(mess_data["xml"])
133 else: 133 else:
134 message_elt = appdata["xml"] 134 message_elt = appdata["xml"]
135 assert message_elt.name == "message" 135 assert message_elt.name == "message"
136 message_elt.addElement("body", content=msg) 136 message_elt.addElement("body", content=msg)
137 137
138 def stopCb(self, __, feedback): 138 def stop_cb(self, __, feedback):
139 client = self.user.client 139 client = self.user.client
140 self.host.bridge.otrState( 140 self.host.bridge.otr_state(
141 OTR_STATE_UNENCRYPTED, self.peer.full(), client.profile 141 OTR_STATE_UNENCRYPTED, self.peer.full(), client.profile
142 ) 142 )
143 client.feedback(self.peer, feedback) 143 client.feedback(self.peer, feedback)
144 144
145 def stopEb(self, failure_): 145 def stop_eb(self, failure_):
146 # encryption may be already stopped in case of manual stop 146 # encryption may be already stopped in case of manual stop
147 if not failure_.check(exceptions.NotFound): 147 if not failure_.check(exceptions.NotFound):
148 log.error("Error while stopping OTR encryption: {msg}".format(msg=failure_)) 148 log.error("Error while stopping OTR encryption: {msg}".format(msg=failure_))
149 149
150 def isTrusted(self): 150 def is_trusted(self):
151 # we have to check value because potr code says that a 2-tuples should be 151 # we have to check value because potr code says that a 2-tuples should be
152 # returned while in practice it's either None or u"trusted" 152 # returned while in practice it's either None or u"trusted"
153 trusted = self.getCurrentTrust() 153 trusted = self.getCurrentTrust()
154 if trusted is None: 154 if trusted is None:
155 return False 155 return False
158 else: 158 else:
159 log.error("Unexpected getCurrentTrust() value: {value}".format( 159 log.error("Unexpected getCurrentTrust() value: {value}".format(
160 value=trusted)) 160 value=trusted))
161 return False 161 return False
162 162
163 def setState(self, state): 163 def set_state(self, state):
164 client = self.user.client 164 client = self.user.client
165 old_state = self.state 165 old_state = self.state
166 super(Context, self).setState(state) 166 super(Context, self).set_state(state)
167 log.debug("setState: %s (old_state=%s)" % (state, old_state)) 167 log.debug("set_state: %s (old_state=%s)" % (state, old_state))
168 168
169 if state == potr.context.STATE_PLAINTEXT: 169 if state == potr.context.STATE_PLAINTEXT:
170 feedback = _("/!\\ conversation with %(other_jid)s is now UNENCRYPTED") % { 170 feedback = _("/!\\ conversation with %(other_jid)s is now UNENCRYPTED") % {
171 "other_jid": self.peer.full() 171 "other_jid": self.peer.full()
172 } 172 }
173 d = defer.ensureDeferred(client.encryption.stop(self.peer, NS_OTR)) 173 d = defer.ensureDeferred(client.encryption.stop(self.peer, NS_OTR))
174 d.addCallback(self.stopCb, feedback=feedback) 174 d.addCallback(self.stop_cb, feedback=feedback)
175 d.addErrback(self.stopEb) 175 d.addErrback(self.stop_eb)
176 return 176 return
177 elif state == potr.context.STATE_ENCRYPTED: 177 elif state == potr.context.STATE_ENCRYPTED:
178 defer.ensureDeferred(client.encryption.start(self.peer, NS_OTR)) 178 defer.ensureDeferred(client.encryption.start(self.peer, NS_OTR))
179 try: 179 try:
180 trusted = self.isTrusted() 180 trusted = self.is_trusted()
181 except TypeError: 181 except TypeError:
182 trusted = False 182 trusted = False
183 trusted_str = _("trusted") if trusted else _("untrusted") 183 trusted_str = _("trusted") if trusted else _("untrusted")
184 184
185 if old_state == potr.context.STATE_ENCRYPTED: 185 if old_state == potr.context.STATE_ENCRYPTED:
193 ).format( 193 ).format(
194 trusted=trusted_str, 194 trusted=trusted_str,
195 other_jid=self.peer.full(), 195 other_jid=self.peer.full(),
196 extra_info=NO_ADV_FEATURES, 196 extra_info=NO_ADV_FEATURES,
197 ) 197 )
198 self.host.bridge.otrState( 198 self.host.bridge.otr_state(
199 OTR_STATE_ENCRYPTED, self.peer.full(), client.profile 199 OTR_STATE_ENCRYPTED, self.peer.full(), client.profile
200 ) 200 )
201 elif state == potr.context.STATE_FINISHED: 201 elif state == potr.context.STATE_FINISHED:
202 feedback = D_("OTR conversation with {other_jid} is FINISHED").format( 202 feedback = D_("OTR conversation with {other_jid} is FINISHED").format(
203 other_jid=self.peer.full() 203 other_jid=self.peer.full()
204 ) 204 )
205 d = defer.ensureDeferred(client.encryption.stop(self.peer, NS_OTR)) 205 d = defer.ensureDeferred(client.encryption.stop(self.peer, NS_OTR))
206 d.addCallback(self.stopCb, feedback=feedback) 206 d.addCallback(self.stop_cb, feedback=feedback)
207 d.addErrback(self.stopEb) 207 d.addErrback(self.stop_eb)
208 return 208 return
209 else: 209 else:
210 log.error(D_("Unknown OTR state")) 210 log.error(D_("Unknown OTR state"))
211 return 211 return
212 212
238 log.warning("Account created without resource") 238 log.warning("Account created without resource")
239 super(Account, self).__init__(str(client.jid), "xmpp", 1024) 239 super(Account, self).__init__(str(client.jid), "xmpp", 1024)
240 self.host = host 240 self.host = host
241 self.client = client 241 self.client = client
242 242
243 def loadPrivkey(self): 243 def load_privkey(self):
244 log.debug("loadPrivkey") 244 log.debug("load_privkey")
245 return self.privkey 245 return self.privkey
246 246
247 def savePrivkey(self): 247 def save_privkey(self):
248 log.debug("savePrivkey") 248 log.debug("save_privkey")
249 if self.privkey is None: 249 if self.privkey is None:
250 raise exceptions.InternalError(_("Save is called but privkey is None !")) 250 raise exceptions.InternalError(_("Save is called but privkey is None !"))
251 priv_key = hexlify(self.privkey.serializePrivateKey()) 251 priv_key = hexlify(self.privkey.serializePrivateKey())
252 encrypted_priv_key = self.host.memory.encryptValue(priv_key, self.client.profile) 252 encrypted_priv_key = self.host.memory.encrypt_value(priv_key, self.client.profile)
253 self.client._otr_data[PRIVATE_KEY] = encrypted_priv_key 253 self.client._otr_data[PRIVATE_KEY] = encrypted_priv_key
254 254
255 def loadTrusts(self): 255 def load_trusts(self):
256 trust_data = self.client._otr_data.get("trust", {}) 256 trust_data = self.client._otr_data.get("trust", {})
257 for jid_, jid_data in trust_data.items(): 257 for jid_, jid_data in trust_data.items():
258 for fingerprint, trust_level in jid_data.items(): 258 for fingerprint, trust_level in jid_data.items():
259 log.debug( 259 log.debug(
260 'setting trust for {jid}: [{fingerprint}] = "{trust_level}"'.format( 260 'setting trust for {jid}: [{fingerprint}] = "{trust_level}"'.format(
261 jid=jid_, fingerprint=fingerprint, trust_level=trust_level 261 jid=jid_, fingerprint=fingerprint, trust_level=trust_level
262 ) 262 )
263 ) 263 )
264 self.trusts.setdefault(jid.JID(jid_), {})[fingerprint] = trust_level 264 self.trusts.setdefault(jid.JID(jid_), {})[fingerprint] = trust_level
265 265
266 def saveTrusts(self): 266 def save_trusts(self):
267 log.debug("saving trusts for {profile}".format(profile=self.client.profile)) 267 log.debug("saving trusts for {profile}".format(profile=self.client.profile))
268 log.debug("trusts = {}".format(self.client._otr_data["trust"])) 268 log.debug("trusts = {}".format(self.client._otr_data["trust"]))
269 self.client._otr_data.force("trust") 269 self.client._otr_data.force("trust")
270 270
271 def setTrust(self, other_jid, fingerprint, trustLevel): 271 def set_trust(self, other_jid, fingerprint, trustLevel):
272 try: 272 try:
273 trust_data = self.client._otr_data["trust"] 273 trust_data = self.client._otr_data["trust"]
274 except KeyError: 274 except KeyError:
275 trust_data = {} 275 trust_data = {}
276 self.client._otr_data["trust"] = trust_data 276 self.client._otr_data["trust"] = trust_data
277 jid_data = trust_data.setdefault(other_jid.full(), {}) 277 jid_data = trust_data.setdefault(other_jid.full(), {})
278 jid_data[fingerprint] = trustLevel 278 jid_data[fingerprint] = trustLevel
279 super(Account, self).setTrust(other_jid, fingerprint, trustLevel) 279 super(Account, self).set_trust(other_jid, fingerprint, trustLevel)
280 280
281 281
282 class ContextManager(object): 282 class ContextManager(object):
283 def __init__(self, parent, client): 283 def __init__(self, parent, client):
284 self.parent = parent 284 self.parent = parent
287 287
288 @property 288 @property
289 def host(self): 289 def host(self):
290 return self.parent.host 290 return self.parent.host
291 291
292 def startContext(self, other_jid): 292 def start_context(self, other_jid):
293 assert isinstance(other_jid, jid.JID) 293 assert isinstance(other_jid, jid.JID)
294 context = self.contexts.setdefault( 294 context = self.contexts.setdefault(
295 other_jid, Context(self, other_jid) 295 other_jid, Context(self, other_jid)
296 ) 296 )
297 return context 297 return context
298 298
299 def getContextForUser(self, other): 299 def get_context_for_user(self, other):
300 log.debug("getContextForUser [%s]" % other) 300 log.debug("get_context_for_user [%s]" % other)
301 if not other.resource: 301 if not other.resource:
302 log.warning("getContextForUser called with a bare jid: %s" % other.full()) 302 log.warning("get_context_for_user called with a bare jid: %s" % other.full())
303 return self.startContext(other) 303 return self.start_context(other)
304 304
305 305
306 class OTR(object): 306 class OTR(object):
307 307
308 def __init__(self, host): 308 def __init__(self, host):
312 self.skipped_profiles = ( 312 self.skipped_profiles = (
313 set() 313 set()
314 ) #  FIXME: OTR should not be skipped per profile, this need to be refactored 314 ) #  FIXME: OTR should not be skipped per profile, this need to be refactored
315 self._p_hints = host.plugins["XEP-0334"] 315 self._p_hints = host.plugins["XEP-0334"]
316 self._p_carbons = host.plugins["XEP-0280"] 316 self._p_carbons = host.plugins["XEP-0280"]
317 host.trigger.add("messageReceived", self.messageReceivedTrigger, priority=100000) 317 host.trigger.add("messageReceived", self.message_received_trigger, priority=100000)
318 host.trigger.add("sendMessage", self.sendMessageTrigger, priority=100000) 318 host.trigger.add("sendMessage", self.send_message_trigger, priority=100000)
319 host.trigger.add("sendMessageData", self._sendMessageDataTrigger) 319 host.trigger.add("send_message_data", self._send_message_data_trigger)
320 host.bridge.addMethod( 320 host.bridge.add_method(
321 "skipOTR", ".plugin", in_sign="s", out_sign="", method=self._skipOTR 321 "skip_otr", ".plugin", in_sign="s", out_sign="", method=self._skip_otr
322 ) # FIXME: must be removed, must be done on per-message basis 322 ) # FIXME: must be removed, must be done on per-message basis
323 host.bridge.addSignal( 323 host.bridge.add_signal(
324 "otrState", ".plugin", signature="sss" 324 "otr_state", ".plugin", signature="sss"
325 ) # args: state, destinee_jid, profile 325 ) # args: state, destinee_jid, profile
326 # XXX: menus are disabled in favor to the new more generic encryption menu 326 # XXX: menus are disabled in favor to the new more generic encryption menu
327 # there are let here commented for a little while as a reference 327 # there are let here commented for a little while as a reference
328 # host.importMenu( 328 # host.import_menu(
329 # (OTR_MENU, D_(u"Start/Refresh")), 329 # (OTR_MENU, D_(u"Start/Refresh")),
330 # self._otrStartRefresh, 330 # self._otr_start_refresh,
331 # security_limit=0, 331 # security_limit=0,
332 # help_string=D_(u"Start or refresh an OTR session"), 332 # help_string=D_(u"Start or refresh an OTR session"),
333 # type_=C.MENU_SINGLE, 333 # type_=C.MENU_SINGLE,
334 # ) 334 # )
335 # host.importMenu( 335 # host.import_menu(
336 # (OTR_MENU, D_(u"End session")), 336 # (OTR_MENU, D_(u"End session")),
337 # self._otrSessionEnd, 337 # self._otr_session_end,
338 # security_limit=0, 338 # security_limit=0,
339 # help_string=D_(u"Finish an OTR session"), 339 # help_string=D_(u"Finish an OTR session"),
340 # type_=C.MENU_SINGLE, 340 # type_=C.MENU_SINGLE,
341 # ) 341 # )
342 # host.importMenu( 342 # host.import_menu(
343 # (OTR_MENU, D_(u"Authenticate")), 343 # (OTR_MENU, D_(u"Authenticate")),
344 # self._otrAuthenticate, 344 # self._otr_authenticate,
345 # security_limit=0, 345 # security_limit=0,
346 # help_string=D_(u"Authenticate user/see your fingerprint"), 346 # help_string=D_(u"Authenticate user/see your fingerprint"),
347 # type_=C.MENU_SINGLE, 347 # type_=C.MENU_SINGLE,
348 # ) 348 # )
349 # host.importMenu( 349 # host.import_menu(
350 # (OTR_MENU, D_(u"Drop private key")), 350 # (OTR_MENU, D_(u"Drop private key")),
351 # self._dropPrivKey, 351 # self._drop_priv_key,
352 # security_limit=0, 352 # security_limit=0,
353 # type_=C.MENU_SINGLE, 353 # type_=C.MENU_SINGLE,
354 # ) 354 # )
355 host.trigger.add("presence_received", self._presenceReceivedTrigger) 355 host.trigger.add("presence_received", self._presence_received_trigger)
356 self.host.registerEncryptionPlugin(self, "OTR", NS_OTR, directed=True) 356 self.host.register_encryption_plugin(self, "OTR", NS_OTR, directed=True)
357 357
358 def _skipOTR(self, profile): 358 def _skip_otr(self, profile):
359 """Tell the backend to not handle OTR for this profile. 359 """Tell the backend to not handle OTR for this profile.
360 360
361 @param profile (str): %(doc_profile)s 361 @param profile (str): %(doc_profile)s
362 """ 362 """
363 # FIXME: should not be done per profile but per message, using extra data 363 # FIXME: should not be done per profile but per message, using extra data
364 # for message received, profile wide hook may be need, but client 364 # for message received, profile wide hook may be need, but client
365 # should be used anyway instead of a class attribute 365 # should be used anyway instead of a class attribute
366 self.skipped_profiles.add(profile) 366 self.skipped_profiles.add(profile)
367 367
368 @defer.inlineCallbacks 368 @defer.inlineCallbacks
369 def profileConnecting(self, client): 369 def profile_connecting(self, client):
370 if client.profile in self.skipped_profiles: 370 if client.profile in self.skipped_profiles:
371 return 371 return
372 ctxMng = client._otr_context_manager = ContextManager(self, client) 372 ctxMng = client._otr_context_manager = ContextManager(self, client)
373 client._otr_data = persistent.PersistentBinaryDict(NS_OTR, client.profile) 373 client._otr_data = persistent.PersistentBinaryDict(NS_OTR, client.profile)
374 yield client._otr_data.load() 374 yield client._otr_data.load()
375 encrypted_priv_key = client._otr_data.get(PRIVATE_KEY, None) 375 encrypted_priv_key = client._otr_data.get(PRIVATE_KEY, None)
376 if encrypted_priv_key is not None: 376 if encrypted_priv_key is not None:
377 priv_key = self.host.memory.decryptValue( 377 priv_key = self.host.memory.decrypt_value(
378 encrypted_priv_key, client.profile 378 encrypted_priv_key, client.profile
379 ) 379 )
380 ctxMng.account.privkey = potr.crypt.PK.parsePrivateKey( 380 ctxMng.account.privkey = potr.crypt.PK.parsePrivateKey(
381 unhexlify(priv_key.encode('utf-8')) 381 unhexlify(priv_key.encode('utf-8'))
382 )[0] 382 )[0]
383 else: 383 else:
384 ctxMng.account.privkey = None 384 ctxMng.account.privkey = None
385 ctxMng.account.loadTrusts() 385 ctxMng.account.load_trusts()
386 386
387 def profileDisconnected(self, client): 387 def profile_disconnected(self, client):
388 if client.profile in self.skipped_profiles: 388 if client.profile in self.skipped_profiles:
389 self.skipped_profiles.remove(client.profile) 389 self.skipped_profiles.remove(client.profile)
390 return 390 return
391 for context in list(client._otr_context_manager.contexts.values()): 391 for context in list(client._otr_context_manager.contexts.values()):
392 context.disconnect() 392 context.disconnect()
393 del client._otr_context_manager 393 del client._otr_context_manager
394 394
395 # encryption plugin methods 395 # encryption plugin methods
396 396
397 def startEncryption(self, client, entity_jid): 397 def start_encryption(self, client, entity_jid):
398 self.startRefresh(client, entity_jid) 398 self.start_refresh(client, entity_jid)
399 399
400 def stopEncryption(self, client, entity_jid): 400 def stop_encryption(self, client, entity_jid):
401 self.endSession(client, entity_jid) 401 self.end_session(client, entity_jid)
402 402
403 def getTrustUI(self, client, entity_jid): 403 def get_trust_ui(self, client, entity_jid):
404 if not entity_jid.resource: 404 if not entity_jid.resource:
405 entity_jid.resource = self.host.memory.getMainResource( 405 entity_jid.resource = self.host.memory.main_resource_get(
406 client, entity_jid 406 client, entity_jid
407 ) # FIXME: temporary and unsecure, must be changed when frontends 407 ) # FIXME: temporary and unsecure, must be changed when frontends
408 # are refactored 408 # are refactored
409 ctxMng = client._otr_context_manager 409 ctxMng = client._otr_context_manager
410 otrctx = ctxMng.getContextForUser(entity_jid) 410 otrctx = ctxMng.get_context_for_user(entity_jid)
411 priv_key = ctxMng.account.privkey 411 priv_key = ctxMng.account.privkey
412 412
413 if priv_key is None: 413 if priv_key is None:
414 # we have no private key yet 414 # we have no private key yet
415 dialog = xml_tools.XMLUI( 415 dialog = xml_tools.XMLUI(
442 }, 442 },
443 title=_("Fingerprint"), 443 title=_("Fingerprint"),
444 ) 444 )
445 return dialog 445 return dialog
446 446
447 def setTrust(raw_data, profile): 447 def set_trust(raw_data, profile):
448 if xml_tools.isXMLUICancelled(raw_data): 448 if xml_tools.is_xmlui_cancelled(raw_data):
449 return {} 449 return {}
450 # This method is called when authentication form is submited 450 # This method is called when authentication form is submited
451 data = xml_tools.XMLUIResult2DataFormResult(raw_data) 451 data = xml_tools.xmlui_result_2_data_form_result(raw_data)
452 if data["match"] == "yes": 452 if data["match"] == "yes":
453 otrctx.setCurrentTrust(OTR_STATE_TRUSTED) 453 otrctx.setCurrentTrust(OTR_STATE_TRUSTED)
454 note_msg = _("Your correspondent {correspondent} is now TRUSTED") 454 note_msg = _("Your correspondent {correspondent} is now TRUSTED")
455 self.host.bridge.otrState( 455 self.host.bridge.otr_state(
456 OTR_STATE_TRUSTED, entity_jid.full(), client.profile 456 OTR_STATE_TRUSTED, entity_jid.full(), client.profile
457 ) 457 )
458 else: 458 else:
459 otrctx.setCurrentTrust("") 459 otrctx.setCurrentTrust("")
460 note_msg = _("Your correspondent {correspondent} is now UNTRUSTED") 460 note_msg = _("Your correspondent {correspondent} is now UNTRUSTED")
461 self.host.bridge.otrState( 461 self.host.bridge.otr_state(
462 OTR_STATE_UNTRUSTED, entity_jid.full(), client.profile 462 OTR_STATE_UNTRUSTED, entity_jid.full(), client.profile
463 ) 463 )
464 note = xml_tools.XMLUI( 464 note = xml_tools.XMLUI(
465 C.XMLUI_DIALOG, 465 C.XMLUI_DIALOG,
466 dialog_opt={ 466 dialog_opt={
468 C.XMLUI_DATA_MESS: note_msg.format(correspondent=otrctx.peer), 468 C.XMLUI_DATA_MESS: note_msg.format(correspondent=otrctx.peer),
469 }, 469 },
470 ) 470 )
471 return {"xmlui": note.toXml()} 471 return {"xmlui": note.toXml()}
472 472
473 submit_id = self.host.registerCallback(setTrust, with_data=True, one_shot=True) 473 submit_id = self.host.register_callback(set_trust, with_data=True, one_shot=True)
474 trusted = otrctx.isTrusted() 474 trusted = otrctx.is_trusted()
475 475
476 xmlui = xml_tools.XMLUI( 476 xmlui = xml_tools.XMLUI(
477 C.XMLUI_FORM, 477 C.XMLUI_FORM,
478 title=_("Authentication ({entity_jid})").format(entity_jid=entity_jid.full()), 478 title=_("Authentication ({entity_jid})").format(entity_jid=entity_jid.full()),
479 submit_id=submit_id, 479 submit_id=submit_id,
487 D_("Your correspondent fingerprint should be:\n{fingerprint}").format( 487 D_("Your correspondent fingerprint should be:\n{fingerprint}").format(
488 fingerprint=other_fingerprint 488 fingerprint=other_fingerprint
489 ) 489 )
490 ) 490 )
491 xmlui.addDivider("blank") 491 xmlui.addDivider("blank")
492 xmlui.changeContainer("pairs") 492 xmlui.change_container("pairs")
493 xmlui.addLabel(D_("Is your correspondent fingerprint the same as here ?")) 493 xmlui.addLabel(D_("Is your correspondent fingerprint the same as here ?"))
494 xmlui.addList( 494 xmlui.addList(
495 "match", [("yes", _("yes")), ("no", _("no"))], ["yes" if trusted else "no"] 495 "match", [("yes", _("yes")), ("no", _("no"))], ["yes" if trusted else "no"]
496 ) 496 )
497 return xmlui 497 return xmlui
498 498
499 def _otrStartRefresh(self, menu_data, profile): 499 def _otr_start_refresh(self, menu_data, profile):
500 """Start or refresh an OTR session 500 """Start or refresh an OTR session
501 501
502 @param menu_data: %(menu_data)s 502 @param menu_data: %(menu_data)s
503 @param profile: %(doc_profile)s 503 @param profile: %(doc_profile)s
504 """ 504 """
505 client = self.host.getClient(profile) 505 client = self.host.get_client(profile)
506 try: 506 try:
507 to_jid = jid.JID(menu_data["jid"]) 507 to_jid = jid.JID(menu_data["jid"])
508 except KeyError: 508 except KeyError:
509 log.error(_("jid key is not present !")) 509 log.error(_("jid key is not present !"))
510 return defer.fail(exceptions.DataError) 510 return defer.fail(exceptions.DataError)
511 self.startRefresh(client, to_jid) 511 self.start_refresh(client, to_jid)
512 return {} 512 return {}
513 513
514 def startRefresh(self, client, to_jid): 514 def start_refresh(self, client, to_jid):
515 """Start or refresh an OTR session 515 """Start or refresh an OTR session
516 516
517 @param to_jid(jid.JID): jid to start encrypted session with 517 @param to_jid(jid.JID): jid to start encrypted session with
518 """ 518 """
519 encrypted_session = client.encryption.getSession(to_jid.userhostJID()) 519 encrypted_session = client.encryption.getSession(to_jid.userhostJID())
520 if encrypted_session and encrypted_session['plugin'].namespace != NS_OTR: 520 if encrypted_session and encrypted_session['plugin'].namespace != NS_OTR:
521 raise exceptions.ConflictError(_( 521 raise exceptions.ConflictError(_(
522 "Can't start an OTR session, there is already an encrypted session " 522 "Can't start an OTR session, there is already an encrypted session "
523 "with {name}").format(name=encrypted_session['plugin'].name)) 523 "with {name}").format(name=encrypted_session['plugin'].name))
524 if not to_jid.resource: 524 if not to_jid.resource:
525 to_jid.resource = self.host.memory.getMainResource( 525 to_jid.resource = self.host.memory.main_resource_get(
526 client, to_jid 526 client, to_jid
527 ) # FIXME: temporary and unsecure, must be changed when frontends 527 ) # FIXME: temporary and unsecure, must be changed when frontends
528 # are refactored 528 # are refactored
529 otrctx = client._otr_context_manager.getContextForUser(to_jid) 529 otrctx = client._otr_context_manager.get_context_for_user(to_jid)
530 query = otrctx.sendMessage(0, b"?OTRv?") 530 query = otrctx.sendMessage(0, b"?OTRv?")
531 otrctx.inject(query) 531 otrctx.inject(query)
532 532
533 def _otrSessionEnd(self, menu_data, profile): 533 def _otr_session_end(self, menu_data, profile):
534 """End an OTR session 534 """End an OTR session
535 535
536 @param menu_data: %(menu_data)s 536 @param menu_data: %(menu_data)s
537 @param profile: %(doc_profile)s 537 @param profile: %(doc_profile)s
538 """ 538 """
539 client = self.host.getClient(profile) 539 client = self.host.get_client(profile)
540 try: 540 try:
541 to_jid = jid.JID(menu_data["jid"]) 541 to_jid = jid.JID(menu_data["jid"])
542 except KeyError: 542 except KeyError:
543 log.error(_("jid key is not present !")) 543 log.error(_("jid key is not present !"))
544 return defer.fail(exceptions.DataError) 544 return defer.fail(exceptions.DataError)
545 self.endSession(client, to_jid) 545 self.end_session(client, to_jid)
546 return {} 546 return {}
547 547
548 def endSession(self, client, to_jid): 548 def end_session(self, client, to_jid):
549 """End an OTR session""" 549 """End an OTR session"""
550 if not to_jid.resource: 550 if not to_jid.resource:
551 to_jid.resource = self.host.memory.getMainResource( 551 to_jid.resource = self.host.memory.main_resource_get(
552 client, to_jid 552 client, to_jid
553 ) # FIXME: temporary and unsecure, must be changed when frontends 553 ) # FIXME: temporary and unsecure, must be changed when frontends
554 # are refactored 554 # are refactored
555 otrctx = client._otr_context_manager.getContextForUser(to_jid) 555 otrctx = client._otr_context_manager.get_context_for_user(to_jid)
556 otrctx.disconnect() 556 otrctx.disconnect()
557 return {} 557 return {}
558 558
559 def _otrAuthenticate(self, menu_data, profile): 559 def _otr_authenticate(self, menu_data, profile):
560 """End an OTR session 560 """End an OTR session
561 561
562 @param menu_data: %(menu_data)s 562 @param menu_data: %(menu_data)s
563 @param profile: %(doc_profile)s 563 @param profile: %(doc_profile)s
564 """ 564 """
565 client = self.host.getClient(profile) 565 client = self.host.get_client(profile)
566 try: 566 try:
567 to_jid = jid.JID(menu_data["jid"]) 567 to_jid = jid.JID(menu_data["jid"])
568 except KeyError: 568 except KeyError:
569 log.error(_("jid key is not present !")) 569 log.error(_("jid key is not present !"))
570 return defer.fail(exceptions.DataError) 570 return defer.fail(exceptions.DataError)
571 return self.authenticate(client, to_jid) 571 return self.authenticate(client, to_jid)
572 572
573 def authenticate(self, client, to_jid): 573 def authenticate(self, client, to_jid):
574 """Authenticate other user and see our own fingerprint""" 574 """Authenticate other user and see our own fingerprint"""
575 xmlui = self.getTrustUI(client, to_jid) 575 xmlui = self.get_trust_ui(client, to_jid)
576 return {"xmlui": xmlui.toXml()} 576 return {"xmlui": xmlui.toXml()}
577 577
578 def _dropPrivKey(self, menu_data, profile): 578 def _drop_priv_key(self, menu_data, profile):
579 """Drop our private Key 579 """Drop our private Key
580 580
581 @param menu_data: %(menu_data)s 581 @param menu_data: %(menu_data)s
582 @param profile: %(doc_profile)s 582 @param profile: %(doc_profile)s
583 """ 583 """
584 client = self.host.getClient(profile) 584 client = self.host.get_client(profile)
585 try: 585 try:
586 to_jid = jid.JID(menu_data["jid"]) 586 to_jid = jid.JID(menu_data["jid"])
587 if not to_jid.resource: 587 if not to_jid.resource:
588 to_jid.resource = self.host.memory.getMainResource( 588 to_jid.resource = self.host.memory.main_resource_get(
589 client, to_jid 589 client, to_jid
590 ) # FIXME: temporary and unsecure, must be changed when frontends 590 ) # FIXME: temporary and unsecure, must be changed when frontends
591 # are refactored 591 # are refactored
592 except KeyError: 592 except KeyError:
593 log.error(_("jid key is not present !")) 593 log.error(_("jid key is not present !"))
597 if ctxMng.account.privkey is None: 597 if ctxMng.account.privkey is None:
598 return { 598 return {
599 "xmlui": xml_tools.note(_("You don't have a private key yet !")).toXml() 599 "xmlui": xml_tools.note(_("You don't have a private key yet !")).toXml()
600 } 600 }
601 601
602 def dropKey(data, profile): 602 def drop_key(data, profile):
603 if C.bool(data["answer"]): 603 if C.bool(data["answer"]):
604 # we end all sessions 604 # we end all sessions
605 for context in list(ctxMng.contexts.values()): 605 for context in list(ctxMng.contexts.values()):
606 context.disconnect() 606 context.disconnect()
607 ctxMng.account.privkey = None 607 ctxMng.account.privkey = None
612 D_("Your private key has been dropped") 612 D_("Your private key has been dropped")
613 ).toXml() 613 ).toXml()
614 } 614 }
615 return {} 615 return {}
616 616
617 submit_id = self.host.registerCallback(dropKey, with_data=True, one_shot=True) 617 submit_id = self.host.register_callback(drop_key, with_data=True, one_shot=True)
618 618
619 confirm = xml_tools.XMLUI( 619 confirm = xml_tools.XMLUI(
620 C.XMLUI_DIALOG, 620 C.XMLUI_DIALOG,
621 title=_("Confirm private key drop"), 621 title=_("Confirm private key drop"),
622 dialog_opt={"type": C.XMLUI_DIALOG_CONFIRM, "message": _(DROP_TXT)}, 622 dialog_opt={"type": C.XMLUI_DIALOG_CONFIRM, "message": _(DROP_TXT)},
623 submit_id=submit_id, 623 submit_id=submit_id,
624 ) 624 )
625 return {"xmlui": confirm.toXml()} 625 return {"xmlui": confirm.toXml()}
626 626
627 def _receivedTreatment(self, data, client): 627 def _received_treatment(self, data, client):
628 from_jid = data["from"] 628 from_jid = data["from"]
629 log.debug("_receivedTreatment [from_jid = %s]" % from_jid) 629 log.debug("_received_treatment [from_jid = %s]" % from_jid)
630 otrctx = client._otr_context_manager.getContextForUser(from_jid) 630 otrctx = client._otr_context_manager.get_context_for_user(from_jid)
631 631
632 try: 632 try:
633 message = ( 633 message = (
634 next(iter(data["message"].values())) 634 next(iter(data["message"].values()))
635 ) # FIXME: Q&D fix for message refactoring, message is now a dict 635 ) # FIXME: Q&D fix for message refactoring, message is now a dict
697 else: 697 else:
698 raise failure.Failure( 698 raise failure.Failure(
699 exceptions.CancelError("Cancelled by OTR") 699 exceptions.CancelError("Cancelled by OTR")
700 ) # no message at all (no history, no signal) 700 ) # no message at all (no history, no signal)
701 701
702 client.encryption.markAsEncrypted(data, namespace=NS_OTR) 702 client.encryption.mark_as_encrypted(data, namespace=NS_OTR)
703 trusted = otrctx.isTrusted() 703 trusted = otrctx.is_trusted()
704 704
705 if trusted: 705 if trusted:
706 client.encryption.markAsTrusted(data) 706 client.encryption.mark_as_trusted(data)
707 else: 707 else:
708 client.encryption.markAsUntrusted(data) 708 client.encryption.mark_as_untrusted(data)
709 709
710 return data 710 return data
711 711
712 def _receivedTreatmentForSkippedProfiles(self, data): 712 def _received_treatment_for_skipped_profiles(self, data):
713 """This profile must be skipped because the frontend manages OTR itself, 713 """This profile must be skipped because the frontend manages OTR itself,
714 714
715 but we still need to check if the message must be stored in history or not 715 but we still need to check if the message must be stored in history or not
716 """ 716 """
717 #  XXX: FIXME: this should not be done on a per-profile basis, but per-message 717 #  XXX: FIXME: this should not be done on a per-profile basis, but per-message
729 # if they are used at the same time as Libervia. 729 # if they are used at the same time as Libervia.
730 # Hard to avoid with decryption on Libervia though. 730 # Hard to avoid with decryption on Libervia though.
731 data["history"] = C.HISTORY_SKIP 731 data["history"] = C.HISTORY_SKIP
732 return data 732 return data
733 733
734 def messageReceivedTrigger(self, client, message_elt, post_treat): 734 def message_received_trigger(self, client, message_elt, post_treat):
735 if client.is_component: 735 if client.is_component:
736 return True 736 return True
737 if message_elt.getAttribute("type") == C.MESS_TYPE_GROUPCHAT: 737 if message_elt.getAttribute("type") == C.MESS_TYPE_GROUPCHAT:
738 # OTR is not possible in group chats 738 # OTR is not possible in group chats
739 return True 739 return True
740 from_jid = jid.JID(message_elt['from']) 740 from_jid = jid.JID(message_elt['from'])
741 if not from_jid.resource or from_jid.userhostJID() == client.jid.userhostJID(): 741 if not from_jid.resource or from_jid.userhostJID() == client.jid.userhostJID():
742 # OTR is only usable when resources are present 742 # OTR is only usable when resources are present
743 return True 743 return True
744 if client.profile in self.skipped_profiles: 744 if client.profile in self.skipped_profiles:
745 post_treat.addCallback(self._receivedTreatmentForSkippedProfiles) 745 post_treat.addCallback(self._received_treatment_for_skipped_profiles)
746 else: 746 else:
747 post_treat.addCallback(self._receivedTreatment, client) 747 post_treat.addCallback(self._received_treatment, client)
748 return True 748 return True
749 749
750 def _sendMessageDataTrigger(self, client, mess_data): 750 def _send_message_data_trigger(self, client, mess_data):
751 if client.is_component: 751 if client.is_component:
752 return True 752 return True
753 encryption = mess_data.get(C.MESS_KEY_ENCRYPTION) 753 encryption = mess_data.get(C.MESS_KEY_ENCRYPTION)
754 if encryption is None or encryption['plugin'].namespace != NS_OTR: 754 if encryption is None or encryption['plugin'].namespace != NS_OTR:
755 return 755 return
756 to_jid = mess_data['to'] 756 to_jid = mess_data['to']
757 if not to_jid.resource: 757 if not to_jid.resource:
758 to_jid.resource = self.host.memory.getMainResource( 758 to_jid.resource = self.host.memory.main_resource_get(
759 client, to_jid 759 client, to_jid
760 ) # FIXME: temporary and unsecure, must be changed when frontends 760 ) # FIXME: temporary and unsecure, must be changed when frontends
761 otrctx = client._otr_context_manager.getContextForUser(to_jid) 761 otrctx = client._otr_context_manager.get_context_for_user(to_jid)
762 message_elt = mess_data["xml"] 762 message_elt = mess_data["xml"]
763 if otrctx.state == potr.context.STATE_ENCRYPTED: 763 if otrctx.state == potr.context.STATE_ENCRYPTED:
764 log.debug("encrypting message") 764 log.debug("encrypting message")
765 body = None 765 body = None
766 for child in list(message_elt.children): 766 for child in list(message_elt.children):
774 # we don't want any XHTML-IM element 774 # we don't want any XHTML-IM element
775 message_elt.children.remove(child) 775 message_elt.children.remove(child)
776 if body is None: 776 if body is None:
777 log.warning("No message found") 777 log.warning("No message found")
778 else: 778 else:
779 self._p_carbons.setPrivate(message_elt) 779 self._p_carbons.set_private(message_elt)
780 self._p_hints.addHintElements(message_elt, [ 780 self._p_hints.add_hint_elements(message_elt, [
781 self._p_hints.HINT_NO_COPY, 781 self._p_hints.HINT_NO_COPY,
782 self._p_hints.HINT_NO_PERMANENT_STORE]) 782 self._p_hints.HINT_NO_PERMANENT_STORE])
783 otrctx.sendMessage(0, str(body).encode("utf-8"), appdata=mess_data) 783 otrctx.sendMessage(0, str(body).encode("utf-8"), appdata=mess_data)
784 else: 784 else:
785 feedback = D_( 785 feedback = D_(
789 ) 789 )
790 log.warning(_("Message discarded because closed encryption channel")) 790 log.warning(_("Message discarded because closed encryption channel"))
791 client.feedback(to_jid, feedback) 791 client.feedback(to_jid, feedback)
792 raise failure.Failure(exceptions.CancelError("Cancelled by OTR plugin")) 792 raise failure.Failure(exceptions.CancelError("Cancelled by OTR plugin"))
793 793
794 def sendMessageTrigger(self, client, mess_data, pre_xml_treatments, 794 def send_message_trigger(self, client, mess_data, pre_xml_treatments,
795 post_xml_treatments): 795 post_xml_treatments):
796 if client.is_component: 796 if client.is_component:
797 return True 797 return True
798 if mess_data["type"] == "groupchat": 798 if mess_data["type"] == "groupchat":
799 return True 799 return True
806 if client.encryption.getSession(to_jid.userhostJID()): 806 if client.encryption.getSession(to_jid.userhostJID()):
807 # there is already an encrypted session with this entity 807 # there is already an encrypted session with this entity
808 return True 808 return True
809 809
810 if not to_jid.resource: 810 if not to_jid.resource:
811 to_jid.resource = self.host.memory.getMainResource( 811 to_jid.resource = self.host.memory.main_resource_get(
812 client, to_jid 812 client, to_jid
813 ) # FIXME: full jid may not be known 813 ) # FIXME: full jid may not be known
814 814
815 otrctx = client._otr_context_manager.getContextForUser(to_jid) 815 otrctx = client._otr_context_manager.get_context_for_user(to_jid)
816 816
817 if otrctx.state != potr.context.STATE_PLAINTEXT: 817 if otrctx.state != potr.context.STATE_PLAINTEXT:
818 defer.ensureDeferred(client.encryption.start(to_jid, NS_OTR)) 818 defer.ensureDeferred(client.encryption.start(to_jid, NS_OTR))
819 client.encryption.setEncryptionFlag(mess_data) 819 client.encryption.set_encryption_flag(mess_data)
820 if not mess_data["to"].resource: 820 if not mess_data["to"].resource:
821 # if not resource was given, we force it here 821 # if not resource was given, we force it here
822 mess_data["to"] = to_jid 822 mess_data["to"] = to_jid
823 return True 823 return True
824 824
825 def _presenceReceivedTrigger(self, client, entity, show, priority, statuses): 825 def _presence_received_trigger(self, client, entity, show, priority, statuses):
826 if show != C.PRESENCE_UNAVAILABLE: 826 if show != C.PRESENCE_UNAVAILABLE:
827 return True 827 return True
828 if not entity.resource: 828 if not entity.resource:
829 try: 829 try:
830 entity.resource = self.host.memory.getMainResource( 830 entity.resource = self.host.memory.main_resource_get(
831 client, entity 831 client, entity
832 ) # FIXME: temporary and unsecure, must be changed when frontends 832 ) # FIXME: temporary and unsecure, must be changed when frontends
833 # are refactored 833 # are refactored
834 except exceptions.UnknownEntityError: 834 except exceptions.UnknownEntityError:
835 return True # entity was not connected 835 return True # entity was not connected
836 if entity in client._otr_context_manager.contexts: 836 if entity in client._otr_context_manager.contexts:
837 otrctx = client._otr_context_manager.getContextForUser(entity) 837 otrctx = client._otr_context_manager.get_context_for_user(entity)
838 otrctx.disconnect() 838 otrctx.disconnect()
839 return True 839 return True