Commit 268fd5a9 authored by 's avatar

- resolved a circular import issue by moving TaintedString out of ZPublisher

parent e2266001
...@@ -11,6 +11,9 @@ Trunk (unreleased) ...@@ -11,6 +11,9 @@ Trunk (unreleased)
Restructuring Restructuring
+++++++++++++ +++++++++++++
- Moved TaintedString from ZPublisher to Shared.
This resolves a circular import issue.
- Moved zope.formlib / zope.app.form integration into a separate package - Moved zope.formlib / zope.app.form integration into a separate package
called five.formlib. called five.formlib.
......
...@@ -12,9 +12,13 @@ ...@@ -12,9 +12,13 @@
############################################################################## ##############################################################################
"""DTML Utilities """DTML Utilities
$Id$""" $Id$
"""
import re import re
import string
from types import BuiltinFunctionType
from types import FunctionType
# for import by other modules, dont remove! # for import by other modules, dont remove!
from DocumentTemplate.html_quote import html_quote, ustr from DocumentTemplate.html_quote import html_quote, ustr
...@@ -27,6 +31,8 @@ from RestrictedPython.Guards import safe_builtins ...@@ -27,6 +31,8 @@ from RestrictedPython.Guards import safe_builtins
from RestrictedPython.Utilities import utility_builtins from RestrictedPython.Utilities import utility_builtins
from RestrictedPython.Eval import RestrictionCapableEval from RestrictedPython.Eval import RestrictionCapableEval
from Shared.TaintedString import TaintedString
test = utility_builtins['test'] # for backwards compatibility, dont remove! test = utility_builtins['test'] # for backwards compatibility, dont remove!
LIMITED_BUILTINS = 1 LIMITED_BUILTINS = 1
...@@ -68,13 +74,9 @@ if LIMITED_BUILTINS: ...@@ -68,13 +74,9 @@ if LIMITED_BUILTINS:
f = NotBindable(f) f = NotBindable(f)
setattr(TemplateDict, name, f) setattr(TemplateDict, name, f)
try: # Wrap the string module so it can deal with TaintedString strings.
# Wrap the string module so it can deal with TaintedString strings. class StringModuleWrapper:
from ZPublisher.TaintedString import TaintedString
from types import FunctionType, BuiltinFunctionType, StringType
import string
class StringModuleWrapper:
def __getattr__(self, key): def __getattr__(self, key):
attr = getattr(string, key) attr = getattr(string, key)
if (isinstance(attr, FunctionType) or if (isinstance(attr, FunctionType) or
...@@ -83,7 +85,8 @@ try: ...@@ -83,7 +85,8 @@ try:
else: else:
return attr return attr
class StringFunctionWrapper: class StringFunctionWrapper:
def __init__(self, method): def __init__(self, method):
self._method = method self._method = method
...@@ -101,15 +104,11 @@ try: ...@@ -101,15 +104,11 @@ try:
args = tuple(args) args = tuple(args)
retval = self._method(*args, **kw) retval = self._method(*args, **kw)
if tainted and isinstance(retval, StringType) and '<' in retval: if tainted and isinstance(retval, str) and '<' in retval:
retval = TaintedString(retval) retval = TaintedString(retval)
return retval return retval
TemplateDict.string = StringModuleWrapper() TemplateDict.string = StringModuleWrapper()
except ImportError:
# Use the string module already defined in RestrictedPython.Utilities
pass
# The functions below are meant to bind to the TemplateDict. # The functions below are meant to bind to the TemplateDict.
......
...@@ -7,10 +7,10 @@ ...@@ -7,10 +7,10 @@
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE # FOR A PARTICULAR PURPOSE.
# #
############################################################################## ##############################################################################
__doc__='''Variable insertion parameters """Variable insertion parameters
When inserting variables, parameters may be specified to When inserting variables, parameters may be specified to
control how the data will be formatted. In HTML source, the control how the data will be formatted. In HTML source, the
...@@ -149,14 +149,10 @@ Evaluating expressions without rendering results ...@@ -149,14 +149,10 @@ Evaluating expressions without rendering results
A 'call' tag is provided for evaluating named objects or expressions A 'call' tag is provided for evaluating named objects or expressions
without rendering the result. without rendering the result.
$Id$
''' # ' """
__rcs_id__='$Id$'
__version__='$Revision: 1.60 $'[11:-2]
import string, re, sys import string, re, sys
from cgi import escape
from urllib import quote, quote_plus, unquote, unquote_plus from urllib import quote, quote_plus, unquote, unquote_plus
# for import by other modules, dont remove! # for import by other modules, dont remove!
...@@ -164,8 +160,8 @@ from DocumentTemplate.html_quote import html_quote ...@@ -164,8 +160,8 @@ from DocumentTemplate.html_quote import html_quote
from DocumentTemplate.DT_Util import parse_params, name_param, str, ustr from DocumentTemplate.DT_Util import parse_params, name_param, str, ustr
from Acquisition import aq_base from Acquisition import aq_base
from ZPublisher.TaintedString import TaintedString from Shared.TaintedString import TaintedString
from zope.structuredtext.html import HTMLWithImages, HTML from zope.structuredtext.html import HTML
from zope.structuredtext.document import DocumentWithImages from zope.structuredtext.document import DocumentWithImages
from App.config import getConfiguration from App.config import getConfiguration
......
...@@ -44,14 +44,13 @@ class TestNewlineToBr(doctest.DocTestCase): ...@@ -44,14 +44,13 @@ class TestNewlineToBr(doctest.DocTestCase):
True True
""" """
def test_newline_to_br_tainted(self): def test_newline_to_br_tainted(self):
""" """
>>> text = ''' >>> text = '''
... <li>line one</li> ... <li>line one</li>
... <li>line two</li> ... <li>line two</li>
... ''' ... '''
>>> from ZPublisher.TaintedString import TaintedString >>> from Shared.TaintedString import TaintedString
>>> tainted = TaintedString(text) >>> tainted = TaintedString(text)
>>> print DT_Var.newline_to_br(tainted) >>> print DT_Var.newline_to_br(tainted)
<br /> <br />
......
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors. All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
""" TaintedString implementation.
TaintedStrings hold potentially dangerous untrusted data; anything that could
possibly hold HTML is considered dangerous. DTML code will use the quoted
value of this string, and raised exceptions in Zope will use the repr()
conversion.
$Id$
"""
from cgi import escape
class TaintedString:
def __init__(self, value):
self._value = value
def __str__(self):
return self._value
def __repr__(self):
return repr(self.quoted())
def __cmp__(self, o):
return cmp(self._value, o)
def __hash__(self):
return hash(self._value)
def __len__(self):
return len(self._value)
def __getitem__(self, index):
v = self._value[index]
if '<' in v:
v = self.__class__(v)
return v
def __getslice__(self, i, j):
i = max(i, 0)
j = max(j, 0)
v = self._value[i:j]
if '<' in v:
v = self.__class__(v)
return v
def __add__(self, o):
return self.__class__(self._value + o)
def __radd__(self, o):
return self.__class__(o + self._value)
def __mul__(self, o):
return self.__class__(self._value * o)
def __rmul__(self, o):
return self.__class__(o * self._value)
def __mod__(self, o):
return self.__class__(self._value % o)
def __int__(self):
return int(self._value)
def __float__(self):
return float(self._value)
def __long__(self):
return long(self._value)
def __getstate__(self):
# If an object tries to store a TaintedString, it obviously wasn't aware
# that it was playing with untrusted data. Complain acordingly.
raise SystemError("A TaintedString cannot be pickled. Code that "
"caused this TaintedString to be stored should be more careful "
"with untrusted data from the REQUEST.")
def __getattr__(self, a):
# for string methods support other than those defined below
return getattr(self._value, a)
# Python 2.2 only.
def decode(self, *args):
return self.__class__(self._value.decode(*args))
def encode(self, *args):
return self.__class__(self._value.encode(*args))
def expandtabs(self, *args):
return self.__class__(self._value.expandtabs(*args))
def replace(self, *args):
v = self._value.replace(*args)
if '<' in v:
v = self.__class__(v)
return v
def split(self, *args):
r = self._value.split(*args)
return map(lambda v, c=self.__class__: '<' in v and c(v) or v, r)
def splitlines(self, *args):
r = self._value.splitlines(*args)
return map(lambda v, c=self.__class__: '<' in v and c(v) or v, r)
def translate(self, *args):
v = self._value.translate(*args)
if '<' in v:
v = self.__class__(v)
return v
def quoted(self):
return escape(self._value, 1)
# As called by cDocumentTemplate
__untaint__ = quoted
def createSimpleWrapper(func):
return lambda s, f=func: s.__class__(getattr(s._value, f)())
def createOneArgWrapper(func):
return lambda s, a, f=func: s.__class__(getattr(s._value, f)(a))
def createOneOptArgWrapper(func):
return lambda s, a=None, f=func: s.__class__(getattr(s._value, f)(a))
simpleWrappedMethods = \
"capitalize lower swapcase title upper".split()
oneArgWrappedMethods = "center join ljust rjust".split()
oneOptArgWrappedMethods = "lstrip rstrip strip".split()
for f in simpleWrappedMethods:
setattr(TaintedString, f, createSimpleWrapper(f))
for f in oneArgWrappedMethods:
setattr(TaintedString, f, createOneArgWrapper(f))
for f in oneOptArgWrappedMethods:
setattr(TaintedString, f, createOneOptArgWrapper(f))
...@@ -7,20 +7,25 @@ ...@@ -7,20 +7,25 @@
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE # FOR A PARTICULAR PURPOSE.
# #
############################################################################## ##############################################################################
""" TaintedString tests.
$Id$
"""
import unittest import unittest
class TestTaintedString(unittest.TestCase): class TestTaintedString(unittest.TestCase):
def setUp(self): def setUp(self):
self.unquoted = '<test attr="&">' self.unquoted = '<test attr="&">'
self.quoted = '&lt;test attr=&quot;&amp;&quot;&gt;' self.quoted = '&lt;test attr=&quot;&amp;&quot;&gt;'
self.tainted = self._getClass()(self.unquoted) self.tainted = self._getClass()(self.unquoted)
def _getClass(self): def _getClass(self):
from ZPublisher.TaintedString import TaintedString from Shared.TaintedString import TaintedString
return TaintedString return TaintedString
def testStr(self): def testStr(self):
...@@ -152,21 +157,8 @@ class TestTaintedString(unittest.TestCase): ...@@ -152,21 +157,8 @@ class TestTaintedString(unittest.TestCase):
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestTaintedString, 'test')) suite.addTest(unittest.makeSuite(TestTaintedString))
return suite return suite
def main(): if __name__ == '__main__':
unittest.TextTestRunner().run(test_suite()) unittest.main(defaultTest='test_suite')
def debug():
test_suite().debug()
def pdebug():
import pdb
pdb.run('debug()')
if __name__=='__main__':
if len(sys.argv) > 1:
globals()[sys.argv[1]]()
else:
main()
...@@ -38,12 +38,12 @@ from zope.interface import implements ...@@ -38,12 +38,12 @@ from zope.interface import implements
from zope.publisher.base import DebugFlags from zope.publisher.base import DebugFlags
from zope.publisher.interfaces.browser import IBrowserRequest from zope.publisher.interfaces.browser import IBrowserRequest
from Shared.TaintedString import TaintedString
from ZPublisher.BaseRequest import BaseRequest from ZPublisher.BaseRequest import BaseRequest
from ZPublisher.BaseRequest import quote from ZPublisher.BaseRequest import quote
from ZPublisher.Converters import get_converter from ZPublisher.Converters import get_converter
from ZPublisher.HTTPResponse import HTTPResponse from ZPublisher.HTTPResponse import HTTPResponse
from ZPublisher.maybe_lock import allocate_lock from ZPublisher.maybe_lock import allocate_lock
from ZPublisher.TaintedString import TaintedString
# Flags # Flags
SEQUENCE = 1 SEQUENCE = 1
......
...@@ -7,145 +7,16 @@ ...@@ -7,145 +7,16 @@
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE # FOR A PARTICULAR PURPOSE.
# #
############################################################################## ##############################################################################
"""TaintedString legacy module.
__version__='$Revision: 1.2 $'[11:-2] $Id$
"""
from cgi import escape from zope.deferredimport import deprecated
deprecated('ZPublisher.TaintedString will be removed in Zope 2.14. Please '
'import from Shared.TaintedString instead.',
# TaintedStrings hold potentially dangerous untrusted data; anything that could TaintedString = 'Shared.TaintedString:TaintedString',
# possibly hold HTML is considered dangerous. DTML code will use the quoted )
# value of this tring, and raised exceptions in Zope will use the repr()
# conversion.
class TaintedString:
def __init__(self, value):
self._value = value
def __str__(self):
return self._value
def __repr__(self):
return repr(self.quoted())
def __cmp__(self, o):
return cmp(self._value, o)
def __hash__(self):
return hash(self._value)
def __len__(self):
return len(self._value)
def __getitem__(self, index):
v = self._value[index]
if '<' in v:
v = self.__class__(v)
return v
def __getslice__(self, i, j):
i = max(i, 0)
j = max(j, 0)
v = self._value[i:j]
if '<' in v:
v = self.__class__(v)
return v
def __add__(self, o):
return self.__class__(self._value + o)
def __radd__(self, o):
return self.__class__(o + self._value)
def __mul__(self, o):
return self.__class__(self._value * o)
def __rmul__(self, o):
return self.__class__(o * self._value)
def __mod__(self, o):
return self.__class__(self._value % o)
def __int__(self):
return int(self._value)
def __float__(self):
return float(self._value)
def __long__(self):
return long(self._value)
def __getstate__(self):
# If an object tries to store a TaintedString, it obviously wasn't aware
# that it was playing with untrusted data. Complain acordingly.
raise SystemError("A TaintedString cannot be pickled. Code that "
"caused this TaintedString to be stored should be more careful "
"with untrusted data from the REQUEST.")
def __getattr__(self, a):
# for string methods support other than those defined below
return getattr(self._value, a)
# Python 2.2 only.
def decode(self, *args):
return self.__class__(self._value.decode(*args))
def encode(self, *args):
return self.__class__(self._value.encode(*args))
def expandtabs(self, *args):
return self.__class__(self._value.expandtabs(*args))
def replace(self, *args):
v = self._value.replace(*args)
if '<' in v:
v = self.__class__(v)
return v
def split(self, *args):
r = self._value.split(*args)
return map(lambda v, c=self.__class__: '<' in v and c(v) or v, r)
def splitlines(self, *args):
r = self._value.splitlines(*args)
return map(lambda v, c=self.__class__: '<' in v and c(v) or v, r)
def translate(self, *args):
v = self._value.translate(*args)
if '<' in v:
v = self.__class__(v)
return v
def quoted(self):
return escape(self._value, 1)
# As called by cDocumentTemplate
__untaint__ = quoted
def createSimpleWrapper(func):
return lambda s, f=func: s.__class__(getattr(s._value, f)())
def createOneArgWrapper(func):
return lambda s, a, f=func: s.__class__(getattr(s._value, f)(a))
def createOneOptArgWrapper(func):
return lambda s, a=None, f=func: s.__class__(getattr(s._value, f)(a))
simpleWrappedMethods = \
"capitalize lower swapcase title upper".split()
oneArgWrappedMethods = "center join ljust rjust".split()
oneOptArgWrappedMethods = "lstrip rstrip strip".split()
for f in simpleWrappedMethods:
setattr(TaintedString, f, createSimpleWrapper(f))
for f in oneArgWrappedMethods:
setattr(TaintedString, f, createOneArgWrapper(f))
for f in oneOptArgWrappedMethods:
setattr(TaintedString, f, createOneOptArgWrapper(f))
...@@ -71,7 +71,7 @@ class HTTPRequestTests(unittest.TestCase): ...@@ -71,7 +71,7 @@ class HTTPRequestTests(unittest.TestCase):
# Also raises an Assertion if a string which *should* have been # Also raises an Assertion if a string which *should* have been
# tainted is found, or when a tainted string is not deemed dangerous. # tainted is found, or when a tainted string is not deemed dangerous.
from ZPublisher.HTTPRequest import record from ZPublisher.HTTPRequest import record
from ZPublisher.TaintedString import TaintedString from Shared.TaintedString import TaintedString
retval = 0 retval = 0
...@@ -1015,8 +1015,12 @@ test %s ...@@ -1015,8 +1015,12 @@ test %s
''' % ('test' * 1000) ''' % ('test' * 1000)
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(RecordTests, 'test')) suite.addTest(unittest.makeSuite(RecordTests))
suite.addTest(unittest.makeSuite(HTTPRequestTests, 'test')) suite.addTest(unittest.makeSuite(HTTPRequestTests))
return suite return suite
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
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