Mercurial > libervia-pubsub
comparison sat_pubsub/pubsub_admin.py @ 405:c56a728412f1
file organisation + setup refactoring:
- `/src` has been renamed to `/sat_pubsub`, this is the recommended naming convention
- revamped `setup.py` on the basis of SàT's `setup.py`
- added a `VERSION` which is the unique place where version number will now be set
- use same trick as in SàT to specify dev version (`D` at the end)
- use setuptools_scm to retrieve Mercurial hash when in dev version
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 16 Aug 2019 12:00:02 +0200 |
parents | src/pubsub_admin.py@1d2222a91e6b |
children | ccb2a22ea0fc |
comparison
equal
deleted
inserted
replaced
404:105a0772eedd | 405:c56a728412f1 |
---|---|
1 #!/usr/bin/python | |
2 #-*- coding: utf-8 -*- | |
3 | |
4 # Copyright (c) 2019 Jérôme Poisson | |
5 # | |
6 # This program is free software: you can redistribute it and/or modify | |
7 # it under the terms of the GNU Affero General Public License as published by | |
8 # the Free Software Foundation, either version 3 of the License, or | |
9 # (at your option) any later version. | |
10 # | |
11 # This program is distributed in the hope that it will be useful, | |
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 # GNU Affero General Public License for more details. | |
15 # | |
16 # You should have received a copy of the GNU Affero General Public License | |
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | |
19 """ | |
20 Pubsub Admin experimental protocol implementation | |
21 | |
22 """ | |
23 | |
24 from zope.interface import implements | |
25 from twisted.python import log | |
26 from twisted.internet import defer | |
27 from twisted.words.protocols.jabber import jid, error as jabber_error, xmlstream | |
28 from sat_pubsub import error | |
29 from wokkel.subprotocols import XMPPHandler | |
30 from wokkel import disco, iwokkel, pubsub | |
31 | |
32 NS_PUBSUB_ADMIN = u"https://salut-a-toi.org/spec/pubsub_admin:0" | |
33 ADMIN_REQUEST = '/iq[@type="set"]/admin[@xmlns="{}"]'.format(NS_PUBSUB_ADMIN) | |
34 | |
35 | |
36 class PubsubAdminHandler(XMPPHandler): | |
37 implements(iwokkel.IDisco) | |
38 | |
39 def __init__(self, backend): | |
40 super(PubsubAdminHandler, self).__init__() | |
41 self.backend = backend | |
42 | |
43 def connectionInitialized(self): | |
44 self.xmlstream.addObserver(ADMIN_REQUEST, self.onAdminRequest) | |
45 | |
46 def sendError(self, iq_elt, condition=u'bad-request'): | |
47 stanza_error = jabber_error.StanzaError(condition) | |
48 iq_error = stanza_error.toResponse(iq_elt) | |
49 self.parent.xmlstream.send(iq_error) | |
50 | |
51 @defer.inlineCallbacks | |
52 def onAdminRequest(self, iq_elt): | |
53 """Pubsub Admin request received""" | |
54 iq_elt.handled = True | |
55 try: | |
56 pep = bool(iq_elt.delegated) | |
57 except AttributeError: | |
58 pep = False | |
59 | |
60 # is the sender really an admin? | |
61 admins = self.backend.config[u'admins_jids_list'] | |
62 from_jid = jid.JID(iq_elt[u'from']) | |
63 if from_jid.userhostJID() not in admins: | |
64 log.msg("WARNING: admin request done by non admin entity {from_jid}" | |
65 .format(from_jid=from_jid.full())) | |
66 self.sendError(iq_elt, u'forbidden') | |
67 return | |
68 | |
69 # alright, we can proceed | |
70 recipient = jid.JID(iq_elt[u'to']) | |
71 admin_elt = iq_elt.admin | |
72 try: | |
73 pubsub_elt = next(admin_elt.elements(pubsub.NS_PUBSUB, u'pubsub')) | |
74 publish_elt = next(pubsub_elt.elements(pubsub.NS_PUBSUB, u'publish')) | |
75 except StopIteration: | |
76 self.sendError(iq_elt) | |
77 return | |
78 try: | |
79 node = publish_elt[u'node'] | |
80 except KeyError: | |
81 self.sendError(iq_elt) | |
82 return | |
83 | |
84 # we prepare the result IQ request, we will fill it with item ids | |
85 iq_result_elt = xmlstream.toResponse(iq_elt, u'result') | |
86 result_admin_elt = iq_result_elt.addElement((NS_PUBSUB_ADMIN, u'admin')) | |
87 result_pubsub_elt = result_admin_elt.addElement((pubsub.NS_PUBSUB, u'pubsub')) | |
88 result_publish_elt = result_pubsub_elt.addElement(u'publish') | |
89 result_publish_elt[u'node'] = node | |
90 | |
91 # now we can send the items | |
92 for item in publish_elt.elements(pubsub.NS_PUBSUB, u'item'): | |
93 try: | |
94 requestor = jid.JID(item.attributes.pop(u'publisher')) | |
95 except Exception as e: | |
96 log.msg(u"WARNING: invalid jid in publisher ({requestor}): {msg}" | |
97 .format(requestor=requestor, msg=e)) | |
98 self.sendError(iq_elt) | |
99 return | |
100 except KeyError: | |
101 requestor = from_jid | |
102 | |
103 # we don't use a DeferredList because we want to be sure that | |
104 # each request is done in order | |
105 try: | |
106 payload = yield self.backend.publish( | |
107 nodeIdentifier=node, | |
108 items=[item], | |
109 requestor=requestor, | |
110 pep=pep, | |
111 recipient=recipient) | |
112 except (error.Forbidden, error.ItemForbidden): | |
113 __import__('pudb').set_trace() | |
114 self.sendError(iq_elt, u"forbidden") | |
115 return | |
116 except Exception as e: | |
117 self.sendError(iq_elt, u"internal-server-error") | |
118 log.msg(u"INTERNAL ERROR: {msg}".format(msg=e)) | |
119 return | |
120 | |
121 result_item_elt = result_publish_elt.addElement(u'item') | |
122 # either the id was given and it is available in item | |
123 # either it's a new item, and we can retrieve it from return payload | |
124 try: | |
125 result_item_elt[u'id'] = item[u'id'] | |
126 except KeyError: | |
127 result_item_elt = payload.publish.item[u'id'] | |
128 | |
129 self.xmlstream.send(iq_result_elt) | |
130 | |
131 def getDiscoInfo(self, requestor, service, nodeIdentifier=''): | |
132 return [disco.DiscoFeature(NS_PUBSUB_ADMIN)] | |
133 | |
134 def getDiscoItems(self, requestor, service, nodeIdentifier=''): | |
135 return [] |