comparison sat_pubsub/delegation.py @ 459:cebcb7f56889

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)
author Goffi <goffi@goffi.org>
date Fri, 15 Oct 2021 09:32:04 +0200
parents ccb2a22ea0fc
children 607616f9ef5b
comparison
equal deleted inserted replaced
458:bc2e04a4d3c1 459:cebcb7f56889
1 #!/usr/bin/env python3 1 #!/usr/bin/env python3
2 #-*- coding: utf-8 -*-
3 # 2 #
4 # Copyright (c) 2015 Jérôme Poisson 3 # Copyright (c) 2015-2021 Jérôme Poisson
5 4
6 5
7 # This program is free software: you can redistribute it and/or modify 6 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the GNU Affero General Public License as published by 7 # it under the terms of the GNU Affero General Public License as published by
9 # the Free Software Foundation, either version 3 of the License, or 8 # the Free Software Foundation, either version 3 of the License, or
22 # This module implements XEP-0355 (Namespace delegation) to use SàT Pubsub as PEP service 21 # This module implements XEP-0355 (Namespace delegation) to use SàT Pubsub as PEP service
23 22
24 from wokkel.subprotocols import XMPPHandler 23 from wokkel.subprotocols import XMPPHandler
25 from wokkel import pubsub 24 from wokkel import pubsub
26 from wokkel import data_form 25 from wokkel import data_form
27 from wokkel import disco, iwokkel 26 from wokkel import disco, iwokkel, generic
28 from wokkel.iwokkel import IPubSubService 27 from wokkel.iwokkel import IPubSubService
29 from wokkel import mam 28 from wokkel import mam
30 from twisted.python import log 29 from twisted.python import log
31 from twisted.words.protocols.jabber import jid, error 30 from twisted.words.protocols.jabber import ijabber, jid, error
32 from twisted.words.protocols.jabber.xmlstream import toResponse 31 from twisted.words.protocols.jabber.xmlstream import toResponse
33 from twisted.words.xish import domish 32 from twisted.words.xish import domish
34 from zope.interface import implementer 33 from zope.interface import implementer
35 34
36 DELEGATION_NS = 'urn:xmpp:delegation:1' 35 DELEGATION_NS = 'urn:xmpp:delegation:2'
37 FORWARDED_NS = 'urn:xmpp:forward:0' 36 FORWARDED_NS = 'urn:xmpp:forward:0'
38 DELEGATION_ADV_XPATH = '/message/delegation[@xmlns="{}"]'.format(DELEGATION_NS) 37 DELEGATION_ADV_XPATH = '/message/delegation[@xmlns="{}"]'.format(DELEGATION_NS)
39 DELEGATION_FWD_XPATH = '/iq[@type="set"]/delegation[@xmlns="{}"]/forwarded[@xmlns="{}"]'.format(DELEGATION_NS, FORWARDED_NS) 38 DELEGATION_FWD_XPATH = '/iq[@type="set"]/delegation[@xmlns="{}"]/forwarded[@xmlns="{}"]'.format(DELEGATION_NS, FORWARDED_NS)
40 39
41 DELEGATION_MAIN_SEP = "::" 40 DELEGATION_MAIN_SEP = "::"
42 DELEGATION_BARE_SEP = ":bare:" 41 DELEGATION_BARE_SEP = ":bare:"
43 42
44 TO_HACK = ((IPubSubService, pubsub, "PubSubRequest"), 43 TO_HACK = ((IPubSubService, pubsub, "PubSubRequest"),
45 (mam.IMAMService, mam, "MAMRequest")) 44 (mam.IMAMService, mam, "MAMRequest"),
45 (None, disco, "_DiscoRequest"))
46 46
47 47
48 class InvalidStanza(Exception): 48 class InvalidStanza(Exception):
49 pass 49 pass
50 50
60 """Patch the request classes of services to track delegated stanzas""" 60 """Patch the request classes of services to track delegated stanzas"""
61 # XXX: we need to monkey patch to track origin of the stanza in PubSubRequest. 61 # XXX: we need to monkey patch to track origin of the stanza in PubSubRequest.
62 # As PubSubRequest from sat.tmp.wokkel.pubsub use _request_class while 62 # As PubSubRequest from sat.tmp.wokkel.pubsub use _request_class while
63 # original wokkel.pubsub use directly pubsub.PubSubRequest, we need to 63 # original wokkel.pubsub use directly pubsub.PubSubRequest, we need to
64 # check which version is used before monkeypatching 64 # check which version is used before monkeypatching
65 for handler in self.parent.handlers: 65 for service, module, default_base_cls in TO_HACK:
66 for service, module, default_base_cls in TO_HACK: 66 module_patched = False
67 if service.providedBy(handler): 67 for handler in self.parent.handlers:
68 if not service or service.providedBy(handler):
68 if hasattr(handler, '_request_class'): 69 if hasattr(handler, '_request_class'):
69 request_base_class = handler._request_class 70 request_base_class = handler._request_class
70 else: 71 else:
71 request_base_class = getattr(module, default_base_cls) 72 request_base_class = getattr(module, default_base_cls)
72 73
85 delegated = element.__getattribute__('delegated') 86 delegated = element.__getattribute__('delegated')
86 except AttributeError: 87 except AttributeError:
87 delegated = False 88 delegated = False
88 instance = cls.__base__.fromElement(element) 89 instance = cls.__base__.fromElement(element)
89 instance.delegated = delegated 90 instance.delegated = delegated
91 try:
92 instance.recipient.delegated = delegated
93 except (AttributeError, TypeError):
94 pass
90 return instance 95 return instance
91 96
92 if hasattr(handler, '_request_class'): 97 if hasattr(handler, '_request_class'):
93 handler._request_class = RequestWithDelegation 98 handler._request_class = RequestWithDelegation
94 else: 99 elif not module_patched:
95 setattr(module, default_base_cls, RequestWithDelegation) 100 setattr(module, default_base_cls, RequestWithDelegation)
101 module_patched = True
96 DelegationsHandler._service_hacked = True 102 DelegationsHandler._service_hacked = True
97 103
98 def connectionInitialized(self): 104 def connectionInitialized(self):
99 if not self._service_hacked: 105 if not self._service_hacked:
100 self._service_hack() 106 self._service_hack()