[views/primary] some inner sections should use the `limit` by default to avoid a denial of service (closes #2719110)
authorAurelien Campeas <aurelien.campeas@logilab.fr>
Tue, 19 Mar 2013 15:30:06 +0100
changeset 8736 b84a233cb8b0
parent 8735 5567a5117aeb
child 8737 d95cbb7349f0
[views/primary] some inner sections should use the `limit` by default to avoid a denial of service (closes #2719110) Today, it is possible to call .related and get a huge unlimited database-dos-inducing resultset that will be nevertheless limited a bit further in pure python in the `autolimited` view. While we cannot completely avoid potential denial of services such as these we mitigate the problem with the default ui settings: if the inner vid is `autolimited`, then the relation result sets is computed using the user-defined limit. This change respects the semantics of the `autolimited` view and shouldn't break anything.
web/views/primary.py
--- a/web/views/primary.py	Tue Mar 19 15:18:22 2013 +0100
+++ b/web/views/primary.py	Tue Mar 19 15:30:06 2013 +0100
@@ -234,6 +234,7 @@
 
     def render_entity_relations(self, entity):
         """Renders all relations in the 'relations' section."""
+        defaultlimit = self._cw.property_value('navigation.related-limit')
         for rschema, tschemas, role, dispctrl in self._section_def(entity, 'relations'):
             if rschema.final or dispctrl.get('rtypevid'):
                 vid = dispctrl.get('vid', 'reledit')
@@ -247,7 +248,9 @@
                 value = rview.render(row=entity.cw_row, col=entity.cw_col,
                                      rtype=rschema.type, role=role)
             else:
-                rset = self._relation_rset(entity, rschema, role, dispctrl)
+                vid = dispctrl.get('vid', 'autolimited')
+                limit = defaultlimit if vid == 'autolimited' else None
+                rset = self._relation_rset(entity, rschema, role, dispctrl, limit=limit)
                 if not rset:
                     continue
                 if hasattr(self, '_render_relation'):
@@ -257,7 +260,6 @@
                          'been renamed to render_relation, please update %s'
                          % self.__class__, DeprecationWarning)
                     continue
-                vid = dispctrl.get('vid', 'autolimited')
                 try:
                     rview = self._cw.vreg['views'].select(
                         vid, self._cw, rset=rset, dispctrl=dispctrl)
@@ -301,12 +303,14 @@
     def _prepare_side_boxes(self, entity):
         sideboxes = []
         boxesreg = self._cw.vreg['ctxcomponents']
+        defaultlimit = self._cw.property_value('navigation.related-limit')
         for rschema, tschemas, role, dispctrl in self._section_def(entity, 'sideboxes'):
-            rset = self._relation_rset(entity, rschema, role, dispctrl)
+            vid = dispctrl.get('vid', 'autolimited')
+            limit = defaultlimit if vid == 'autolimited' else None
+            rset = self._relation_rset(entity, rschema, role, dispctrl, limit=limit)
             if not rset:
                 continue
             label = self._rel_label(entity, rschema, role, dispctrl)
-            vid = dispctrl.get('vid', 'autolimited')
             box = boxesreg.select('rsetbox', self._cw, rset=rset,
                                   vid=vid, title=label, dispctrl=dispctrl,
                                   context='incontext')
@@ -339,9 +343,9 @@
                 rdefs.append( (rschema, matchtschemas, role, dispctrl) )
         return sorted(rdefs, key=lambda x: x[-1]['order'])
 
-    def _relation_rset(self, entity, rschema, role, dispctrl):
+    def _relation_rset(self, entity, rschema, role, dispctrl, limit=None):
         try:
-            rset = entity.related(rschema.type, role)
+            rset = entity.related(rschema.type, role, limit=limit)
         except Unauthorized:
             return
         if 'filter' in dispctrl: