comparison sat_pubsub/pubsub_admin.py @ 414:ccb2a22ea0fc

Python 3 port: /!\ Python 3.6+ is now needed to use SàT Pubsub /!\ instability may occur and features may not be working anymore, this will improve with time The same procedure as in backend has been applied (check backend commit ab2696e34d29 logs for details). Python minimal version has been updated in setup.py
author Goffi <goffi@goffi.org>
date Fri, 16 Aug 2019 12:53:33 +0200
parents c56a728412f1
children 412d26a9b2c2
comparison
equal deleted inserted replaced
413:a5edf5e1dd74 414:ccb2a22ea0fc
1 #!/usr/bin/python 1 #!/usr/bin/env python3
2 #-*- coding: utf-8 -*- 2 #-*- coding: utf-8 -*-
3 3
4 # Copyright (c) 2019 Jérôme Poisson 4 # Copyright (c) 2019 Jérôme Poisson
5 # 5 #
6 # 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
19 """ 19 """
20 Pubsub Admin experimental protocol implementation 20 Pubsub Admin experimental protocol implementation
21 21
22 """ 22 """
23 23
24 from zope.interface import implements 24 from zope.interface import implementer
25 from twisted.python import log 25 from twisted.python import log
26 from twisted.internet import defer 26 from twisted.internet import defer
27 from twisted.words.protocols.jabber import jid, error as jabber_error, xmlstream 27 from twisted.words.protocols.jabber import jid, error as jabber_error, xmlstream
28 from sat_pubsub import error 28 from sat_pubsub import error
29 from wokkel.subprotocols import XMPPHandler 29 from wokkel.subprotocols import XMPPHandler
30 from wokkel import disco, iwokkel, pubsub 30 from wokkel import disco, iwokkel, pubsub
31 31
32 NS_PUBSUB_ADMIN = u"https://salut-a-toi.org/spec/pubsub_admin:0" 32 NS_PUBSUB_ADMIN = "https://salut-a-toi.org/spec/pubsub_admin:0"
33 ADMIN_REQUEST = '/iq[@type="set"]/admin[@xmlns="{}"]'.format(NS_PUBSUB_ADMIN) 33 ADMIN_REQUEST = '/iq[@type="set"]/admin[@xmlns="{}"]'.format(NS_PUBSUB_ADMIN)
34 34
35 35
36 @implementer(iwokkel.IDisco)
36 class PubsubAdminHandler(XMPPHandler): 37 class PubsubAdminHandler(XMPPHandler):
37 implements(iwokkel.IDisco)
38 38
39 def __init__(self, backend): 39 def __init__(self, backend):
40 super(PubsubAdminHandler, self).__init__() 40 super(PubsubAdminHandler, self).__init__()
41 self.backend = backend 41 self.backend = backend
42 42
43 def connectionInitialized(self): 43 def connectionInitialized(self):
44 self.xmlstream.addObserver(ADMIN_REQUEST, self.onAdminRequest) 44 self.xmlstream.addObserver(ADMIN_REQUEST, self.onAdminRequest)
45 45
46 def sendError(self, iq_elt, condition=u'bad-request'): 46 def sendError(self, iq_elt, condition='bad-request'):
47 stanza_error = jabber_error.StanzaError(condition) 47 stanza_error = jabber_error.StanzaError(condition)
48 iq_error = stanza_error.toResponse(iq_elt) 48 iq_error = stanza_error.toResponse(iq_elt)
49 self.parent.xmlstream.send(iq_error) 49 self.parent.xmlstream.send(iq_error)
50 50
51 @defer.inlineCallbacks 51 @defer.inlineCallbacks
56 pep = bool(iq_elt.delegated) 56 pep = bool(iq_elt.delegated)
57 except AttributeError: 57 except AttributeError:
58 pep = False 58 pep = False
59 59
60 # is the sender really an admin? 60 # is the sender really an admin?
61 admins = self.backend.config[u'admins_jids_list'] 61 admins = self.backend.config['admins_jids_list']
62 from_jid = jid.JID(iq_elt[u'from']) 62 from_jid = jid.JID(iq_elt['from'])
63 if from_jid.userhostJID() not in admins: 63 if from_jid.userhostJID() not in admins:
64 log.msg("WARNING: admin request done by non admin entity {from_jid}" 64 log.msg("WARNING: admin request done by non admin entity {from_jid}"
65 .format(from_jid=from_jid.full())) 65 .format(from_jid=from_jid.full()))
66 self.sendError(iq_elt, u'forbidden') 66 self.sendError(iq_elt, 'forbidden')
67 return 67 return
68 68
69 # alright, we can proceed 69 # alright, we can proceed
70 recipient = jid.JID(iq_elt[u'to']) 70 recipient = jid.JID(iq_elt['to'])
71 admin_elt = iq_elt.admin 71 admin_elt = iq_elt.admin
72 try: 72 try:
73 pubsub_elt = next(admin_elt.elements(pubsub.NS_PUBSUB, u'pubsub')) 73 pubsub_elt = next(admin_elt.elements(pubsub.NS_PUBSUB, 'pubsub'))
74 publish_elt = next(pubsub_elt.elements(pubsub.NS_PUBSUB, u'publish')) 74 publish_elt = next(pubsub_elt.elements(pubsub.NS_PUBSUB, 'publish'))
75 except StopIteration: 75 except StopIteration:
76 self.sendError(iq_elt) 76 self.sendError(iq_elt)
77 return 77 return
78 try: 78 try:
79 node = publish_elt[u'node'] 79 node = publish_elt['node']
80 except KeyError: 80 except KeyError:
81 self.sendError(iq_elt) 81 self.sendError(iq_elt)
82 return 82 return
83 83
84 # we prepare the result IQ request, we will fill it with item ids 84 # we prepare the result IQ request, we will fill it with item ids
85 iq_result_elt = xmlstream.toResponse(iq_elt, u'result') 85 iq_result_elt = xmlstream.toResponse(iq_elt, 'result')
86 result_admin_elt = iq_result_elt.addElement((NS_PUBSUB_ADMIN, u'admin')) 86 result_admin_elt = iq_result_elt.addElement((NS_PUBSUB_ADMIN, 'admin'))
87 result_pubsub_elt = result_admin_elt.addElement((pubsub.NS_PUBSUB, u'pubsub')) 87 result_pubsub_elt = result_admin_elt.addElement((pubsub.NS_PUBSUB, 'pubsub'))
88 result_publish_elt = result_pubsub_elt.addElement(u'publish') 88 result_publish_elt = result_pubsub_elt.addElement('publish')
89 result_publish_elt[u'node'] = node 89 result_publish_elt['node'] = node
90 90
91 # now we can send the items 91 # now we can send the items
92 for item in publish_elt.elements(pubsub.NS_PUBSUB, u'item'): 92 for item in publish_elt.elements(pubsub.NS_PUBSUB, 'item'):
93 try: 93 try:
94 requestor = jid.JID(item.attributes.pop(u'publisher')) 94 requestor = jid.JID(item.attributes.pop('publisher'))
95 except Exception as e: 95 except Exception as e:
96 log.msg(u"WARNING: invalid jid in publisher ({requestor}): {msg}" 96 log.msg("WARNING: invalid jid in publisher ({requestor}): {msg}"
97 .format(requestor=requestor, msg=e)) 97 .format(requestor=requestor, msg=e))
98 self.sendError(iq_elt) 98 self.sendError(iq_elt)
99 return 99 return
100 except KeyError: 100 except KeyError:
101 requestor = from_jid 101 requestor = from_jid
109 requestor=requestor, 109 requestor=requestor,
110 pep=pep, 110 pep=pep,
111 recipient=recipient) 111 recipient=recipient)
112 except (error.Forbidden, error.ItemForbidden): 112 except (error.Forbidden, error.ItemForbidden):
113 __import__('pudb').set_trace() 113 __import__('pudb').set_trace()
114 self.sendError(iq_elt, u"forbidden") 114 self.sendError(iq_elt, "forbidden")
115 return 115 return
116 except Exception as e: 116 except Exception as e:
117 self.sendError(iq_elt, u"internal-server-error") 117 self.sendError(iq_elt, "internal-server-error")
118 log.msg(u"INTERNAL ERROR: {msg}".format(msg=e)) 118 log.msg("INTERNAL ERROR: {msg}".format(msg=e))
119 return 119 return
120 120
121 result_item_elt = result_publish_elt.addElement(u'item') 121 result_item_elt = result_publish_elt.addElement('item')
122 # either the id was given and it is available in 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 123 # either it's a new item, and we can retrieve it from return payload
124 try: 124 try:
125 result_item_elt[u'id'] = item[u'id'] 125 result_item_elt['id'] = item['id']
126 except KeyError: 126 except KeyError:
127 result_item_elt = payload.publish.item[u'id'] 127 result_item_elt = payload.publish.item['id']
128 128
129 self.xmlstream.send(iq_result_elt) 129 self.xmlstream.send(iq_result_elt)
130 130
131 def getDiscoInfo(self, requestor, service, nodeIdentifier=''): 131 def getDiscoInfo(self, requestor, service, nodeIdentifier=''):
132 return [disco.DiscoFeature(NS_PUBSUB_ADMIN)] 132 return [disco.DiscoFeature(NS_PUBSUB_ADMIN)]