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