comparison sat_pubsub/backend.py @ 353:7c5d85c6fb3a

backend: enforce schema on get/publish and notifications
author Goffi <goffi@goffi.org>
date Fri, 08 Sep 2017 08:02:05 +0200
parents efbdca10f0fb
children 18b983fe9e1b
comparison
equal deleted inserted replaced
352:efbdca10f0fb 353:7c5d85c6fb3a
161 def __init__(self, storage): 161 def __init__(self, storage):
162 utility.EventDispatcher.__init__(self) 162 utility.EventDispatcher.__init__(self)
163 self.storage = storage 163 self.storage = storage
164 self._callbackList = [] 164 self._callbackList = []
165 165
166
167 def supportsPublisherAffiliation(self): 166 def supportsPublisherAffiliation(self):
168 return True 167 return True
169 168
170
171 def supportsGroupBlog(self): 169 def supportsGroupBlog(self):
172 return True 170 return True
173 171
174
175 def supportsOutcastAffiliation(self): 172 def supportsOutcastAffiliation(self):
176 return True 173 return True
177 174
178
179 def supportsPersistentItems(self): 175 def supportsPersistentItems(self):
180 return True 176 return True
181 177
182
183 def supportsPublishModel(self): 178 def supportsPublishModel(self):
184 return True 179 return True
185
186 180
187 def getNodeType(self, nodeIdentifier, pep, recipient=None): 181 def getNodeType(self, nodeIdentifier, pep, recipient=None):
188 # FIXME: manage pep and recipient 182 # FIXME: manage pep and recipient
189 d = self.storage.getNode(nodeIdentifier, pep, recipient) 183 d = self.storage.getNode(nodeIdentifier, pep, recipient)
190 d.addCallback(lambda node: node.getType()) 184 d.addCallback(lambda node: node.getType())
204 d = self.privilege.isSubscribedFrom(requestor, recipient) 198 d = self.privilege.isSubscribedFrom(requestor, recipient)
205 d.addCallback(self._getNodesIds, pep, recipient) 199 d.addCallback(self._getNodesIds, pep, recipient)
206 return d 200 return d
207 return self.storage.getNodeIds(pep, recipient) 201 return self.storage.getNodeIds(pep, recipient)
208 202
209
210 def getNodeMetaData(self, nodeIdentifier, pep, recipient=None): 203 def getNodeMetaData(self, nodeIdentifier, pep, recipient=None):
211 # FIXME: manage pep and recipient 204 # FIXME: manage pep and recipient
212 d = self.storage.getNode(nodeIdentifier, pep, recipient) 205 d = self.storage.getNode(nodeIdentifier, pep, recipient)
213 d.addCallback(lambda node: node.getMetaData()) 206 d.addCallback(lambda node: node.getMetaData())
214 d.addCallback(self._makeMetaData) 207 d.addCallback(self._makeMetaData)
215 return d 208 return d
216
217 209
218 def _makeMetaData(self, metaData): 210 def _makeMetaData(self, metaData):
219 options = [] 211 options = []
220 for key, value in metaData.iteritems(): 212 for key, value in metaData.iteritems():
221 if key in self.nodeOptions: 213 if key in self.nodeOptions:
223 option.update(self.nodeOptions[key]) 215 option.update(self.nodeOptions[key])
224 option["value"] = value 216 option["value"] = value
225 options.append(option) 217 options.append(option)
226 218
227 return options 219 return options
228
229 220
230 def _checkAuth(self, node, requestor): 221 def _checkAuth(self, node, requestor):
231 """ Check authorisation of publishing in node for requestor """ 222 """ Check authorisation of publishing in node for requestor """
232 223
233 def check(affiliation): 224 def check(affiliation):
296 if category: 287 if category:
297 categories.append(category) 288 categories.append(category)
298 289
299 return categories 290 return categories
300 291
292 def enforceSchema(self, item_elt, schema, affiliation):
293 """modifify item according to element, or refuse publishing
294
295 @param item_elt(domish.Element): item to check/modify
296 @param schema(domish.Eement): schema to enfore
297 @param affiliation(unicode): affiliation of the publisher
298 """
299 try:
300 x_elt = next(item_elt.elements(data_form.NS_X_DATA, 'x'))
301 item_form = data_form.Form.fromElement(x_elt)
302 except (StopIteration, data_form.Error):
303 raise pubsub.BadRequest(text="node has a schema but item has no form")
304 else:
305 item_elt.children.remove(x_elt)
306
307 schema_form = data_form.Form.fromElement(schema)
308
309 # we enforce restrictions
310 for field_elt in schema.elements(data_form.NS_X_DATA, 'field'):
311 var = field_elt['var']
312 for restrict_elt in field_elt.elements(const.NS_SCHEMA_RESTRICT, 'restrict'):
313 write_restriction = restrict_elt.attributes.get('write')
314 if write_restriction is not None:
315 if write_restriction == 'owner':
316 if affiliation != 'owner':
317 # write is not allowed on this field, we use default value
318 # we can safely use Field from schema_form because
319 # we have created this instance only for this method
320 try:
321 item_form.removeField(item_form.fields[var])
322 except KeyError:
323 pass
324 item_form.addField(schema_form.fields[var])
325 else:
326 raise StanzaError('feature-not-implemented', text='unknown write restriction {}'.format(write_restriction))
327
328 # we now remove every field which is not in data schema
329 to_remove = set()
330 for item_var, item_field in item_form.fields.iteritems():
331 if item_var not in schema_form.fields:
332 to_remove.add(item_field)
333
334 for field in to_remove:
335 item_form.removeField(field)
336 item_elt.addChild(item_form.toElement())
337
301 def _checkOverwrite(self, node, itemIdentifiers, publisher): 338 def _checkOverwrite(self, node, itemIdentifiers, publisher):
302 """Check that the itemIdentifiers correspond to items published 339 """Check that the itemIdentifiers correspond to items published
303 by the current publisher""" 340 by the current publisher"""
304 def doCheck(item_pub_map): 341 def doCheck(item_pub_map):
305 for item_publisher in item_pub_map.itervalues(): 342 for item_publisher in item_pub_map.itervalues():
308 345
309 d = node.getItemsPublishers(itemIdentifiers) 346 d = node.getItemsPublishers(itemIdentifiers)
310 d.addCallback(doCheck) 347 d.addCallback(doCheck)
311 return d 348 return d
312 349
313
314 def publish(self, nodeIdentifier, items, requestor, pep, recipient): 350 def publish(self, nodeIdentifier, items, requestor, pep, recipient):
315 d = self.storage.getNode(nodeIdentifier, pep, recipient) 351 d = self.storage.getNode(nodeIdentifier, pep, recipient)
316 d.addCallback(self._checkAuth, requestor) 352 d.addCallback(self._checkAuth, requestor)
317 #FIXME: owner and publisher are not necessarly the same. So far we use only owner to get roster. 353 #FIXME: owner and publisher are not necessarly the same. So far we use only owner to get roster.
318 #FIXME: in addition, there can be several owners: that is not managed yet 354 #FIXME: in addition, there can be several owners: that is not managed yet
319 d.addCallback(self._doPublish, items, requestor, pep, recipient) 355 d.addCallback(self._doPublish, items, requestor, pep, recipient)
320 return d 356 return d
321
322 357
323 def _doPublish(self, result, items, requestor, pep, recipient): 358 def _doPublish(self, result, items, requestor, pep, recipient):
324 affiliation, node = result 359 affiliation, node = result
325 if node.nodeType == 'collection': 360 if node.nodeType == 'collection':
326 raise error.NoPublishing() 361 raise error.NoPublishing()
346 item["id"] = str(uuid.uuid4()) 381 item["id"] = str(uuid.uuid4())
347 else: 382 else:
348 check_overwrite = True 383 check_overwrite = True
349 access_model, item_config = self.parseItemConfig(item) 384 access_model, item_config = self.parseItemConfig(item)
350 categories = self.parseCategories(item) 385 categories = self.parseCategories(item)
386 schema = node.getSchema()
387 if schema is not None:
388 self.enforceSchema(item, schema, affiliation)
351 items_data.append(container.ItemData(item, access_model, item_config, categories)) 389 items_data.append(container.ItemData(item, access_model, item_config, categories))
352 390
353 if persistItems: 391 if persistItems:
354 if check_overwrite and affiliation != 'owner': 392 if check_overwrite and affiliation != 'owner':
355 # we don't want a publisher to overwrite the item 393 # we don't want a publisher to overwrite the item
363 401
364 d.addCallback(self._doNotify, node, items_data, 402 d.addCallback(self._doNotify, node, items_data,
365 deliverPayloads, pep, recipient) 403 deliverPayloads, pep, recipient)
366 return d 404 return d
367 405
368
369 def _doNotify(self, result, node, items_data, deliverPayloads, pep, recipient): 406 def _doNotify(self, result, node, items_data, deliverPayloads, pep, recipient):
370 if items_data and not deliverPayloads: 407 if items_data and not deliverPayloads:
371 for item_data in items_data: 408 for item_data in items_data:
372 item_data.item.children = [] 409 item_data.item.children = []
373 self.dispatch({'items_data': items_data, 'node': node, 'pep': pep, 'recipient': recipient}, 410 self.dispatch({'items_data': items_data, 'node': node, 'pep': pep, 'recipient': recipient},
374 '//event/pubsub/notify') 411 '//event/pubsub/notify')
375
376 412
377 def getNotifications(self, node, items_data): 413 def getNotifications(self, node, items_data):
378 """Build a list of subscriber to the node 414 """Build a list of subscriber to the node
379 415
380 subscribers will be associated with subscribed items, 416 subscribers will be associated with subscribed items,
424 d = self.storage.getNode(nodeIdentifier, pep, recipient) 460 d = self.storage.getNode(nodeIdentifier, pep, recipient)
425 d.addCallback(_getAffiliation, subscriberEntity) 461 d.addCallback(_getAffiliation, subscriberEntity)
426 d.addCallback(self._doSubscribe, subscriber) 462 d.addCallback(self._doSubscribe, subscriber)
427 return d 463 return d
428 464
429
430 def _doSubscribe(self, result, subscriber): 465 def _doSubscribe(self, result, subscriber):
431 # TODO: implement other access models 466 # TODO: implement other access models
432 node, affiliation = result 467 node, affiliation = result
433 468
434 if affiliation == 'outcast': 469 if affiliation == 'outcast':
452 d = node.addSubscription(subscriber, 'subscribed', {}) 487 d = node.addSubscription(subscriber, 'subscribed', {})
453 d.addCallbacks(lambda _: True, trapExists) 488 d.addCallbacks(lambda _: True, trapExists)
454 d.addCallback(cb) 489 d.addCallback(cb)
455 490
456 return d 491 return d
457
458 492
459 def _sendLastPublished(self, subscription, node): 493 def _sendLastPublished(self, subscription, node):
460 494
461 def notifyItem(items): 495 def notifyItem(items):
462 if items: 496 if items:
476 d.addCallback(notifyItem) 510 d.addCallback(notifyItem)
477 d.addErrback(log.err) 511 d.addErrback(log.err)
478 512
479 return subscription 513 return subscription
480 514
481
482 def unsubscribe(self, nodeIdentifier, subscriber, requestor, pep, recipient): 515 def unsubscribe(self, nodeIdentifier, subscriber, requestor, pep, recipient):
483 if subscriber.userhostJID() != requestor.userhostJID(): 516 if subscriber.userhostJID() != requestor.userhostJID():
484 return defer.fail(error.Forbidden()) 517 return defer.fail(error.Forbidden())
485 518
486 d = self.storage.getNode(nodeIdentifier, pep, recipient) 519 d = self.storage.getNode(nodeIdentifier, pep, recipient)
487 d.addCallback(lambda node: node.removeSubscription(subscriber)) 520 d.addCallback(lambda node: node.removeSubscription(subscriber))
488 return d 521 return d
489 522
490
491 def getSubscriptions(self, entity): 523 def getSubscriptions(self, entity):
492 return self.storage.getSubscriptions(entity) 524 return self.storage.getSubscriptions(entity)
493 525
494 def supportsAutoCreate(self): 526 def supportsAutoCreate(self):
495 return True 527 return True
497 def supportsCreatorCheck(self): 529 def supportsCreatorCheck(self):
498 return True 530 return True
499 531
500 def supportsInstantNodes(self): 532 def supportsInstantNodes(self):
501 return True 533 return True
502
503 534
504 def createNode(self, nodeIdentifier, requestor, options = None, pep=False, recipient=None): 535 def createNode(self, nodeIdentifier, requestor, options = None, pep=False, recipient=None):
505 if not nodeIdentifier: 536 if not nodeIdentifier:
506 nodeIdentifier = 'generic/%s' % uuid.uuid4() 537 nodeIdentifier = 'generic/%s' % uuid.uuid4()
507 538
530 # TODO: handle schema on creation 561 # TODO: handle schema on creation
531 d = self.storage.createNode(nodeIdentifier, requestor, config, None, pep, recipient) 562 d = self.storage.createNode(nodeIdentifier, requestor, config, None, pep, recipient)
532 d.addCallback(lambda _: nodeIdentifier) 563 d.addCallback(lambda _: nodeIdentifier)
533 return d 564 return d
534 565
535
536 def getDefaultConfiguration(self, nodeType): 566 def getDefaultConfiguration(self, nodeType):
537 d = defer.succeed(self.storage.getDefaultConfiguration(nodeType)) 567 d = defer.succeed(self.storage.getDefaultConfiguration(nodeType))
538 return d 568 return d
539
540 569
541 def getNodeConfiguration(self, nodeIdentifier, pep, recipient): 570 def getNodeConfiguration(self, nodeIdentifier, pep, recipient):
542 if not nodeIdentifier: 571 if not nodeIdentifier:
543 return defer.fail(error.NoRootNode()) 572 return defer.fail(error.NoRootNode())
544 573
545 d = self.storage.getNode(nodeIdentifier, pep, recipient) 574 d = self.storage.getNode(nodeIdentifier, pep, recipient)
546 d.addCallback(lambda node: node.getConfiguration()) 575 d.addCallback(lambda node: node.getConfiguration())
547 576
548 return d 577 return d
549 578
550
551 def setNodeConfiguration(self, nodeIdentifier, options, requestor, pep, recipient): 579 def setNodeConfiguration(self, nodeIdentifier, options, requestor, pep, recipient):
552 if not nodeIdentifier: 580 if not nodeIdentifier:
553 return defer.fail(error.NoRootNode()) 581 return defer.fail(error.NoRootNode())
554 582
555 d = self.storage.getNode(nodeIdentifier, pep, recipient) 583 d = self.storage.getNode(nodeIdentifier, pep, recipient)
556 d.addCallback(_getAffiliation, requestor) 584 d.addCallback(_getAffiliation, requestor)
557 d.addCallback(self._doSetNodeConfiguration, options) 585 d.addCallback(self._doSetNodeConfiguration, options)
558 return d 586 return d
559 587
560
561 def _doSetNodeConfiguration(self, result, options): 588 def _doSetNodeConfiguration(self, result, options):
562 node, affiliation = result 589 node, affiliation = result
563 590
564 if affiliation != 'owner': 591 if affiliation != 'owner':
565 raise error.Forbidden() 592 raise error.Forbidden()
566 593
567 return node.setConfiguration(options) 594 return node.setConfiguration(options)
568
569 595
570 def getNodeSchema(self, nodeIdentifier, pep, recipient): 596 def getNodeSchema(self, nodeIdentifier, pep, recipient):
571 if not nodeIdentifier: 597 if not nodeIdentifier:
572 return defer.fail(error.NoRootNode()) 598 return defer.fail(error.NoRootNode())
573 599
590 d = self.storage.getNode(nodeIdentifier, pep, recipient) 616 d = self.storage.getNode(nodeIdentifier, pep, recipient)
591 d.addCallback(_getAffiliation, requestor) 617 d.addCallback(_getAffiliation, requestor)
592 d.addCallback(self._doSetNodeSchema, schema) 618 d.addCallback(self._doSetNodeSchema, schema)
593 return d 619 return d
594 620
595
596 def _doSetNodeSchema(self, result, schema): 621 def _doSetNodeSchema(self, result, schema):
597 node, affiliation = result 622 node, affiliation = result
598 623
599 if affiliation != 'owner': 624 if affiliation != 'owner':
600 raise error.Forbidden() 625 raise error.Forbidden()
601 626
602 return node.setSchema(schema) 627 return node.setSchema(schema)
603 628
604
605 def getAffiliations(self, entity, nodeIdentifier, pep, recipient): 629 def getAffiliations(self, entity, nodeIdentifier, pep, recipient):
606 return self.storage.getAffiliations(entity, nodeIdentifier, pep, recipient) 630 return self.storage.getAffiliations(entity, nodeIdentifier, pep, recipient)
607
608 631
609 def getAffiliationsOwner(self, nodeIdentifier, requestor, pep, recipient): 632 def getAffiliationsOwner(self, nodeIdentifier, requestor, pep, recipient):
610 d = self.storage.getNode(nodeIdentifier, pep, recipient) 633 d = self.storage.getNode(nodeIdentifier, pep, recipient)
611 d.addCallback(_getAffiliation, requestor) 634 d.addCallback(_getAffiliation, requestor)
612 d.addCallback(self._doGetAffiliationsOwner) 635 d.addCallback(self._doGetAffiliationsOwner)
613 return d 636 return d
614 637
615
616 def _doGetAffiliationsOwner(self, result): 638 def _doGetAffiliationsOwner(self, result):
617 node, affiliation = result 639 node, affiliation = result
618 640
619 if affiliation != 'owner': 641 if affiliation != 'owner':
620 raise error.Forbidden() 642 raise error.Forbidden()
621 return node.getAffiliations() 643 return node.getAffiliations()
622
623 644
624 def setAffiliationsOwner(self, nodeIdentifier, requestor, affiliations, pep, recipient): 645 def setAffiliationsOwner(self, nodeIdentifier, requestor, affiliations, pep, recipient):
625 d = self.storage.getNode(nodeIdentifier, pep, recipient) 646 d = self.storage.getNode(nodeIdentifier, pep, recipient)
626 d.addCallback(_getAffiliation, requestor) 647 d.addCallback(_getAffiliation, requestor)
627 d.addCallback(self._doSetAffiliationsOwner, requestor, affiliations) 648 d.addCallback(self._doSetAffiliationsOwner, requestor, affiliations)
628 return d 649 return d
629
630 650
631 def _doSetAffiliationsOwner(self, result, requestor, affiliations): 651 def _doSetAffiliationsOwner(self, result, requestor, affiliations):
632 # Check that requestor is allowed to set affiliations, and delete entities 652 # Check that requestor is allowed to set affiliations, and delete entities
633 # with "none" affiliation 653 # with "none" affiliation
634 654
656 else: 676 else:
657 d = node.setAffiliations(affiliations) 677 d = node.setAffiliations(affiliations)
658 678
659 return d 679 return d
660 680
661
662 def getSubscriptionsOwner(self, nodeIdentifier, requestor, pep, recipient): 681 def getSubscriptionsOwner(self, nodeIdentifier, requestor, pep, recipient):
663 d = self.storage.getNode(nodeIdentifier, pep, recipient) 682 d = self.storage.getNode(nodeIdentifier, pep, recipient)
664 d.addCallback(_getAffiliation, requestor) 683 d.addCallback(_getAffiliation, requestor)
665 d.addCallback(self._doGetSubscriptionsOwner) 684 d.addCallback(self._doGetSubscriptionsOwner)
666 return d 685 return d
667 686
668
669 def _doGetSubscriptionsOwner(self, result): 687 def _doGetSubscriptionsOwner(self, result):
670 node, affiliation = result 688 node, affiliation = result
671 689
672 if affiliation != 'owner': 690 if affiliation != 'owner':
673 raise error.Forbidden() 691 raise error.Forbidden()
674 return node.getSubscriptions() 692 return node.getSubscriptions()
675
676 693
677 def setSubscriptionsOwner(self, nodeIdentifier, requestor, subscriptions, pep, recipient): 694 def setSubscriptionsOwner(self, nodeIdentifier, requestor, subscriptions, pep, recipient):
678 d = self.storage.getNode(nodeIdentifier, pep, recipient) 695 d = self.storage.getNode(nodeIdentifier, pep, recipient)
679 d.addCallback(_getAffiliation, requestor) 696 d.addCallback(_getAffiliation, requestor)
680 d.addCallback(self._doSetSubscriptionsOwner, requestor, subscriptions) 697 d.addCallback(self._doSetSubscriptionsOwner, requestor, subscriptions)
706 723
707 d = defer.gatherResults(d_list, consumeErrors=True) 724 d = defer.gatherResults(d_list, consumeErrors=True)
708 d.addCallback(lambda _: None) 725 d.addCallback(lambda _: None)
709 d.addErrback(self.unwrapFirstError) 726 d.addErrback(self.unwrapFirstError)
710 return d 727 return d
728
729 def filterItemsWithSchema(self, items_data, schema, owner):
730 """check schema restriction and remove fields/items if they don't comply
731
732 @param items_data(list[ItemData]): items to filter
733 items in this list will be modified
734 @param schema(domish.Element): node schema
735 @param owner(bool): True is requestor is a owner of the node
736 """
737 fields_to_remove = set()
738 for field_elt in schema.elements(data_form.NS_X_DATA, 'field'):
739 for restrict_elt in field_elt.elements(const.NS_SCHEMA_RESTRICT, 'restrict'):
740 read_restriction = restrict_elt.attributes.get('read')
741 if read_restriction is not None:
742 if read_restriction == 'owner':
743 if not owner:
744 fields_to_remove.add(field_elt['var'])
745 else:
746 raise StanzaError('feature-not-implemented', text='unknown read restriction {}'.format(read_restriction))
747 items_to_remove = []
748 for idx, item_data in enumerate(items_data):
749 item_elt = item_data.item
750 try:
751 x_elt = next(item_elt.elements(data_form.NS_X_DATA, 'x'))
752 except StopIteration:
753 log.msg("WARNING, item {id} has a schema but no form, ignoring it")
754 items_to_remove.append(item_data)
755 continue
756 form = data_form.Form.fromElement(x_elt)
757 # we remove fields which are not visible for this user
758 for field in fields_to_remove:
759 try:
760 form.removeField(form.fields[field])
761 except KeyError:
762 continue
763 item_elt.children.remove(x_elt)
764 item_elt.addChild(form.toElement())
765
766 for item_data in items_to_remove:
767 items_data.remove(item_data)
711 768
712 @defer.inlineCallbacks 769 @defer.inlineCallbacks
713 def checkNodeAccess(self, node, requestor): 770 def checkNodeAccess(self, node, requestor):
714 """check if a requestor can access data of a node 771 """check if a requestor can access data of a node
715 772
857 #FIXME 914 #FIXME
858 raise NotImplementedError 915 raise NotImplementedError
859 else: 916 else:
860 raise error.BadAccessTypeError(access_model) 917 raise error.BadAccessTypeError(access_model)
861 918
919 schema = node.getSchema()
920 if schema is not None:
921 self.filterItemsWithSchema(items_data, schema, owner)
922
862 yield self._items_rsm(items_data, node, requestor_groups, owner, itemIdentifiers, ext_data) 923 yield self._items_rsm(items_data, node, requestor_groups, owner, itemIdentifiers, ext_data)
863 defer.returnValue(items_data) 924 defer.returnValue(items_data)
864 925
865 def _setCount(self, value, response): 926 def _setCount(self, value, response):
866 response.count = value 927 response.count = value
970 1031
971 if notify: 1032 if notify:
972 d.addCallback(self._doNotifyRetraction, node, pep, recipient) 1033 d.addCallback(self._doNotifyRetraction, node, pep, recipient)
973 return d 1034 return d
974 1035
975
976 def _doNotifyRetraction(self, items_data, node, pep, recipient): 1036 def _doNotifyRetraction(self, items_data, node, pep, recipient):
977 self.dispatch({'items_data': items_data, 1037 self.dispatch({'items_data': items_data,
978 'node': node, 1038 'node': node,
979 'pep': pep, 1039 'pep': pep,
980 'recipient': recipient}, 1040 'recipient': recipient},
981 '//event/pubsub/retract') 1041 '//event/pubsub/retract')
982 1042
983
984 def purgeNode(self, nodeIdentifier, requestor, pep, recipient): 1043 def purgeNode(self, nodeIdentifier, requestor, pep, recipient):
985 d = self.storage.getNode(nodeIdentifier, pep, recipient) 1044 d = self.storage.getNode(nodeIdentifier, pep, recipient)
986 d.addCallback(_getAffiliation, requestor) 1045 d.addCallback(_getAffiliation, requestor)
987 d.addCallback(self._doPurge) 1046 d.addCallback(self._doPurge)
988 return d 1047 return d
989 1048
990
991 def _doPurge(self, result): 1049 def _doPurge(self, result):
992 node, affiliation = result 1050 node, affiliation = result
993 persistItems = node.getConfiguration()[const.OPT_PERSIST_ITEMS] 1051 persistItems = node.getConfiguration()[const.OPT_PERSIST_ITEMS]
994 1052
995 if affiliation != 'owner': 1053 if affiliation != 'owner':
1000 1058
1001 d = node.purge() 1059 d = node.purge()
1002 d.addCallback(self._doNotifyPurge, node.nodeIdentifier) 1060 d.addCallback(self._doNotifyPurge, node.nodeIdentifier)
1003 return d 1061 return d
1004 1062
1005
1006 def _doNotifyPurge(self, result, nodeIdentifier): 1063 def _doNotifyPurge(self, result, nodeIdentifier):
1007 self.dispatch(nodeIdentifier, '//event/pubsub/purge') 1064 self.dispatch(nodeIdentifier, '//event/pubsub/purge')
1008 1065
1009
1010 def registerPreDelete(self, preDeleteFn): 1066 def registerPreDelete(self, preDeleteFn):
1011 self._callbackList.append(preDeleteFn) 1067 self._callbackList.append(preDeleteFn)
1012
1013 1068
1014 def getSubscribers(self, nodeIdentifier, pep, recipient): 1069 def getSubscribers(self, nodeIdentifier, pep, recipient):
1015 def cb(subscriptions): 1070 def cb(subscriptions):
1016 return [subscription.subscriber for subscription in subscriptions] 1071 return [subscription.subscriber for subscription in subscriptions]
1017 1072
1018 d = self.storage.getNode(nodeIdentifier, pep, recipient) 1073 d = self.storage.getNode(nodeIdentifier, pep, recipient)
1019 d.addCallback(lambda node: node.getSubscriptions('subscribed')) 1074 d.addCallback(lambda node: node.getSubscriptions('subscribed'))
1020 d.addCallback(cb) 1075 d.addCallback(cb)
1021 return d 1076 return d
1022
1023 1077
1024 def deleteNode(self, nodeIdentifier, requestor, pep, recipient, redirectURI=None): 1078 def deleteNode(self, nodeIdentifier, requestor, pep, recipient, redirectURI=None):
1025 d = self.storage.getNode(nodeIdentifier, pep, recipient) 1079 d = self.storage.getNode(nodeIdentifier, pep, recipient)
1026 d.addCallback(_getAffiliation, requestor) 1080 d.addCallback(_getAffiliation, requestor)
1027 d.addCallback(self._doPreDelete, redirectURI, pep, recipient) 1081 d.addCallback(self._doPreDelete, redirectURI, pep, recipient)
1028 return d 1082 return d
1029 1083
1030
1031 def _doPreDelete(self, result, redirectURI, pep, recipient): 1084 def _doPreDelete(self, result, redirectURI, pep, recipient):
1032 node, affiliation = result 1085 node, affiliation = result
1033 1086
1034 if affiliation != 'owner': 1087 if affiliation != 'owner':
1035 raise error.Forbidden() 1088 raise error.Forbidden()
1039 1092
1040 d = defer.DeferredList([cb(data, pep, recipient) 1093 d = defer.DeferredList([cb(data, pep, recipient)
1041 for cb in self._callbackList], 1094 for cb in self._callbackList],
1042 consumeErrors=1) 1095 consumeErrors=1)
1043 d.addCallback(self._doDelete, node.nodeDbId) 1096 d.addCallback(self._doDelete, node.nodeDbId)
1044
1045 1097
1046 def _doDelete(self, result, nodeDbId): 1098 def _doDelete(self, result, nodeDbId):
1047 dl = [] 1099 dl = []
1048 for succeeded, r in result: 1100 for succeeded, r in result:
1049 if succeeded and r: 1101 if succeeded and r:
1052 d = self.storage.deleteNodeByDbId(nodeDbId) 1104 d = self.storage.deleteNodeByDbId(nodeDbId)
1053 d.addCallback(self._doNotifyDelete, dl) 1105 d.addCallback(self._doNotifyDelete, dl)
1054 1106
1055 return d 1107 return d
1056 1108
1057
1058 def _doNotifyDelete(self, result, dl): 1109 def _doNotifyDelete(self, result, dl):
1059 for d in dl: 1110 for d in dl:
1060 d.callback(None) 1111 d.callback(None)
1061
1062 1112
1063 1113
1064 class PubSubResourceFromBackend(pubsub.PubSubResource): 1114 class PubSubResourceFromBackend(pubsub.PubSubResource):
1065 """ 1115 """
1066 Adapts a backend to an xmpp publish-subscribe service. 1116 Adapts a backend to an xmpp publish-subscribe service.
1149 self.features.append("groupblog") 1199 self.features.append("groupblog")
1150 1200
1151 # if self.backend.supportsPublishModel(): #XXX: this feature is not really described in XEP-0060, we just can see it in examples 1201 # if self.backend.supportsPublishModel(): #XXX: this feature is not really described in XEP-0060, we just can see it in examples
1152 # self.features.append("publish_model") # but it's necessary for microblogging comments (see XEP-0277) 1202 # self.features.append("publish_model") # but it's necessary for microblogging comments (see XEP-0277)
1153 1203
1154
1155 def getFullItem(self, item_data): 1204 def getFullItem(self, item_data):
1156 """ Attach item configuration to this item 1205 """ Attach item configuration to this item
1157 1206
1158 Used to give item configuration back to node's owner (and *only* to owner) 1207 Used to give item configuration back to node's owner (and *only* to owner)
1159 """ 1208 """
1230 notifications_filtered) 1279 notifications_filtered)
1231 1280
1232 d = self._prepareNotify(items_data, node, data.get('subscription'), pep, recipient) 1281 d = self._prepareNotify(items_data, node, data.get('subscription'), pep, recipient)
1233 d.addCallback(afterPrepare) 1282 d.addCallback(afterPrepare)
1234 return d 1283 return d
1235
1236 1284
1237 @defer.inlineCallbacks 1285 @defer.inlineCallbacks
1238 def _prepareNotify(self, items_data, node, subscription=None, pep=None, recipient=None): 1286 def _prepareNotify(self, items_data, node, subscription=None, pep=None, recipient=None):
1239 """Do a bunch of permissions check and filter notifications 1287 """Do a bunch of permissions check and filter notifications
1240 1288
1270 1318
1271 # now we check access of subscriber for each item, and keep only allowed ones 1319 # now we check access of subscriber for each item, and keep only allowed ones
1272 1320
1273 #we filter items not allowed for the subscribers 1321 #we filter items not allowed for the subscribers
1274 notifications_filtered = [] 1322 notifications_filtered = []
1323 schema = node.getSchema()
1275 1324
1276 for subscriber, subscriptions, items_data in notifications: 1325 for subscriber, subscriptions, items_data in notifications:
1277 subscriber_bare = subscriber.userhostJID() 1326 subscriber_bare = subscriber.userhostJID()
1278 if subscriber_bare in owners: 1327 if subscriber_bare in owners:
1279 # as notification is always sent to owner, 1328 # as notification is always sent to owner,
1280 # we ignore owner if he is here 1329 # we ignore owner if he is here
1281 continue 1330 continue
1282 allowed_items = [] #we keep only item which subscriber can access 1331 allowed_items = [] #we keep only item which subscriber can access
1332
1333 if schema is not None:
1334 # we have to deepcopy items because different subscribers may receive
1335 # different items (e.g. read restriction in schema)
1336 items_data = deepcopy(items_data)
1337 self.backend.filterItemsWithSchema(items_data, schema, False)
1283 1338
1284 for item_data in items_data: 1339 for item_data in items_data:
1285 item, access_model = item_data.item, item_data.access_model 1340 item, access_model = item_data.item, item_data.access_model
1286 access_list = item_data.config 1341 access_list = item_data.config
1287 if access_model == const.VAL_AMODEL_OPEN: 1342 if access_model == const.VAL_AMODEL_OPEN:
1390 d = self.backend.getNodes(requestor.userhostJID(), 1445 d = self.backend.getNodes(requestor.userhostJID(),
1391 pep, 1446 pep,
1392 service) 1447 service)
1393 return d.addErrback(self._mapErrors) 1448 return d.addErrback(self._mapErrors)
1394 1449
1395
1396 def getConfigurationOptions(self): 1450 def getConfigurationOptions(self):
1397 return self.backend.nodeOptions 1451 return self.backend.nodeOptions
1398 1452
1399 def _publish_errb(self, failure, request): 1453 def _publish_errb(self, failure, request):
1400 if failure.type == error.NodeNotFound and self.backend.supportsAutoCreate(): 1454 if failure.type == error.NodeNotFound and self.backend.supportsAutoCreate():
1428 self._isPep(request), 1482 self._isPep(request),
1429 request.recipient) 1483 request.recipient)
1430 d.addErrback(self._publish_errb, request) 1484 d.addErrback(self._publish_errb, request)
1431 return d.addErrback(self._mapErrors) 1485 return d.addErrback(self._mapErrors)
1432 1486
1433
1434 def subscribe(self, request): 1487 def subscribe(self, request):
1435 d = self.backend.subscribe(request.nodeIdentifier, 1488 d = self.backend.subscribe(request.nodeIdentifier,
1436 request.subscriber, 1489 request.subscriber,
1437 request.sender, 1490 request.sender,
1438 self._isPep(request), 1491 self._isPep(request),
1439 request.recipient) 1492 request.recipient)
1440 return d.addErrback(self._mapErrors) 1493 return d.addErrback(self._mapErrors)
1441 1494
1442
1443 def unsubscribe(self, request): 1495 def unsubscribe(self, request):
1444 d = self.backend.unsubscribe(request.nodeIdentifier, 1496 d = self.backend.unsubscribe(request.nodeIdentifier,
1445 request.subscriber, 1497 request.subscriber,
1446 request.sender, 1498 request.sender,
1447 self._isPep(request), 1499 self._isPep(request),
1448 request.recipient) 1500 request.recipient)
1449 return d.addErrback(self._mapErrors) 1501 return d.addErrback(self._mapErrors)
1450 1502
1451
1452 def subscriptions(self, request): 1503 def subscriptions(self, request):
1453 d = self.backend.getSubscriptions(self._isPep(request), 1504 d = self.backend.getSubscriptions(self._isPep(request),
1454 request.sender) 1505 request.sender)
1455 return d.addErrback(self._mapErrors) 1506 return d.addErrback(self._mapErrors)
1456
1457 1507
1458 def affiliations(self, request): 1508 def affiliations(self, request):
1459 """Retrieve affiliation for normal entity (cf. XEP-0060 §5.7) 1509 """Retrieve affiliation for normal entity (cf. XEP-0060 §5.7)
1460 1510
1461 retrieve all node where this jid is affiliated 1511 retrieve all node where this jid is affiliated
1464 request.nodeIdentifier, 1514 request.nodeIdentifier,
1465 self._isPep(request), 1515 self._isPep(request),
1466 request.recipient) 1516 request.recipient)
1467 return d.addErrback(self._mapErrors) 1517 return d.addErrback(self._mapErrors)
1468 1518
1469
1470 def create(self, request): 1519 def create(self, request):
1471 d = self.backend.createNode(request.nodeIdentifier, 1520 d = self.backend.createNode(request.nodeIdentifier,
1472 request.sender, request.options, 1521 request.sender, request.options,
1473 self._isPep(request), 1522 self._isPep(request),
1474 request.recipient) 1523 request.recipient)
1475 return d.addErrback(self._mapErrors) 1524 return d.addErrback(self._mapErrors)
1476 1525
1477
1478 def default(self, request): 1526 def default(self, request):
1479 d = self.backend.getDefaultConfiguration(request.nodeType, 1527 d = self.backend.getDefaultConfiguration(request.nodeType,
1480 self._isPep(request), 1528 self._isPep(request),
1481 request.sender) 1529 request.sender)
1482 return d.addErrback(self._mapErrors) 1530 return d.addErrback(self._mapErrors)
1483 1531
1484
1485 def configureGet(self, request): 1532 def configureGet(self, request):
1486 d = self.backend.getNodeConfiguration(request.nodeIdentifier, 1533 d = self.backend.getNodeConfiguration(request.nodeIdentifier,
1487 self._isPep(request), 1534 self._isPep(request),
1488 request.recipient) 1535 request.recipient)
1489 return d.addErrback(self._mapErrors) 1536 return d.addErrback(self._mapErrors)
1490
1491 1537
1492 def configureSet(self, request): 1538 def configureSet(self, request):
1493 d = self.backend.setNodeConfiguration(request.nodeIdentifier, 1539 d = self.backend.setNodeConfiguration(request.nodeIdentifier,
1494 request.options, 1540 request.options,
1495 request.sender, 1541 request.sender,
1496 self._isPep(request), 1542 self._isPep(request),
1497 request.recipient) 1543 request.recipient)
1498 return d.addErrback(self._mapErrors) 1544 return d.addErrback(self._mapErrors)
1499 1545
1500
1501 def affiliationsGet(self, request): 1546 def affiliationsGet(self, request):
1502 """Retrieve affiliations for owner (cf. XEP-0060 §8.9.1) 1547 """Retrieve affiliations for owner (cf. XEP-0060 §8.9.1)
1503 1548
1504 retrieve all affiliations for a node 1549 retrieve all affiliations for a node
1505 """ 1550 """
1515 request.affiliations, 1560 request.affiliations,
1516 self._isPep(request), 1561 self._isPep(request),
1517 request.recipient) 1562 request.recipient)
1518 return d.addErrback(self._mapErrors) 1563 return d.addErrback(self._mapErrors)
1519 1564
1520
1521 def subscriptionsGet(self, request): 1565 def subscriptionsGet(self, request):
1522 """Retrieve subscriptions for owner (cf. XEP-0060 §8.8.1) 1566 """Retrieve subscriptions for owner (cf. XEP-0060 §8.8.1)
1523 1567
1524 retrieve all affiliations for a node 1568 retrieve all affiliations for a node
1525 """ 1569 """
1527 request.sender, 1571 request.sender,
1528 self._isPep(request), 1572 self._isPep(request),
1529 request.recipient) 1573 request.recipient)
1530 return d.addErrback(self._mapErrors) 1574 return d.addErrback(self._mapErrors)
1531 1575
1532
1533 def subscriptionsSet(self, request): 1576 def subscriptionsSet(self, request):
1534 d = self.backend.setSubscriptionsOwner(request.nodeIdentifier, 1577 d = self.backend.setSubscriptionsOwner(request.nodeIdentifier,
1535 request.sender, 1578 request.sender,
1536 request.subscriptions, 1579 request.subscriptions,
1537 self._isPep(request), 1580 self._isPep(request),
1538 request.recipient) 1581 request.recipient)
1539 return d.addErrback(self._mapErrors) 1582 return d.addErrback(self._mapErrors)
1540
1541 1583
1542 def items(self, request): 1584 def items(self, request):
1543 ext_data = {} 1585 ext_data = {}
1544 if const.FLAG_ENABLE_RSM and request.rsm is not None: 1586 if const.FLAG_ENABLE_RSM and request.rsm is not None:
1545 ext_data['rsm'] = request.rsm 1587 ext_data['rsm'] = request.rsm
1562 request.notify, 1604 request.notify,
1563 self._isPep(request), 1605 self._isPep(request),
1564 request.recipient) 1606 request.recipient)
1565 return d.addErrback(self._mapErrors) 1607 return d.addErrback(self._mapErrors)
1566 1608
1567
1568 def purge(self, request): 1609 def purge(self, request):
1569 d = self.backend.purgeNode(request.nodeIdentifier, 1610 d = self.backend.purgeNode(request.nodeIdentifier,
1570 request.sender, 1611 request.sender,
1571 self._isPep(request), 1612 self._isPep(request),
1572 request.recipient) 1613 request.recipient)
1573 return d.addErrback(self._mapErrors) 1614 return d.addErrback(self._mapErrors)
1574 1615
1575
1576 def delete(self, request): 1616 def delete(self, request):
1577 d = self.backend.deleteNode(request.nodeIdentifier, 1617 d = self.backend.deleteNode(request.nodeIdentifier,
1578 request.sender, 1618 request.sender,
1579 self._isPep(request), 1619 self._isPep(request),
1580 request.recipient) 1620 request.recipient)