Mercurial > libervia-pubsub
comparison sat_pubsub/privilege.py @ 460:607616f9ef5b
backend: new `server_jid` option:
Server domain must be known to validate requests, this can be done explicitely by using the
`server_jid` option. If this option is not set, the server domain is found:
- by using the `from` name of the initial delegation advertising message
- or it fallbacks to using the part after initial `.` (`pubsub.example.org` would give
`example.org`)
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 15 Oct 2021 09:32:07 +0200 |
parents | 0b5233981671 |
children | a017af61a32b |
comparison
equal
deleted
inserted
replaced
459:cebcb7f56889 | 460:607616f9ef5b |
---|---|
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 |
15 # GNU Affero General Public License for more details. | 14 # GNU Affero General Public License for more details. |
16 | 15 |
17 # You should have received a copy of the GNU Affero General Public License | 16 # You should have received a copy of the GNU Affero General Public License |
18 # 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/>. |
19 | 18 |
20 # --- | 19 "This module implements XEP-0356 (Privileged Entity) to manage rosters, messages and " |
20 "presences" | |
21 | 21 |
22 # This module implements XEP-0356 (Privileged Entity) to manage rosters, messages and presences | 22 # This module implements XEP-0356 (Privileged Entity) to manage rosters, messages and presences |
23 | 23 |
24 from wokkel import xmppim | 24 from wokkel import xmppim |
25 from wokkel.compat import IQ | 25 from wokkel.compat import IQ |
56 #FIXME: need to manage updates, and database sync | 56 #FIXME: need to manage updates, and database sync |
57 #TODO: cache | 57 #TODO: cache |
58 | 58 |
59 def __init__(self, service_jid): | 59 def __init__(self, service_jid): |
60 super(PrivilegesHandler, self).__init__() | 60 super(PrivilegesHandler, self).__init__() |
61 self.backend = None | |
61 self._permissions = {PERM_ROSTER: 'none', | 62 self._permissions = {PERM_ROSTER: 'none', |
62 PERM_MESSAGE: 'none', | 63 PERM_MESSAGE: 'none', |
63 PERM_PRESENCE: 'none'} | 64 PERM_PRESENCE: 'none'} |
64 self._pubsub_service = None | 65 self._pubsub_service = None |
65 self._backend = None | |
66 # FIXME: we use a hack supposing that our privilege come from hostname | |
67 # and we are a component named [name].hostname | |
68 # but we need to manage properly server | |
69 # TODO: do proper server handling | |
70 self.server_jid = jid.JID(service_jid.host.split('.', 1)[1]) | |
71 self.caps_map = {} # key: bare jid, value: dict of resources with caps hash | 66 self.caps_map = {} # key: bare jid, value: dict of resources with caps hash |
72 self.hash_map = {} # key: (hash,version), value: dict with DiscoInfo instance (infos) and nodes to notify (notify) | 67 # key: (hash,version), value: dict with DiscoInfo instance (infos) and nodes to |
68 # notify (notify) | |
69 self.hash_map = {} | |
73 self.roster_cache = {} # key: jid, value: dict with "timestamp" and "roster" | 70 self.roster_cache = {} # key: jid, value: dict with "timestamp" and "roster" |
74 self.presence_map = {} # inverted roster: key: jid, value: set of entities who has this jid in roster (with presence of "from" or "both") | 71 self.presence_map = {} # inverted roster: key: jid, value: set of entities who has this jid in roster (with presence of "from" or "both") |
75 self.server = None | |
76 | 72 |
77 @property | 73 @property |
78 def permissions(self): | 74 def permissions(self): |
79 return self._permissions | 75 return self._permissions |
80 | 76 |
81 def connectionInitialized(self): | 77 def connectionInitialized(self): |
82 for handler in self.parent.handlers: | 78 for handler in self.parent.handlers: |
83 if IPubSubService.providedBy(handler): | 79 if IPubSubService.providedBy(handler): |
84 self._pubsub_service = handler | 80 self._pubsub_service = handler |
85 break | 81 break |
86 self._backend = self.parent.parent.getServiceNamed('backend') | 82 self.backend = self.parent.parent.getServiceNamed('backend') |
87 self.xmlstream.addObserver(PRIV_ENT_ADV_XPATH, self.onAdvertise) | 83 self.xmlstream.addObserver(PRIV_ENT_ADV_XPATH, self.onAdvertise) |
88 self.xmlstream.addObserver('/presence', self.onPresence) | 84 self.xmlstream.addObserver('/presence', self._onPresence) |
89 | 85 |
90 def onAdvertise(self, message): | 86 def onAdvertise(self, message): |
91 """Managage the <message/> advertising privileges | 87 """Managage the <message/> advertising privileges |
92 | 88 |
93 self._permissions will be updated according to advertised privileged | 89 self._permissions will be updated according to advertised privileged |
173 log.msg("WARNING: permission not allowed to send privileged messages") | 169 log.msg("WARNING: permission not allowed to send privileged messages") |
174 raise failure.Failure(NotAllowedError('privileged messages are not allowed')) | 170 raise failure.Failure(NotAllowedError('privileged messages are not allowed')) |
175 | 171 |
176 main_message = domish.Element((None, "message")) | 172 main_message = domish.Element((None, "message")) |
177 if to_jid is None: | 173 if to_jid is None: |
178 to_jid = self.server_jid | 174 to_jid = self.backend.server_jid |
179 main_message['to'] = to_jid.full() | 175 main_message['to'] = to_jid.full() |
180 privilege_elt = main_message.addElement((PRIV_ENT_NS, 'privilege')) | 176 privilege_elt = main_message.addElement((PRIV_ENT_NS, 'privilege')) |
181 forwarded_elt = privilege_elt.addElement((FORWARDED_NS, 'forwarded')) | 177 forwarded_elt = privilege_elt.addElement((FORWARDED_NS, 'forwarded')) |
182 priv_message['xmlns'] = 'jabber:client' | 178 priv_message['xmlns'] = 'jabber:client' |
183 forwarded_elt.addChild(priv_message) | 179 forwarded_elt.addChild(priv_message) |
236 ) | 232 ) |
237 self.sendMessage(message) | 233 self.sendMessage(message) |
238 | 234 |
239 ## presence ## | 235 ## presence ## |
240 | 236 |
241 @defer.inlineCallbacks | 237 def _onPresence(self, presence_elt: domish.Element) -> None: |
242 def onPresence(self, presence_elt): | 238 defer.ensureDeferred(self.onPresence(presence_elt)) |
243 if self.server is None: | 239 |
244 # FIXME: we use a hack supposing that our delegation come from hostname | 240 async def onPresence(self, presence_elt: domish.Element) -> None: |
245 # and we are a component named [name].hostname | |
246 # but we need to manage properly allowed servers | |
247 # TODO: do proper origin security check | |
248 _, self.server = presence_elt['to'].split('.', 1) | |
249 from_jid = jid.JID(presence_elt['from']) | 241 from_jid = jid.JID(presence_elt['from']) |
250 from_jid_bare = from_jid.userhostJID() | 242 from_jid_bare = from_jid.userhostJID() |
251 if from_jid.host == self.server and from_jid_bare not in self.roster_cache: | 243 if ((jid.JID(from_jid.host) == self.backend.server_jid |
252 roster = yield self.getRoster(from_jid_bare) | 244 and from_jid_bare not in self.roster_cache)): |
245 roster = await self.getRoster(from_jid_bare) | |
253 timestamp = time.time() | 246 timestamp = time.time() |
254 self.roster_cache[from_jid_bare] = {'timestamp': timestamp, | 247 self.roster_cache[from_jid_bare] = {'timestamp': timestamp, |
255 'roster': roster, | 248 'roster': roster, |
256 } | 249 } |
257 for roster_jid, roster_item in roster.items(): | 250 for roster_jid, roster_item in roster.items(): |