comparison sat/plugins/plugin_sec_oxps.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 9badc46c5481
children c23cad65ae99
comparison
equal deleted inserted replaced
4036:c4464d7ae97b 4037:524856bd7b19
81 class PubsubEncryption: 81 class PubsubEncryption:
82 namespace = NS_OXPS 82 namespace = NS_OXPS
83 83
84 def __init__(self, host): 84 def __init__(self, host):
85 log.info(_("OpenPGP for XMPP Pubsub plugin initialization")) 85 log.info(_("OpenPGP for XMPP Pubsub plugin initialization"))
86 host.registerNamespace("oxps", NS_OXPS) 86 host.register_namespace("oxps", NS_OXPS)
87 self.host = host 87 self.host = host
88 self._p = host.plugins["XEP-0060"] 88 self._p = host.plugins["XEP-0060"]
89 self._h = host.plugins["XEP-0334"] 89 self._h = host.plugins["XEP-0334"]
90 self._ox = host.plugins["XEP-0373"] 90 self._ox = host.plugins["XEP-0373"]
91 host.trigger.add("XEP-0060_publish", self._publish_trigger) 91 host.trigger.add("XEP-0060_publish", self._publish_trigger)
92 host.trigger.add("XEP-0060_items", self._items_trigger) 92 host.trigger.add("XEP-0060_items", self._items_trigger)
93 host.trigger.add( 93 host.trigger.add(
94 "messageReceived", 94 "messageReceived",
95 self._message_received_trigger, 95 self._message_received_trigger,
96 ) 96 )
97 host.bridge.addMethod( 97 host.bridge.add_method(
98 "psSecretShare", 98 "ps_secret_share",
99 ".plugin", 99 ".plugin",
100 in_sign="sssass", 100 in_sign="sssass",
101 out_sign="", 101 out_sign="",
102 method=self._ps_secret_share, 102 method=self._ps_secret_share,
103 async_=True, 103 async_=True,
104 ) 104 )
105 host.bridge.addMethod( 105 host.bridge.add_method(
106 "psSecretRevoke", 106 "ps_secret_revoke",
107 ".plugin", 107 ".plugin",
108 in_sign="sssass", 108 in_sign="sssass",
109 out_sign="", 109 out_sign="",
110 method=self._ps_secret_revoke, 110 method=self._ps_secret_revoke,
111 async_=True, 111 async_=True,
112 ) 112 )
113 host.bridge.addMethod( 113 host.bridge.add_method(
114 "psSecretRotate", 114 "ps_secret_rotate",
115 ".plugin", 115 ".plugin",
116 in_sign="ssass", 116 in_sign="ssass",
117 out_sign="", 117 out_sign="",
118 method=self._ps_secret_rotate, 118 method=self._ps_secret_rotate,
119 async_=True, 119 async_=True,
120 ) 120 )
121 host.bridge.addMethod( 121 host.bridge.add_method(
122 "psSecretsList", 122 "ps_secrets_list",
123 ".plugin", 123 ".plugin",
124 in_sign="sss", 124 in_sign="sss",
125 out_sign="s", 125 out_sign="s",
126 method=self._ps_secrets_list, 126 method=self._ps_secrets_list,
127 async_=True, 127 async_=True,
128 ) 128 )
129 129
130 def getHandler(self, client): 130 def get_handler(self, client):
131 return PubsubEncryption_Handler() 131 return PubsubEncryption_Handler()
132 132
133 async def profileConnecting(self, client): 133 async def profile_connecting(self, client):
134 client.__storage = persistent.LazyPersistentBinaryDict( 134 client.__storage = persistent.LazyPersistentBinaryDict(
135 IMPORT_NAME, client.profile 135 IMPORT_NAME, client.profile
136 ) 136 )
137 # cache to avoid useless DB access, and to avoid race condition by ensuring that 137 # cache to avoid useless DB access, and to avoid race condition by ensuring that
138 # the same shared_secrets instance is always used for a given node. 138 # the same shared_secrets instance is always used for a given node.
237 recipients: List[str], 237 recipients: List[str],
238 profile_key: str 238 profile_key: str
239 ) -> defer.Deferred: 239 ) -> defer.Deferred:
240 return defer.ensureDeferred( 240 return defer.ensureDeferred(
241 self.revoke( 241 self.revoke(
242 self.host.getClient(profile_key), 242 self.host.get_client(profile_key),
243 jid.JID(service) if service else None, 243 jid.JID(service) if service else None,
244 node, 244 node,
245 secret_id, 245 secret_id,
246 [jid.JID(r) for r in recipients] or None, 246 [jid.JID(r) for r in recipients] or None,
247 ) 247 )
265 entities known to have the shared secret will be notified. 265 entities known to have the shared secret will be notified.
266 Use empty list if you don't want to notify anybody (not recommended) 266 Use empty list if you don't want to notify anybody (not recommended)
267 """ 267 """
268 if service is None: 268 if service is None:
269 service = client.jid.userhostJID() 269 service = client.jid.userhostJID()
270 node_uri = uri.buildXMPPUri("pubsub", path=service.full(), node=node) 270 node_uri = uri.build_xmpp_uri("pubsub", path=service.full(), node=node)
271 shared_secrets = await self.load_secrets(client, node_uri) 271 shared_secrets = await self.load_secrets(client, node_uri)
272 if not shared_secrets: 272 if not shared_secrets:
273 raise exceptions.NotFound(f"No shared secret is known for {node_uri}") 273 raise exceptions.NotFound(f"No shared secret is known for {node_uri}")
274 try: 274 try:
275 shared_secret = shared_secrets[secret_id] 275 shared_secret = shared_secrets[secret_id]
325 ) 325 )
326 message_elt = domish.Element((None, "message")) 326 message_elt = domish.Element((None, "message"))
327 message_elt["from"] = client.jid.full() 327 message_elt["from"] = client.jid.full()
328 message_elt["to"] = recipient.full() 328 message_elt["to"] = recipient.full()
329 message_elt.addChild((openpgp_elt)) 329 message_elt.addChild((openpgp_elt))
330 self._h.addHintElements(message_elt, [self._h.HINT_STORE]) 330 self._h.add_hint_elements(message_elt, [self._h.HINT_STORE])
331 client.send(message_elt) 331 client.send(message_elt)
332 332
333 def _ps_secret_share( 333 def _ps_secret_share(
334 self, 334 self,
335 recipient: str, 335 recipient: str,
338 secret_ids: List[str], 338 secret_ids: List[str],
339 profile_key: str 339 profile_key: str
340 ) -> defer.Deferred: 340 ) -> defer.Deferred:
341 return defer.ensureDeferred( 341 return defer.ensureDeferred(
342 self.share_secrets( 342 self.share_secrets(
343 self.host.getClient(profile_key), 343 self.host.get_client(profile_key),
344 jid.JID(recipient), 344 jid.JID(recipient),
345 jid.JID(service) if service else None, 345 jid.JID(service) if service else None,
346 node, 346 node,
347 secret_ids or None, 347 secret_ids or None,
348 ) 348 )
375 ) 375 )
376 message_elt = domish.Element((None, "message")) 376 message_elt = domish.Element((None, "message"))
377 message_elt["from"] = client.jid.full() 377 message_elt["from"] = client.jid.full()
378 message_elt["to"] = recipient.full() 378 message_elt["to"] = recipient.full()
379 message_elt.addChild((openpgp_elt)) 379 message_elt.addChild((openpgp_elt))
380 self._h.addHintElements(message_elt, [self._h.HINT_STORE]) 380 self._h.add_hint_elements(message_elt, [self._h.HINT_STORE])
381 client.send(message_elt) 381 client.send(message_elt)
382 shared_secret.shared_with.add(recipient) 382 shared_secret.shared_with.add(recipient)
383 383
384 async def share_secrets( 384 async def share_secrets(
385 self, 385 self,
397 @param secret_ids: IDs of the secrets to share, or None to share all known secrets 397 @param secret_ids: IDs of the secrets to share, or None to share all known secrets
398 (disabled or not) 398 (disabled or not)
399 """ 399 """
400 if service is None: 400 if service is None:
401 service = client.jid.userhostJID() 401 service = client.jid.userhostJID()
402 node_uri = uri.buildXMPPUri("pubsub", path=service.full(), node=node) 402 node_uri = uri.build_xmpp_uri("pubsub", path=service.full(), node=node)
403 shared_secrets = await self.load_secrets(client, node_uri) 403 shared_secrets = await self.load_secrets(client, node_uri)
404 if shared_secrets is None: 404 if shared_secrets is None:
405 # no secret shared yet, let's generate one 405 # no secret shared yet, let's generate one
406 shared_secret = self.generate_secret(client) 406 shared_secret = self.generate_secret(client)
407 shared_secrets = {shared_secret.id: shared_secret} 407 shared_secrets = {shared_secret.id: shared_secret}
427 recipients: List[str], 427 recipients: List[str],
428 profile_key: str, 428 profile_key: str,
429 ) -> defer.Deferred: 429 ) -> defer.Deferred:
430 return defer.ensureDeferred( 430 return defer.ensureDeferred(
431 self.rotate_secret( 431 self.rotate_secret(
432 self.host.getClient(profile_key), 432 self.host.get_client(profile_key),
433 jid.JID(service) if service else None, 433 jid.JID(service) if service else None,
434 node, 434 node,
435 [jid.JID(r) for r in recipients] or None 435 [jid.JID(r) for r in recipients] or None
436 ) 436 )
437 ) 437 )
451 if None, all recipients known to have last active shared secret will get the 451 if None, all recipients known to have last active shared secret will get the
452 new secret 452 new secret
453 """ 453 """
454 if service is None: 454 if service is None:
455 service = client.jid.userhostJID() 455 service = client.jid.userhostJID()
456 node_uri = uri.buildXMPPUri("pubsub", path=service.full(), node=node) 456 node_uri = uri.build_xmpp_uri("pubsub", path=service.full(), node=node)
457 shared_secrets = await self.load_secrets(client, node_uri) 457 shared_secrets = await self.load_secrets(client, node_uri)
458 if shared_secrets is None: 458 if shared_secrets is None:
459 shared_secrets = {} 459 shared_secrets = {}
460 for shared_secret in shared_secrets.values(): 460 for shared_secret in shared_secrets.values():
461 if not shared_secret.revoked: 461 if not shared_secret.revoked:
487 node: str, 487 node: str,
488 profile_key: str 488 profile_key: str
489 ) -> defer.Deferred: 489 ) -> defer.Deferred:
490 d = defer.ensureDeferred( 490 d = defer.ensureDeferred(
491 self.list_shared_secrets( 491 self.list_shared_secrets(
492 self.host.getClient(profile_key), 492 self.host.get_client(profile_key),
493 jid.JID(service) if service else None, 493 jid.JID(service) if service else None,
494 node, 494 node,
495 ) 495 )
496 ) 496 )
497 d.addCallback(lambda ret: data_format.serialise(ret)) 497 d.addCallback(lambda ret: data_format.serialise(ret))
510 @return: shared secrets data 510 @return: shared secrets data
511 @raise exceptions.NotFound: no shared secret found for this node 511 @raise exceptions.NotFound: no shared secret found for this node
512 """ 512 """
513 if service is None: 513 if service is None:
514 service = client.jid.userhostJID() 514 service = client.jid.userhostJID()
515 node_uri = uri.buildXMPPUri("pubsub", path=service.full(), node=node) 515 node_uri = uri.build_xmpp_uri("pubsub", path=service.full(), node=node)
516 shared_secrets = await self.load_secrets(client, node_uri) 516 shared_secrets = await self.load_secrets(client, node_uri)
517 if shared_secrets is None: 517 if shared_secrets is None:
518 raise exceptions.NotFound(f"No shared secrets found for {node_uri}") 518 raise exceptions.NotFound(f"No shared secrets found for {node_uri}")
519 return [ 519 return [
520 dataclasses.asdict(s, dict_factory=self.__secrect_dict_factory) 520 dataclasses.asdict(s, dict_factory=self.__secrect_dict_factory)
539 except (KeyError, RuntimeError) as e: 539 except (KeyError, RuntimeError) as e:
540 log.warning( 540 log.warning(
541 f"ignoring invalid <revoke> element: {e}\n{revoke_elt.toXml()}" 541 f"ignoring invalid <revoke> element: {e}\n{revoke_elt.toXml()}"
542 ) 542 )
543 return 543 return
544 node_uri = uri.buildXMPPUri("pubsub", path=service.full(), node=node) 544 node_uri = uri.build_xmpp_uri("pubsub", path=service.full(), node=node)
545 shared_secrets = await self.load_secrets(client, node_uri) 545 shared_secrets = await self.load_secrets(client, node_uri)
546 if shared_secrets is None: 546 if shared_secrets is None:
547 log.warning( 547 log.warning(
548 f"Can't revoke shared secret {secret_id}: no known shared secrets for " 548 f"Can't revoke shared secret {secret_id}: no known shared secrets for "
549 f"{node_uri}" 549 f"{node_uri}"
602 ) 602 )
603 return 603 return
604 shared_secret = SharedSecret( 604 shared_secret = SharedSecret(
605 id=secret_id, key=key, timestamp=timestamp, origin=sender, revoked=revoked 605 id=secret_id, key=key, timestamp=timestamp, origin=sender, revoked=revoked
606 ) 606 )
607 node_uri = uri.buildXMPPUri("pubsub", path=service.full(), node=node) 607 node_uri = uri.build_xmpp_uri("pubsub", path=service.full(), node=node)
608 shared_secrets = await self.load_secrets(client, node_uri) 608 shared_secrets = await self.load_secrets(client, node_uri)
609 if shared_secrets is None: 609 if shared_secrets is None:
610 shared_secrets = {} 610 shared_secrets = {}
611 # no known shared secret yet for this node, we have to trust first user who 611 # no known shared secret yet for this node, we have to trust first user who
612 # send it 612 # send it
634 sender: jid.JID, 634 sender: jid.JID,
635 extra: Dict[str, Any] 635 extra: Dict[str, Any]
636 ) -> bool: 636 ) -> bool:
637 if not items or not extra.get("encrypted"): 637 if not items or not extra.get("encrypted"):
638 return True 638 return True
639 node_uri = uri.buildXMPPUri("pubsub", path=service.full(), node=node) 639 node_uri = uri.build_xmpp_uri("pubsub", path=service.full(), node=node)
640 shared_secrets = await self.load_secrets(client, node_uri) 640 shared_secrets = await self.load_secrets(client, node_uri)
641 if shared_secrets is None: 641 if shared_secrets is None:
642 shared_secrets = {} 642 shared_secrets = {}
643 shared_secret = None 643 shared_secret = None
644 else: 644 else:
711 log.warning( 711 log.warning(
712 f'"key" attribute is missing from encrypted item: {item.toXml()}' 712 f'"key" attribute is missing from encrypted item: {item.toXml()}'
713 ) 713 )
714 continue 714 continue
715 if shared_secrets is None: 715 if shared_secrets is None:
716 node_uri = uri.buildXMPPUri("pubsub", path=service.full(), node=node) 716 node_uri = uri.build_xmpp_uri("pubsub", path=service.full(), node=node)
717 shared_secrets = await self.load_secrets(client, node_uri) 717 shared_secrets = await self.load_secrets(client, node_uri)
718 if shared_secrets is None: 718 if shared_secrets is None:
719 log.warning( 719 log.warning(
720 f"No known shared secret for {node_uri}, can't decrypt" 720 f"No known shared secret for {node_uri}, can't decrypt"
721 ) 721 )