Mercurial > libervia-pubsub
comparison sat_pubsub/privilege.py @ 343:ff8aff4c9b79
backend, psql: implemented notifications for auto subscribers in PEP:
people with presence permission from node owner and who request notification (+notify) from node will receive notifications according to XEP-0163 §4.
This make SàT Pubsub a nearly fully compliant PEP service. Following features are still missing:
- presence access model, should be implemented very soon as everything is already there
- deleting resource on unavailable presence, will be implemented really soon
- XEP-0115 hash check
- and most importantly, rosters updates. XEP-0356 needs to be updated for this.
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 20 Aug 2017 18:41:21 +0200 |
parents | 28c9579901d3 |
children | d1f63ae1eaf4 |
comparison
equal
deleted
inserted
replaced
342:28c9579901d3 | 343:ff8aff4c9b79 |
---|---|
66 # FIXME: we use a hack supposing that our privilege come from hostname | 66 # FIXME: we use a hack supposing that our privilege come from hostname |
67 # and we are a component named [name].hostname | 67 # and we are a component named [name].hostname |
68 # but we need to manage properly server | 68 # but we need to manage properly server |
69 # TODO: do proper server handling | 69 # TODO: do proper server handling |
70 self.server_jid = jid.JID(service_jid.host.split('.', 1)[1]) | 70 self.server_jid = jid.JID(service_jid.host.split('.', 1)[1]) |
71 self.caps_map = {} # key: full jid, value: caps_hash | 71 self.caps_map = {} # key: bare jid, value: dict of resources with caps hash |
72 self.hash_map = {} # key: (hash,version), value: DiscoInfo instance | 72 self.hash_map = {} # key: (hash,version), value: dict with DiscoInfo instance (infos) and nodes to notify (notify) |
73 self.roster_cache = {} # key: jid, value: dict with "timestamp" and "roster" | 73 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") | 74 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 | 75 self.server = None |
76 | 76 |
77 @property | 77 @property |
121 Retrieve contact list. | 121 Retrieve contact list. |
122 | 122 |
123 @return: Roster as a mapping from L{JID} to L{RosterItem}. | 123 @return: Roster as a mapping from L{JID} to L{RosterItem}. |
124 @rtype: L{twisted.internet.defer.Deferred} | 124 @rtype: L{twisted.internet.defer.Deferred} |
125 """ | 125 """ |
126 # TODO: cache results | |
126 if self._permissions[PERM_ROSTER] not in ('get', 'both'): | 127 if self._permissions[PERM_ROSTER] not in ('get', 'both'): |
127 log.msg("WARNING: permission not allowed to get roster") | 128 log.msg("WARNING: permission not allowed to get roster") |
128 raise failure.Failure(NotAllowedError('roster get is not allowed')) | 129 raise failure.Failure(NotAllowedError('roster get is not allowed')) |
129 | 130 |
130 def processRoster(result): | 131 def processRoster(result): |
235 # no capabilities, we don't go further | 236 # no capabilities, we don't go further |
236 return | 237 return |
237 | 238 |
238 # FIXME: hash is not checked (cf. XEP-0115) | 239 # FIXME: hash is not checked (cf. XEP-0115) |
239 disco_tuple = (hash_, ver) | 240 disco_tuple = (hash_, ver) |
240 if from_jid not in self.caps_map: | 241 jid_caps = self.caps_map.setdefault(from_jid_bare, {}) |
241 self.caps_map[from_jid] = disco_tuple | 242 if from_jid.resource not in jid_caps: |
243 jid_caps[from_jid.resource] = disco_tuple | |
242 | 244 |
243 if disco_tuple not in self.hash_map: | 245 if disco_tuple not in self.hash_map: |
244 # first time we se this hash, what is behind it? | 246 # first time we se this hash, what is behind it? |
245 infos = yield self.requestInfo(from_jid) | 247 infos = yield self.requestInfo(from_jid) |
246 self.hash_map[disco_tuple] = { | 248 self.hash_map[disco_tuple] = { |
253 if not nodes: | 255 if not nodes: |
254 return | 256 return |
255 # publishers are entities which have granted presence access to our user + user itself | 257 # publishers are entities which have granted presence access to our user + user itself |
256 publishers = tuple(self.presence_map.get(from_jid_bare, ())) + (from_jid_bare,) | 258 publishers = tuple(self.presence_map.get(from_jid_bare, ())) + (from_jid_bare,) |
257 | 259 |
260 # FIXME: add "presence" access_model (for node) for getLastItems | |
258 last_items = yield self._backend.storage.getLastItems(publishers, nodes, ('open',), ('open',), True) | 261 last_items = yield self._backend.storage.getLastItems(publishers, nodes, ('open',), ('open',), True) |
259 # we send message with last item, as required by https://xmpp.org/extensions/xep-0163.html#notify-last | 262 # we send message with last item, as required by https://xmpp.org/extensions/xep-0163.html#notify-last |
260 for pep_jid, node, item, item_access_model in last_items: | 263 for pep_jid, node, item, item_access_model in last_items: |
261 self.notifyPublish(pep_jid, node, [(from_jid, None, [item])]) | 264 self.notifyPublish(pep_jid, node, [(from_jid, None, [item])]) |
265 | |
266 ## misc ## | |
267 | |
268 @defer.inlineCallbacks | |
269 def getAutoSubscribers(self, recipient, nodeIdentifier, explicit_subscribers): | |
270 """get automatic subscribers, i.e. subscribers with presence subscription and +notify for this node | |
271 | |
272 @param recipient(jid.JID): jid of the PEP owner of this node | |
273 @param nodeIdentifier(unicode): node | |
274 @param explicit_subscribers(set(jid.JID}: jids of people which have an explicit subscription | |
275 @return (list[jid.JID]): full jid of automatically subscribed entities | |
276 """ | |
277 auto_subscribers = [] | |
278 roster = yield self.getRoster(recipient) | |
279 for roster_jid, roster_item in roster.iteritems(): | |
280 if roster_jid in explicit_subscribers: | |
281 continue | |
282 if roster_item.subscriptionFrom: | |
283 try: | |
284 online_resources = self.caps_map[roster_jid] | |
285 except KeyError: | |
286 continue | |
287 for res, hash_ in online_resources.iteritems(): | |
288 notify = self.hash_map[hash_]['notify'] | |
289 if nodeIdentifier in notify: | |
290 full_jid = jid.JID(tuple=(roster_jid.user, roster_jid.host, res)) | |
291 auto_subscribers.append(full_jid) | |
292 defer.returnValue(auto_subscribers) |