comparison libervia/backend/memory/encryption.py @ 4270:0d7bb4df2343

Reformatted code base using black.
author Goffi <goffi@goffi.org>
date Wed, 19 Jun 2024 18:44:57 +0200
parents 4b842c1fb686
children
comparison
equal deleted inserted replaced
4269:64a85ce8be70 4270:0d7bb4df2343
21 from functools import partial 21 from functools import partial
22 from typing import Optional 22 from typing import Optional
23 from twisted.words.protocols.jabber import jid 23 from twisted.words.protocols.jabber import jid
24 from twisted.internet import defer 24 from twisted.internet import defer
25 from twisted.python import failure 25 from twisted.python import failure
26 from libervia.backend.core.core_types import EncryptionPlugin, EncryptionSession, MessageData 26 from libervia.backend.core.core_types import (
27 EncryptionPlugin,
28 EncryptionSession,
29 MessageData,
30 )
27 from libervia.backend.core.i18n import D_, _ 31 from libervia.backend.core.i18n import D_, _
28 from libervia.backend.core.constants import Const as C 32 from libervia.backend.core.constants import Const as C
29 from libervia.backend.core import exceptions 33 from libervia.backend.core import exceptions
30 from libervia.backend.core.log import getLogger 34 from libervia.backend.core.log import getLogger
31 from libervia.backend.tools.common import data_format 35 from libervia.backend.tools.common import data_format
36 log = getLogger(__name__) 40 log = getLogger(__name__)
37 41
38 42
39 class EncryptionHandler: 43 class EncryptionHandler:
40 """Class to handle encryption sessions for a client""" 44 """Class to handle encryption sessions for a client"""
45
41 plugins = [] # plugin able to encrypt messages 46 plugins = [] # plugin able to encrypt messages
42 47
43 def __init__(self, client): 48 def __init__(self, client):
44 self.client = client 49 self.client = client
45 self._sessions = {} # bare_jid ==> encryption_data 50 self._sessions = {} # bare_jid ==> encryption_data
46 self._stored_session = persistent.PersistentDict( 51 self._stored_session = persistent.PersistentDict(
47 "core:encryption", profile=client.profile) 52 "core:encryption", profile=client.profile
53 )
48 54
49 @property 55 @property
50 def host(self): 56 def host(self):
51 return self.client.host_app 57 return self.client.host_app
52 58
61 if start_d_list: 67 if start_d_list:
62 result = await defer.DeferredList(start_d_list) 68 result = await defer.DeferredList(start_d_list)
63 for idx, (success, err) in enumerate(result): 69 for idx, (success, err) in enumerate(result):
64 if not success: 70 if not success:
65 entity_jid_s, namespace = list(self._stored_session.items())[idx] 71 entity_jid_s, namespace = list(self._stored_session.items())[idx]
66 log.warning(_( 72 log.warning(
67 "Could not restart {namespace!r} encryption with {entity}: {err}" 73 _(
68 ).format(namespace=namespace, entity=entity_jid_s, err=err)) 74 "Could not restart {namespace!r} encryption with {entity}: {err}"
75 ).format(namespace=namespace, entity=entity_jid_s, err=err)
76 )
69 log.info(_("encryption sessions restored")) 77 log.info(_("encryption sessions restored"))
70 78
71 @classmethod 79 @classmethod
72 def register_plugin(cls, plg_instance, name, namespace, priority=0, directed=False): 80 def register_plugin(cls, plg_instance, name, namespace, priority=0, directed=False):
73 """Register a plugin handling an encryption algorithm 81 """Register a plugin handling an encryption algorithm
103 plugin = EncryptionPlugin( 111 plugin = EncryptionPlugin(
104 instance=plg_instance, 112 instance=plg_instance,
105 name=name, 113 name=name,
106 namespace=namespace, 114 namespace=namespace,
107 priority=priority, 115 priority=priority,
108 directed=directed) 116 directed=directed,
117 )
109 cls.plugins.append(plugin) 118 cls.plugins.append(plugin)
110 cls.plugins.sort(key=lambda p: p.priority) 119 cls.plugins.sort(key=lambda p: p.priority)
111 log.info(_("Encryption plugin registered: {name}").format(name=name)) 120 log.info(_("Encryption plugin registered: {name}").format(name=name))
112 121
113 @classmethod 122 @classmethod
117 @classmethod 126 @classmethod
118 def get_plugin(cls, namespace): 127 def get_plugin(cls, namespace):
119 try: 128 try:
120 return next(p for p in cls.plugins if p.namespace == namespace) 129 return next(p for p in cls.plugins if p.namespace == namespace)
121 except StopIteration: 130 except StopIteration:
122 raise exceptions.NotFound(_( 131 raise exceptions.NotFound(
123 "Can't find requested encryption plugin: {namespace}").format( 132 _("Can't find requested encryption plugin: {namespace}").format(
124 namespace=namespace)) 133 namespace=namespace
134 )
135 )
125 136
126 @classmethod 137 @classmethod
127 def get_namespaces(cls): 138 def get_namespaces(cls):
128 """Get available plugin namespaces""" 139 """Get available plugin namespaces"""
129 return {p.namespace for p in cls.getPlugins()} 140 return {p.namespace for p in cls.getPlugins()}
137 @raise exceptions.NotFound: there is not encryption plugin of this name 148 @raise exceptions.NotFound: there is not encryption plugin of this name
138 """ 149 """
139 for p in cls.plugins: 150 for p in cls.plugins:
140 if p.name.lower() == name.lower(): 151 if p.name.lower() == name.lower():
141 return p.namespace 152 return p.namespace
142 raise exceptions.NotFound(_( 153 raise exceptions.NotFound(
143 "Can't find a plugin with the name \"{name}\".".format( 154 _('Can\'t find a plugin with the name "{name}".'.format(name=name))
144 name=name))) 155 )
145 156
146 def get_bridge_data(self, session): 157 def get_bridge_data(self, session):
147 """Retrieve session data serialized for bridge. 158 """Retrieve session data serialized for bridge.
148 159
149 @param session(dict): encryption session 160 @param session(dict): encryption session
150 @return (unicode): serialized data for bridge 161 @return (unicode): serialized data for bridge
151 """ 162 """
152 if session is None: 163 if session is None:
153 return '' 164 return ""
154 plugin = session['plugin'] 165 plugin = session["plugin"]
155 bridge_data = {'name': plugin.name, 166 bridge_data = {"name": plugin.name, "namespace": plugin.namespace}
156 'namespace': plugin.namespace} 167 if "directed_devices" in session:
157 if 'directed_devices' in session: 168 bridge_data["directed_devices"] = session["directed_devices"]
158 bridge_data['directed_devices'] = session['directed_devices']
159 169
160 return data_format.serialise(bridge_data) 170 return data_format.serialise(bridge_data)
161 171
162 async def _start_encryption(self, plugin, entity): 172 async def _start_encryption(self, plugin, entity):
163 """Start encryption with a plugin 173 """Start encryption with a plugin
203 None to select automatically an algorithm 213 None to select automatically an algorithm
204 @param replace(bool): if True and an encrypted session already exists, 214 @param replace(bool): if True and an encrypted session already exists,
205 it will be replaced by the new one 215 it will be replaced by the new one
206 """ 216 """
207 if not self.plugins: 217 if not self.plugins:
208 raise exceptions.NotFound(_("No encryption plugin is registered, " 218 raise exceptions.NotFound(
209 "an encryption session can't be started")) 219 _(
220 "No encryption plugin is registered, "
221 "an encryption session can't be started"
222 )
223 )
210 224
211 if namespace is None: 225 if namespace is None:
212 plugin = self.plugins[0] 226 plugin = self.plugins[0]
213 else: 227 else:
214 plugin = self.get_plugin(namespace) 228 plugin = self.get_plugin(namespace)
216 bare_jid = entity.userhostJID() 230 bare_jid = entity.userhostJID()
217 if bare_jid in self._sessions: 231 if bare_jid in self._sessions:
218 # we have already an encryption session with this contact 232 # we have already an encryption session with this contact
219 former_plugin = self._sessions[bare_jid]["plugin"] 233 former_plugin = self._sessions[bare_jid]["plugin"]
220 if former_plugin.namespace == namespace: 234 if former_plugin.namespace == namespace:
221 log.info(_("Session with {bare_jid} is already encrypted with {name}. " 235 log.info(
222 "Nothing to do.").format( 236 _(
223 bare_jid=bare_jid, name=former_plugin.name)) 237 "Session with {bare_jid} is already encrypted with {name}. "
238 "Nothing to do."
239 ).format(bare_jid=bare_jid, name=former_plugin.name)
240 )
224 return 241 return
225 242
226 if replace: 243 if replace:
227 # there is a conflict, but replacement is requested 244 # there is a conflict, but replacement is requested
228 # so we stop previous encryption to use new one 245 # so we stop previous encryption to use new one
229 del self._sessions[bare_jid] 246 del self._sessions[bare_jid]
230 await self._stop_encryption(former_plugin, entity) 247 await self._stop_encryption(former_plugin, entity)
231 else: 248 else:
232 msg = (_("Session with {bare_jid} is already encrypted with {name}. " 249 msg = _(
233 "Please stop encryption session before changing algorithm.") 250 "Session with {bare_jid} is already encrypted with {name}. "
234 .format(bare_jid=bare_jid, name=plugin.name)) 251 "Please stop encryption session before changing algorithm."
252 ).format(bare_jid=bare_jid, name=plugin.name)
235 log.warning(msg) 253 log.warning(msg)
236 raise exceptions.ConflictError(msg) 254 raise exceptions.ConflictError(msg)
237 255
238 data = {"plugin": plugin} 256 data = {"plugin": plugin}
239 if plugin.directed: 257 if plugin.directed:
240 if not entity.resource: 258 if not entity.resource:
241 entity.resource = self.host.memory.main_resource_get(self.client, entity) 259 entity.resource = self.host.memory.main_resource_get(self.client, entity)
242 if not entity.resource: 260 if not entity.resource:
243 raise exceptions.NotFound( 261 raise exceptions.NotFound(
244 _("No resource found for {destinee}, can't encrypt with {name}") 262 _(
245 .format(destinee=entity.full(), name=plugin.name)) 263 "No resource found for {destinee}, can't encrypt with {name}"
246 log.info(_("No resource specified to encrypt with {name}, using " 264 ).format(destinee=entity.full(), name=plugin.name)
247 "{destinee}.").format(destinee=entity.full(), 265 )
248 name=plugin.name)) 266 log.info(
267 _(
268 "No resource specified to encrypt with {name}, using "
269 "{destinee}."
270 ).format(destinee=entity.full(), name=plugin.name)
271 )
249 # indicate that we encrypt only for some devices 272 # indicate that we encrypt only for some devices
250 directed_devices = data['directed_devices'] = [entity.resource] 273 directed_devices = data["directed_devices"] = [entity.resource]
251 elif entity.resource: 274 elif entity.resource:
252 raise ValueError(_("{name} encryption must be used with bare jids.")) 275 raise ValueError(_("{name} encryption must be used with bare jids."))
253 276
254 await self._start_encryption(plugin, entity) 277 await self._start_encryption(plugin, entity)
255 self._sessions[entity.userhostJID()] = data 278 self._sessions[entity.userhostJID()] = data
256 log.info(_("Encryption session has been set for {entity_jid} with " 279 log.info(
257 "{encryption_name}").format( 280 _(
258 entity_jid=entity.full(), encryption_name=plugin.name)) 281 "Encryption session has been set for {entity_jid} with "
282 "{encryption_name}"
283 ).format(entity_jid=entity.full(), encryption_name=plugin.name)
284 )
259 self.host.bridge.message_encryption_started( 285 self.host.bridge.message_encryption_started(
260 entity.full(), 286 entity.full(), self.get_bridge_data(data), self.client.profile
261 self.get_bridge_data(data), 287 )
262 self.client.profile) 288 msg = D_(
263 msg = D_("Encryption session started: your messages with {destinee} are " 289 "Encryption session started: your messages with {destinee} are "
264 "now end to end encrypted using {name} algorithm.").format( 290 "now end to end encrypted using {name} algorithm."
265 destinee=entity.full(), name=plugin.name) 291 ).format(destinee=entity.full(), name=plugin.name)
266 directed_devices = data.get('directed_devices') 292 directed_devices = data.get("directed_devices")
267 if directed_devices: 293 if directed_devices:
268 msg += "\n" + D_("Message are encrypted only for {nb_devices} device(s): " 294 msg += "\n" + D_(
269 "{devices_list}.").format( 295 "Message are encrypted only for {nb_devices} device(s): "
270 nb_devices=len(directed_devices), 296 "{devices_list}."
271 devices_list = ', '.join(directed_devices)) 297 ).format(
298 nb_devices=len(directed_devices), devices_list=", ".join(directed_devices)
299 )
272 300
273 self.client.feedback(bare_jid, msg) 301 self.client.feedback(bare_jid, msg)
274 302
275 async def stop(self, entity, namespace=None): 303 async def stop(self, entity, namespace=None):
276 """Stop an encryption session with an entity 304 """Stop an encryption session with an entity
281 when specified, used to check that we stop the right encryption session 309 when specified, used to check that we stop the right encryption session
282 """ 310 """
283 session = self.getSession(entity.userhostJID()) 311 session = self.getSession(entity.userhostJID())
284 if not session: 312 if not session:
285 raise failure.Failure( 313 raise failure.Failure(
286 exceptions.NotFound(_("There is no encryption session with this " 314 exceptions.NotFound(
287 "entity."))) 315 _("There is no encryption session with this " "entity.")
288 plugin = session['plugin'] 316 )
317 )
318 plugin = session["plugin"]
289 if namespace is not None and plugin.namespace != namespace: 319 if namespace is not None and plugin.namespace != namespace:
290 raise exceptions.InternalError(_( 320 raise exceptions.InternalError(
291 "The encryption session is not run with the expected plugin: encrypted " 321 _(
292 "with {current_name} and was expecting {expected_name}").format( 322 "The encryption session is not run with the expected plugin: encrypted "
293 current_name=session['plugin'].namespace, 323 "with {current_name} and was expecting {expected_name}"
294 expected_name=namespace)) 324 ).format(
325 current_name=session["plugin"].namespace, expected_name=namespace
326 )
327 )
295 if entity.resource: 328 if entity.resource:
296 try: 329 try:
297 directed_devices = session['directed_devices'] 330 directed_devices = session["directed_devices"]
298 except KeyError: 331 except KeyError:
299 raise exceptions.NotFound(_( 332 raise exceptions.NotFound(
300 "There is a session for the whole entity (i.e. all devices of the " 333 _(
301 "entity), not a directed one. Please use bare jid if you want to " 334 "There is a session for the whole entity (i.e. all devices of the "
302 "stop the whole encryption with this entity.")) 335 "entity), not a directed one. Please use bare jid if you want to "
336 "stop the whole encryption with this entity."
337 )
338 )
303 339
304 try: 340 try:
305 directed_devices.remove(entity.resource) 341 directed_devices.remove(entity.resource)
306 except ValueError: 342 except ValueError:
307 raise exceptions.NotFound(_("There is no directed session with this " 343 raise exceptions.NotFound(
308 "entity.")) 344 _("There is no directed session with this " "entity.")
345 )
309 else: 346 else:
310 if not directed_devices: 347 if not directed_devices:
311 # if we have no more directed device sessions, 348 # if we have no more directed device sessions,
312 # we stop the whole session 349 # we stop the whole session
313 # see comment below for deleting session before stopping encryption 350 # see comment below for deleting session before stopping encryption
317 # plugin's stop_encryption may call stop again (that's the case with OTR) 354 # plugin's stop_encryption may call stop again (that's the case with OTR)
318 # so we need to remove plugin from session before calling self._stop_encryption 355 # so we need to remove plugin from session before calling self._stop_encryption
319 del self._sessions[entity.userhostJID()] 356 del self._sessions[entity.userhostJID()]
320 await self._stop_encryption(plugin, entity) 357 await self._stop_encryption(plugin, entity)
321 358
322 log.info(_("encryption session stopped with entity {entity}").format( 359 log.info(
323 entity=entity.full())) 360 _("encryption session stopped with entity {entity}").format(
361 entity=entity.full()
362 )
363 )
324 self.host.bridge.message_encryption_stopped( 364 self.host.bridge.message_encryption_stopped(
325 entity.full(), 365 entity.full(),
326 {'name': plugin.name, 366 {
327 'namespace': plugin.namespace, 367 "name": plugin.name,
368 "namespace": plugin.namespace,
328 }, 369 },
329 self.client.profile) 370 self.client.profile,
330 msg = D_("Encryption session finished: your messages with {destinee} are " 371 )
331 "NOT end to end encrypted anymore.\nYour server administrators or " 372 msg = D_(
332 "{destinee} server administrators will be able to read them.").format( 373 "Encryption session finished: your messages with {destinee} are "
333 destinee=entity.full()) 374 "NOT end to end encrypted anymore.\nYour server administrators or "
375 "{destinee} server administrators will be able to read them."
376 ).format(destinee=entity.full())
334 377
335 self.client.feedback(entity, msg) 378 self.client.feedback(entity, msg)
336 379
337 def getSession(self, entity: jid.JID) -> Optional[EncryptionSession]: 380 def getSession(self, entity: jid.JID) -> Optional[EncryptionSession]:
338 """Get encryption session for this contact 381 """Get encryption session for this contact
373 """ 416 """
374 if namespace is None: 417 if namespace is None:
375 session = self.getSession(entity_jid) 418 session = self.getSession(entity_jid)
376 if not session: 419 if not session:
377 raise exceptions.NotFound( 420 raise exceptions.NotFound(
378 "No encryption session currently active for {entity_jid}" 421 "No encryption session currently active for {entity_jid}".format(
379 .format(entity_jid=entity_jid.full())) 422 entity_jid=entity_jid.full()
380 plugin = session['plugin'] 423 )
424 )
425 plugin = session["plugin"]
381 else: 426 else:
382 plugin = self.get_plugin(namespace) 427 plugin = self.get_plugin(namespace)
383 try: 428 try:
384 get_trust_ui = plugin.instance.get_trust_ui 429 get_trust_ui = plugin.instance.get_trust_ui
385 except AttributeError: 430 except AttributeError:
386 raise NotImplementedError( 431 raise NotImplementedError(
387 "Encryption plugin doesn't handle trust management UI") 432 "Encryption plugin doesn't handle trust management UI"
433 )
388 else: 434 else:
389 return utils.as_deferred(get_trust_ui, self.client, entity_jid) 435 return utils.as_deferred(get_trust_ui, self.client, entity_jid)
390 436
391 ## Menus ## 437 ## Menus ##
392 438
393 @classmethod 439 @classmethod
394 def _import_menus(cls, host): 440 def _import_menus(cls, host):
395 host.import_menu( 441 host.import_menu(
396 (D_("Encryption"), D_("unencrypted (plain text)")), 442 (D_("Encryption"), D_("unencrypted (plain text)")),
397 partial(cls._on_menu_unencrypted, host=host), 443 partial(cls._on_menu_unencrypted, host=host),
398 security_limit=0, 444 security_limit=0,
399 help_string=D_("End encrypted session"), 445 help_string=D_("End encrypted session"),
400 type_=C.MENU_SINGLE, 446 type_=C.MENU_SINGLE,
401 ) 447 )
402 for plg in cls.getPlugins(): 448 for plg in cls.getPlugins():
403 host.import_menu( 449 host.import_menu(
404 (D_("Encryption"), plg.name), 450 (D_("Encryption"), plg.name),
405 partial(cls._on_menu_name, host=host, plg=plg), 451 partial(cls._on_menu_name, host=host, plg=plg),
406 security_limit=0, 452 security_limit=0,
407 help_string=D_("Start {name} session").format(name=plg.name), 453 help_string=D_("Start {name} session").format(name=plg.name),
408 type_=C.MENU_SINGLE, 454 type_=C.MENU_SINGLE,
409 ) 455 )
410 host.import_menu( 456 host.import_menu(
411 (D_("Encryption"), D_("⛨ {name} trust").format(name=plg.name)), 457 (D_("Encryption"), D_("⛨ {name} trust").format(name=plg.name)),
412 partial(cls._on_menu_trust, host=host, plg=plg), 458 partial(cls._on_menu_trust, host=host, plg=plg),
413 security_limit=0, 459 security_limit=0,
414 help_string=D_("Manage {name} trust").format(name=plg.name), 460 help_string=D_("Manage {name} trust").format(name=plg.name),
415 type_=C.MENU_SINGLE, 461 type_=C.MENU_SINGLE,
416 ) 462 )
417 463
418 @classmethod 464 @classmethod
419 def _on_menu_unencrypted(cls, data, host, profile): 465 def _on_menu_unencrypted(cls, data, host, profile):
420 client = host.get_client(profile) 466 client = host.get_client(profile)
421 peer_jid = jid.JID(data['jid']).userhostJID() 467 peer_jid = jid.JID(data["jid"]).userhostJID()
422 d = defer.ensureDeferred(client.encryption.stop(peer_jid)) 468 d = defer.ensureDeferred(client.encryption.stop(peer_jid))
423 d.addCallback(lambda __: {}) 469 d.addCallback(lambda __: {})
424 return d 470 return d
425 471
426 @classmethod 472 @classmethod
427 def _on_menu_name(cls, data, host, plg, profile): 473 def _on_menu_name(cls, data, host, plg, profile):
428 client = host.get_client(profile) 474 client = host.get_client(profile)
429 peer_jid = jid.JID(data['jid']) 475 peer_jid = jid.JID(data["jid"])
430 if not plg.directed: 476 if not plg.directed:
431 peer_jid = peer_jid.userhostJID() 477 peer_jid = peer_jid.userhostJID()
432 d = defer.ensureDeferred( 478 d = defer.ensureDeferred(
433 client.encryption.start(peer_jid, plg.namespace, replace=True)) 479 client.encryption.start(peer_jid, plg.namespace, replace=True)
480 )
434 d.addCallback(lambda __: {}) 481 d.addCallback(lambda __: {})
435 return d 482 return d
436 483
437 @classmethod 484 @classmethod
438 @defer.inlineCallbacks 485 @defer.inlineCallbacks
439 def _on_menu_trust(cls, data, host, plg, profile): 486 def _on_menu_trust(cls, data, host, plg, profile):
440 client = host.get_client(profile) 487 client = host.get_client(profile)
441 peer_jid = jid.JID(data['jid']).userhostJID() 488 peer_jid = jid.JID(data["jid"]).userhostJID()
442 ui = yield client.encryption.get_trust_ui(peer_jid, plg.namespace) 489 ui = yield client.encryption.get_trust_ui(peer_jid, plg.namespace)
443 defer.returnValue({'xmlui': ui.toXml()}) 490 defer.returnValue({"xmlui": ui.toXml()})
444 491
445 ## Triggers ## 492 ## Triggers ##
446 493
447 def set_encryption_flag(self, mess_data): 494 def set_encryption_flag(self, mess_data):
448 """Set "encryption" key in mess_data if session with destinee is encrypted""" 495 """Set "encryption" key in mess_data if session with destinee is encrypted"""
449 to_jid = mess_data['to'] 496 to_jid = mess_data["to"]
450 encryption = self._sessions.get(to_jid.userhostJID()) 497 encryption = self._sessions.get(to_jid.userhostJID())
451 if encryption is not None: 498 if encryption is not None:
452 plugin = encryption['plugin'] 499 plugin = encryption["plugin"]
453 if mess_data["type"] == "groupchat" and plugin.directed: 500 if mess_data["type"] == "groupchat" and plugin.directed:
454 raise exceptions.InternalError( 501 raise exceptions.InternalError(
455 f"encryption flag must not be set for groupchat if encryption algorithm " 502 f"encryption flag must not be set for groupchat if encryption algorithm "
456 f"({encryption['plugin'].name}) is directed!") 503 f"({encryption['plugin'].name}) is directed!"
504 )
457 mess_data[C.MESS_KEY_ENCRYPTION] = encryption 505 mess_data[C.MESS_KEY_ENCRYPTION] = encryption
458 self.mark_as_encrypted(mess_data, plugin.namespace) 506 self.mark_as_encrypted(mess_data, plugin.namespace)
459 507
460 ## Misc ## 508 ## Misc ##
461 509
465 This should be used in the post_treat workflow of message_received trigger of 513 This should be used in the post_treat workflow of message_received trigger of
466 the plugin 514 the plugin
467 @param mess_data(dict): message data as used in post treat workflow 515 @param mess_data(dict): message data as used in post treat workflow
468 @param namespace(str): namespace of the algorithm used for encrypting the message 516 @param namespace(str): namespace of the algorithm used for encrypting the message
469 """ 517 """
470 mess_data['extra'][C.MESS_KEY_ENCRYPTED] = True 518 mess_data["extra"][C.MESS_KEY_ENCRYPTED] = True
471 from_bare_jid = mess_data['from'].userhostJID() 519 from_bare_jid = mess_data["from"].userhostJID()
472 if from_bare_jid != self.client.jid.userhostJID(): 520 if from_bare_jid != self.client.jid.userhostJID():
473 session = self.getSession(from_bare_jid) 521 session = self.getSession(from_bare_jid)
474 if session is None: 522 if session is None:
475 # if we are currently unencrypted, we start a session automatically 523 # if we are currently unencrypted, we start a session automatically
476 # to avoid sending unencrypted messages in an encrypted context 524 # to avoid sending unencrypted messages in an encrypted context
477 log.info(_( 525 log.info(
478 "Starting e2e session with {peer_jid} as we receive encrypted " 526 _(
479 "messages") 527 "Starting e2e session with {peer_jid} as we receive encrypted "
480 .format(peer_jid=from_bare_jid) 528 "messages"
529 ).format(peer_jid=from_bare_jid)
481 ) 530 )
482 defer.ensureDeferred(self.start(from_bare_jid, namespace)) 531 defer.ensureDeferred(self.start(from_bare_jid, namespace))
483 532
484 return mess_data 533 return mess_data
485 534
486 def is_encryption_requested( 535 def is_encryption_requested(
487 self, 536 self, mess_data: MessageData, namespace: Optional[str] = None
488 mess_data: MessageData,
489 namespace: Optional[str] = None
490 ) -> bool: 537 ) -> bool:
491 """Helper method to check if encryption is requested in an outgoind message 538 """Helper method to check if encryption is requested in an outgoind message
492 539
493 @param mess_data: message data for outgoing message 540 @param mess_data: message data for outgoing message
494 @param namespace: if set, check if encryption is requested for the algorithm 541 @param namespace: if set, check if encryption is requested for the algorithm
497 """ 544 """
498 encryption = mess_data.get(C.MESS_KEY_ENCRYPTION) 545 encryption = mess_data.get(C.MESS_KEY_ENCRYPTION)
499 if encryption is None: 546 if encryption is None:
500 return False 547 return False
501 # we get plugin even if namespace is None to be sure that the key exists 548 # we get plugin even if namespace is None to be sure that the key exists
502 plugin = encryption['plugin'] 549 plugin = encryption["plugin"]
503 if namespace is None: 550 if namespace is None:
504 return True 551 return True
505 return plugin.namespace == namespace 552 return plugin.namespace == namespace
506 553
507 def isEncrypted(self, mess_data): 554 def isEncrypted(self, mess_data):
508 """Helper method to check if a message has the e2e encrypted flag 555 """Helper method to check if a message has the e2e encrypted flag
509 556
510 @param mess_data(dict): message data 557 @param mess_data(dict): message data
511 @return (bool): True if the encrypted flag is present 558 @return (bool): True if the encrypted flag is present
512 """ 559 """
513 return mess_data['extra'].get(C.MESS_KEY_ENCRYPTED, False) 560 return mess_data["extra"].get(C.MESS_KEY_ENCRYPTED, False)
514
515 561
516 def mark_as_trusted(self, mess_data): 562 def mark_as_trusted(self, mess_data):
517 """Helper methor to mark a message as sent from a trusted entity. 563 """Helper methor to mark a message as sent from a trusted entity.
518 564
519 This should be used in the post_treat workflow of message_received trigger of 565 This should be used in the post_treat workflow of message_received trigger of
528 574
529 This should be used in the post_treat workflow of message_received trigger of 575 This should be used in the post_treat workflow of message_received trigger of
530 the plugin 576 the plugin
531 @param mess_data(dict): message data as used in post treat workflow 577 @param mess_data(dict): message data as used in post treat workflow
532 """ 578 """
533 mess_data['trusted'] = False 579 mess_data["trusted"] = False
534 return mess_data 580 return mess_data