Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0060.py @ 3934:e345d93fb6e5
plugin OXPS: OpenPGP for XMPP Pubsub implementation:
OpenPGP for XMPP Pubsub (https://xmpp.org/extensions/inbox/pubsub-encryption.html,
currently a protoXEP) is implemented and activated when `encrypted` is set to `True` in
pubsub's `extra` data.
On item retrieval, the decryption is transparent if the key is known, except if the
`decrypt` key in `extra` is set to `False` (notably useful when one wants to checks that
data is well encrypted).
Methods and corresponding bridge methods have been implemented to manage shared secrets
(to share, revoke or rotate the secrets).
plugin XEP-0060's `XEP-0060_publish` trigger point as been move before actual publish so
item can be modified (here e2ee) by the triggers. A new `XEP-0060_items` trigger point has
also been added.
`encrypted` flag can be used with plugin XEP-0277's microblog data
rel 380
author | Goffi <goffi@goffi.org> |
---|---|
date | Sat, 15 Oct 2022 20:36:53 +0200 |
parents | cecf45416403 |
children | cd4d95b3fed3 |
comparison
equal
deleted
inserted
replaced
3933:cecf45416403 | 3934:e345d93fb6e5 |
---|---|
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | 18 |
19 | 19 |
20 from collections import namedtuple | 20 from collections import namedtuple |
21 from functools import reduce | 21 from functools import reduce |
22 from typing import Any, Dict, Iterable, List, Optional, Tuple, Union, Callable | 22 from typing import Any, Callable, Dict, Iterable, List, Optional, Set, Tuple, Union |
23 import urllib.error | 23 import urllib.error |
24 import urllib.parse | 24 import urllib.parse |
25 import urllib.request | 25 import urllib.request |
26 | 26 |
27 from twisted.internet import defer, reactor | 27 from twisted.internet import defer, reactor |
656 client: SatXMPPEntity, | 656 client: SatXMPPEntity, |
657 service: jid.JID, | 657 service: jid.JID, |
658 nodeIdentifier: str, | 658 nodeIdentifier: str, |
659 items: Optional[List[domish.Element]] = None, | 659 items: Optional[List[domish.Element]] = None, |
660 options: Optional[dict] = None, | 660 options: Optional[dict] = None, |
661 sender: Optional[jid.JID] = None | 661 sender: Optional[jid.JID] = None, |
662 extra: Optional[Dict[str, Any]] = None | |
662 ) -> domish.Element: | 663 ) -> domish.Element: |
663 """Publish pubsub items | 664 """Publish pubsub items |
664 | 665 |
665 @param sender: sender of the request, | 666 @param sender: sender of the request, |
666 client.jid will be used if nto set | 667 client.jid will be used if nto set |
668 @param extra: extra data | |
669 not used directly by ``publish``, but may be used in triggers | |
667 @return: IQ result stanza | 670 @return: IQ result stanza |
671 @trigger XEP-0060_publish: called just before publication. | |
672 if it returns False, extra must have a "iq_result_elt" key set with | |
673 domish.Element to return. | |
668 """ | 674 """ |
669 if sender is None: | 675 if sender is None: |
670 sender = client.jid | 676 sender = client.jid |
677 if extra is None: | |
678 extra = {} | |
679 if not await self.host.trigger.asyncPoint( | |
680 "XEP-0060_publish", client, service, nodeIdentifier, items, options, sender, | |
681 extra | |
682 ): | |
683 return extra["iq_result_elt"] | |
671 iq_result_elt = await client.pubsub_client.publish( | 684 iq_result_elt = await client.pubsub_client.publish( |
672 service, nodeIdentifier, items, sender, | 685 service, nodeIdentifier, items, sender, |
673 options=options | 686 options=options |
674 ) | |
675 | |
676 await self.host.trigger.asyncPoint( | |
677 "XEP-0060_publish", client, service, nodeIdentifier, items, options, | |
678 iq_result_elt | |
679 ) | 687 ) |
680 return iq_result_elt | 688 return iq_result_elt |
681 | 689 |
682 def _unwrapMAMMessage(self, message_elt): | 690 def _unwrapMAMMessage(self, message_elt): |
683 try: | 691 try: |
766 if not cont: | 774 if not cont: |
767 return ret | 775 return ret |
768 try: | 776 try: |
769 mam_query = extra["mam"] | 777 mam_query = extra["mam"] |
770 except KeyError: | 778 except KeyError: |
771 d = client.pubsub_client.items( | 779 d = defer.ensureDeferred(client.pubsub_client.items( |
772 service = service, | 780 service = service, |
773 nodeIdentifier = node, | 781 nodeIdentifier = node, |
774 maxItems = max_items, | 782 maxItems = max_items, |
775 subscriptionIdentifier = sub_id, | 783 subscriptionIdentifier = sub_id, |
776 sender = None, | 784 sender = None, |
777 itemIdentifiers = item_ids, | 785 itemIdentifiers = item_ids, |
778 orderBy = extra.get(C.KEY_ORDER_BY), | 786 orderBy = extra.get(C.KEY_ORDER_BY), |
779 rsm_request = rsm_request | 787 rsm_request = rsm_request, |
780 ) | 788 extra = extra |
789 )) | |
781 # we have no MAM data here, so we add None | 790 # we have no MAM data here, so we add None |
782 d.addErrback(sat_defer.stanza2NotFound) | 791 d.addErrback(sat_defer.stanza2NotFound) |
783 d.addTimeout(TIMEOUT, reactor) | 792 d.addTimeout(TIMEOUT, reactor) |
784 items, rsm_response = await d | 793 items, rsm_response = await d |
785 mam_response = None | 794 mam_response = None |
1650 rsm.PubSubClient.__init__(self) | 1659 rsm.PubSubClient.__init__(self) |
1651 | 1660 |
1652 def connectionInitialized(self): | 1661 def connectionInitialized(self): |
1653 rsm.PubSubClient.connectionInitialized(self) | 1662 rsm.PubSubClient.connectionInitialized(self) |
1654 | 1663 |
1664 async def items( | |
1665 self, | |
1666 service: Optional[jid.JID], | |
1667 nodeIdentifier: str, | |
1668 maxItems: Optional[int] = None, | |
1669 subscriptionIdentifier: Optional[str] = None, | |
1670 sender: Optional[jid.JID] = None, | |
1671 itemIdentifiers: Optional[Set[str]] = None, | |
1672 orderBy: Optional[List[str]] = None, | |
1673 rsm_request: Optional[rsm.RSMRequest] = None, | |
1674 extra: Optional[Dict[str, Any]] = None, | |
1675 ): | |
1676 if extra is None: | |
1677 extra = {} | |
1678 items, rsm_response = await super().items( | |
1679 service, nodeIdentifier, maxItems, subscriptionIdentifier, sender, | |
1680 itemIdentifiers, orderBy, rsm_request | |
1681 ) | |
1682 # items must be returned, thus this async point can't stop the workflow (but it | |
1683 # can modify returned items) | |
1684 await self.host.trigger.asyncPoint( | |
1685 "XEP-0060_items", self.parent, service, nodeIdentifier, items, rsm_response, | |
1686 extra | |
1687 ) | |
1688 return items, rsm_response | |
1689 | |
1655 def _getNodeCallbacks(self, node, event): | 1690 def _getNodeCallbacks(self, node, event): |
1656 """Generate callbacks from given node and event | 1691 """Generate callbacks from given node and event |
1657 | 1692 |
1658 @param node(unicode): node used for the item | 1693 @param node(unicode): node used for the item |
1659 any registered node which prefix the node will match | 1694 any registered node which prefix the node will match |