Fix #2141: TALES doesn't traverse correctly over 'repeat' variable

parent baa7ef3b
...@@ -18,6 +18,9 @@ Zope Changes ...@@ -18,6 +18,9 @@ Zope Changes
Bugs Fixed Bugs Fixed
- Fix #2141: TALES doesn't traverse correctly over 'repeat'
variable
- reStructuredText/ZReST: setting raw_enabled to 0 for security - reStructuredText/ZReST: setting raw_enabled to 0 for security
reasons reasons
......
...@@ -28,6 +28,7 @@ from zope.proxy import removeAllProxies ...@@ -28,6 +28,7 @@ from zope.proxy import removeAllProxies
import zope.app.pagetemplate.engine import zope.app.pagetemplate.engine
import OFS.interfaces import OFS.interfaces
from MultiMapping import MultiMapping
from Acquisition import aq_base from Acquisition import aq_base
from zExceptions import NotFound, Unauthorized from zExceptions import NotFound, Unauthorized
from Products.Five.browser.providerexpression import Z2ProviderExpression from Products.Five.browser.providerexpression import Z2ProviderExpression
...@@ -140,8 +141,32 @@ class ZopePathExpr(PathExpr): ...@@ -140,8 +141,32 @@ class ZopePathExpr(PathExpr):
return 1 return 1
return 0 return 0
class SafeMapping(MultiMapping):
"""Mapping with security declarations and limited method exposure.
Since it subclasses MultiMapping, this class can be used to wrap
one or more mapping objects. Restricted Python code will not be
able to mutate the SafeMapping or the wrapped mappings, but will be
able to read any value.
"""
__allow_access_to_unprotected_subobjects__ = True
push = pop = None
_push = MultiMapping.push
_pop = MultiMapping.pop
class ZopeContext(Context): class ZopeContext(Context):
def __init__(self, engine, contexts):
super(ZopeContext, self).__init__(engine, contexts)
# wrap the top-level 'repeat' variable, as it is visible to
# restricted code
self.setContext('repeat', SafeMapping(self.repeat_vars))
# regenerate the first scope and the scope stack after messing
# with the global context
self.vars = vars = contexts.copy()
self._vars_stack = [vars]
def translate(self, msgid, domain=None, mapping=None, default=None): def translate(self, msgid, domain=None, mapping=None, default=None):
context = self.contexts.get('context') context = self.contexts.get('context')
return getGlobalTranslationService().translate( return getGlobalTranslationService().translate(
......
...@@ -56,8 +56,6 @@ class PageTemplateFile(SimpleItem, Script, PageTemplate, Traversable): ...@@ -56,8 +56,6 @@ class PageTemplateFile(SimpleItem, Script, PageTemplate, Traversable):
security.declareProtected('View management screens', security.declareProtected('View management screens',
'read', 'document_src') 'read', 'document_src')
_default_bindings = {'name_subpath': 'traverse_subpath'}
def __init__(self, filename, _prefix=None, **kw): def __init__(self, filename, _prefix=None, **kw):
name = kw.pop('__name__', None) name = kw.pop('__name__', None)
......
...@@ -19,21 +19,7 @@ $Id$ ...@@ -19,21 +19,7 @@ $Id$
from zope.tales.tests.simpleexpr import SimpleExpr from zope.tales.tests.simpleexpr import SimpleExpr
from zope.tales.tales import ExpressionEngine as Engine from zope.tales.tales import ExpressionEngine as Engine
from zope.tales.tales import _default as Default from zope.tales.tales import _default as Default
from Products.PageTemplates.Expressions import SafeMapping
from MultiMapping import MultiMapping
class SafeMapping(MultiMapping):
'''Mapping with security declarations and limited method exposure.
Since it subclasses MultiMapping, this class can be used to wrap
one or more mapping objects. Restricted Python code will not be
able to mutate the SafeMapping or the wrapped mappings, but will be
able to read any value.
'''
__allow_access_to_unprotected_subobjects__ = 1
push = pop = None
_push = MultiMapping.push
_pop = MultiMapping.pop
import zope.deprecation import zope.deprecation
zope.deprecation.moved("zope.tales.tales", "2.12") zope.deprecation.moved("zope.tales.tales", "2.12")
<html>
<body>
<ol tal:define="results python:range(5)">
<tal:block tal:repeat="items results">
<li tal:define="odd repeat/items/odd"
tal:content="python:odd and 'odd' or 'even'">Content</li>
</tal:block>
</ol>
</body>
</html>
<html>
<body>
<ol>
<li>even</li>
<li>odd</li>
<li>even</li>
<li>odd</li>
<li>even</li>
</ol>
</body>
</html>
...@@ -74,7 +74,7 @@ class ExpressionTests(zope.component.testing.PlacelessSetup, unittest.TestCase): ...@@ -74,7 +74,7 @@ class ExpressionTests(zope.component.testing.PlacelessSetup, unittest.TestCase):
ec = self.ec ec = self.ec
ec.beginScope() ec.beginScope()
ec.setRepeat('loop', "python:[1,2,3]") ec.setRepeat('loop', "python:[1,2,3]")
assert ec.evaluate("python:repeat['loop'].even()") assert ec.evaluate("python:repeat['loop'].odd()")
ec.endScope() ec.endScope()
def testWrappers(self): def testWrappers(self):
......
...@@ -165,6 +165,9 @@ class HTMLTests(zope.component.testing.PlacelessSetup, unittest.TestCase): ...@@ -165,6 +165,9 @@ class HTMLTests(zope.component.testing.PlacelessSetup, unittest.TestCase):
def checkImportOldStyleClass(self): def checkImportOldStyleClass(self):
self.assert_expected(self.folder.t, 'CheckImportOldStyleClass.html') self.assert_expected(self.folder.t, 'CheckImportOldStyleClass.html')
def checkRepeatVariable(self):
self.assert_expected(self.folder.t, 'RepeatVariable.html')
def test_suite(): def test_suite():
return unittest.makeSuite(HTMLTests, 'check') return unittest.makeSuite(HTMLTests, 'check')
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment