# HG changeset patch # User Goffi # Date 1634283124 -7200 # Node ID cebcb7f56889f900829176bbe3bdf258d073fee6 # Parent bc2e04a4d3c16f98331029c1b5e076fa89473bca backend, delegation: update to XEP-0355 v0.5 (namespace bump) + disco: - delegation now uses namespace `urn:xmpp:delegation:2` - restored node metadata and made it work with PEP - `delegated` attribute is also set on recipient when available (needed to know when a disco query is delegated as the original stanza is lost by wokkel) diff -r bc2e04a4d3c1 -r cebcb7f56889 CHANGELOG --- a/CHANGELOG Thu Oct 14 21:30:33 2021 +0200 +++ b/CHANGELOG Fri Oct 15 09:32:04 2021 +0200 @@ -7,6 +7,7 @@ - XEP-0346 (Form Discovery and Publishing) implementation (replacing the non standard node schema) - environment variables can now be used to set options - service name can now be specified with "service_name" parameter + - namespace delegation update to v0.5 ("urn:xmpp:delegation:2" is now used) - bug fixes v 0.3.0 (16/08/2019) diff -r bc2e04a4d3c1 -r cebcb7f56889 sat_pubsub/backend.py --- a/sat_pubsub/backend.py Thu Oct 14 21:30:33 2021 +0200 +++ b/sat_pubsub/backend.py Fri Oct 15 09:32:04 2021 +0200 @@ -67,7 +67,7 @@ from zope.interface import implementer from twisted.application import service -from twisted.python import components, log +from twisted.python import components, failure, log from twisted.internet import defer, reactor from twisted.words.protocols.jabber.error import StanzaError from twisted.words.protocols.jabber import jid @@ -1638,35 +1638,49 @@ raise exc - def getInfo(self, requestor, service, nodeIdentifier, pep=None, recipient=None): - return [] # FIXME: disabled for now, need to manage PEP + async def _getInfo( + self, + requestor: jid.JID, + service: jid.JID, + nodeIdentifier: str, + pep: bool = False, + recipient: Optional[jid.JID] = None + ) -> Optional[dict]: if not requestor.resource: - # this avoid error when getting a disco request from server during namespace delegation - return [] + # this avoid error when getting a disco request from server during namespace + # delegation + return None info = {} - - def saveType(result): - info['type'] = result - return nodeIdentifier - - def saveMetaData(result): - info['meta-data'] = result + try: + info["type"] = await self.backend.getNodeType(nodeIdentifier, pep, recipient) + info["meta-data"] = await self.backend.getNodeMetaData( + nodeIdentifier, pep, recipient + ) + except error.NodeNotFound: + info["meta-data"] = None + return None + except failure.Failure as e: + self._mapErrors(e) + except Exception as e: + self._mapErrors(failure.Failure(e)) + else: return info - def trapNotFound(failure): - failure.trap(error.NodeNotFound) - return info + def getInfo(self, requestor, service, nodeIdentifier): + try: + pep = service.delegated + except AttributeError: + pep = False + recipient = None + else: + recipient = service if pep else None + return defer.ensureDeferred( + self._getInfo( + requestor, service, nodeIdentifier, pep, recipient + ) + ) - d = defer.succeed(nodeIdentifier) - d.addCallback(self.backend.getNodeType) - d.addCallback(saveType) - d.addCallback(self.backend.getNodeMetaData) - d.addCallback(saveMetaData) - d.addErrback(trapNotFound) - d.addErrback(self._mapErrors) - return d - - def getNodes(self, requestor, service, nodeIdentifier): + async def _getNodes(self, requestor, service, nodeIdentifier): """return nodes for disco#items Pubsub/PEP nodes will be returned if disco node is not specified @@ -1679,25 +1693,35 @@ pep = False if service.resource: - return defer.succeed([]) + return [] if nodeIdentifier: - d = self.backend.getItemsIds(nodeIdentifier, - requestor, - [], - requestor.userhostJID() == service, - None, - None, - pep, - service) + items = await self.backend.getItemsIds( + nodeIdentifier, + requestor, + [], + requestor.userhostJID() == service, + None, + None, + pep, + service + ) # items must be set as name, not node - d.addCallback(lambda items: [(None, item) for item in items]) - + return [(None, item) for item in items] else: - d = self.backend.getNodes(requestor.userhostJID(), - pep, - service) - return d.addErrback(self._mapErrors) + try: + return await self.backend.getNodes( + requestor.userhostJID(), + pep, + service + ) + except failure.Failure as e: + self._mapErrors(e) + except Exception as e: + self._mapErrors(failure.Failure(e)) + + def getNodes(self, requestor, service, nodeIdentifier): + return defer.ensureDeferred(self._getNodes(requestor, service, nodeIdentifier)) def getConfigurationOptions(self): return self.backend.nodeOptions diff -r bc2e04a4d3c1 -r cebcb7f56889 sat_pubsub/delegation.py --- a/sat_pubsub/delegation.py Thu Oct 14 21:30:33 2021 +0200 +++ b/sat_pubsub/delegation.py Fri Oct 15 09:32:04 2021 +0200 @@ -1,7 +1,6 @@ #!/usr/bin/env python3 -#-*- coding: utf-8 -*- # -# Copyright (c) 2015 Jérôme Poisson +# Copyright (c) 2015-2021 Jérôme Poisson # This program is free software: you can redistribute it and/or modify @@ -24,16 +23,16 @@ from wokkel.subprotocols import XMPPHandler from wokkel import pubsub from wokkel import data_form -from wokkel import disco, iwokkel +from wokkel import disco, iwokkel, generic from wokkel.iwokkel import IPubSubService from wokkel import mam from twisted.python import log -from twisted.words.protocols.jabber import jid, error +from twisted.words.protocols.jabber import ijabber, jid, error from twisted.words.protocols.jabber.xmlstream import toResponse from twisted.words.xish import domish from zope.interface import implementer -DELEGATION_NS = 'urn:xmpp:delegation:1' +DELEGATION_NS = 'urn:xmpp:delegation:2' FORWARDED_NS = 'urn:xmpp:forward:0' DELEGATION_ADV_XPATH = '/message/delegation[@xmlns="{}"]'.format(DELEGATION_NS) DELEGATION_FWD_XPATH = '/iq[@type="set"]/delegation[@xmlns="{}"]/forwarded[@xmlns="{}"]'.format(DELEGATION_NS, FORWARDED_NS) @@ -42,7 +41,8 @@ DELEGATION_BARE_SEP = ":bare:" TO_HACK = ((IPubSubService, pubsub, "PubSubRequest"), - (mam.IMAMService, mam, "MAMRequest")) + (mam.IMAMService, mam, "MAMRequest"), + (None, disco, "_DiscoRequest")) class InvalidStanza(Exception): @@ -62,9 +62,10 @@ # As PubSubRequest from sat.tmp.wokkel.pubsub use _request_class while # original wokkel.pubsub use directly pubsub.PubSubRequest, we need to # check which version is used before monkeypatching - for handler in self.parent.handlers: - for service, module, default_base_cls in TO_HACK: - if service.providedBy(handler): + for service, module, default_base_cls in TO_HACK: + module_patched = False + for handler in self.parent.handlers: + if not service or service.providedBy(handler): if hasattr(handler, '_request_class'): request_base_class = handler._request_class else: @@ -87,12 +88,17 @@ delegated = False instance = cls.__base__.fromElement(element) instance.delegated = delegated + try: + instance.recipient.delegated = delegated + except (AttributeError, TypeError): + pass return instance if hasattr(handler, '_request_class'): handler._request_class = RequestWithDelegation - else: + elif not module_patched: setattr(module, default_base_cls, RequestWithDelegation) + module_patched = True DelegationsHandler._service_hacked = True def connectionInitialized(self):