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)
Restructuring
+++++++++++++
- Moved TaintedString from ZPublisher to Shared.
This resolves a circular import issue.
- Moved zope.formlib / zope.app.form integration into a separate package
called five.formlib.
......
......@@ -12,9 +12,13 @@
##############################################################################
"""DTML Utilities
$Id$"""
$Id$
"""
import re
import string
from types import BuiltinFunctionType
from types import FunctionType
# for import by other modules, dont remove!
from DocumentTemplate.html_quote import html_quote, ustr
......@@ -27,6 +31,8 @@ from RestrictedPython.Guards import safe_builtins
from RestrictedPython.Utilities import utility_builtins
from RestrictedPython.Eval import RestrictionCapableEval
from Shared.TaintedString import TaintedString
test = utility_builtins['test'] # for backwards compatibility, dont remove!
LIMITED_BUILTINS = 1
......@@ -68,48 +74,41 @@ if LIMITED_BUILTINS:
f = NotBindable(f)
setattr(TemplateDict, name, f)
try:
# Wrap the string module so it can deal with TaintedString strings.
from ZPublisher.TaintedString import TaintedString
from types import FunctionType, BuiltinFunctionType, StringType
import string
class StringModuleWrapper:
def __getattr__(self, key):
attr = getattr(string, key)
if (isinstance(attr, FunctionType) or
isinstance(attr, BuiltinFunctionType)):
return StringFunctionWrapper(attr)
else:
return attr
class StringFunctionWrapper:
def __init__(self, method):
self._method = method
def __call__(self, *args, **kw):
tainted = 0
args = list(args)
for i in range(len(args)):
if isinstance(args[i], TaintedString):
tainted = 1
args[i] = str(args[i])
for k, v in kw.items():
if isinstance(v, TaintedString):
tainted = 1
kw[k] = str(v)
args = tuple(args)
retval = self._method(*args, **kw)
if tainted and isinstance(retval, StringType) and '<' in retval:
retval = TaintedString(retval)
return retval
TemplateDict.string = StringModuleWrapper()
except ImportError:
# Use the string module already defined in RestrictedPython.Utilities
pass
# Wrap the string module so it can deal with TaintedString strings.
class StringModuleWrapper:
def __getattr__(self, key):
attr = getattr(string, key)
if (isinstance(attr, FunctionType) or
isinstance(attr, BuiltinFunctionType)):
return StringFunctionWrapper(attr)
else:
return attr
class StringFunctionWrapper:
def __init__(self, method):
self._method = method
def __call__(self, *args, **kw):
tainted = 0
args = list(args)
for i in range(len(args)):
if isinstance(args[i], TaintedString):
tainted = 1
args[i] = str(args[i])
for k, v in kw.items():
if isinstance(v, TaintedString):
tainted = 1
kw[k] = str(v)
args = tuple(args)
retval = self._method(*args, **kw)
if tainted and isinstance(retval, str) and '<' in retval:
retval = TaintedString(retval)
return retval
TemplateDict.string = StringModuleWrapper()
# The functions below are meant to bind to the TemplateDict.
......
......@@ -7,10 +7,10 @@
# 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
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
__doc__='''Variable insertion parameters
"""Variable insertion parameters
When inserting variables, parameters may be specified to
control how the data will be formatted. In HTML source, the
......@@ -149,14 +149,10 @@ Evaluating expressions without rendering results
A 'call' tag is provided for evaluating named objects or expressions
without rendering the result.
''' # '
__rcs_id__='$Id$'
__version__='$Revision: 1.60 $'[11:-2]
$Id$
"""
import string, re, sys
from cgi import escape
from urllib import quote, quote_plus, unquote, unquote_plus
# for import by other modules, dont remove!
......@@ -164,8 +160,8 @@ from DocumentTemplate.html_quote import html_quote
from DocumentTemplate.DT_Util import parse_params, name_param, str, ustr
from Acquisition import aq_base
from ZPublisher.TaintedString import TaintedString
from zope.structuredtext.html import HTMLWithImages, HTML
from Shared.TaintedString import TaintedString
from zope.structuredtext.html import HTML
from zope.structuredtext.document import DocumentWithImages
from App.config import getConfiguration
......
......@@ -44,14 +44,13 @@ class TestNewlineToBr(doctest.DocTestCase):
True
"""
def test_newline_to_br_tainted(self):
"""
>>> text = '''
... <li>line one</li>
... <li>line two</li>
... '''
>>> from ZPublisher.TaintedString import TaintedString
>>> from Shared.TaintedString import TaintedString
>>> tainted = TaintedString(text)
>>> print DT_Var.newline_to_br(tainted)
<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 @@
# 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
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
""" TaintedString tests.
$Id$
"""
import unittest
class TestTaintedString(unittest.TestCase):
def setUp(self):
self.unquoted = '<test attr="&">'
self.quoted = '&lt;test attr=&quot;&amp;&quot;&gt;'
self.tainted = self._getClass()(self.unquoted)
def _getClass(self):
from ZPublisher.TaintedString import TaintedString
from Shared.TaintedString import TaintedString
return TaintedString
def testStr(self):
......@@ -152,21 +157,8 @@ class TestTaintedString(unittest.TestCase):
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestTaintedString, 'test'))
suite.addTest(unittest.makeSuite(TestTaintedString))
return suite
def main():
unittest.TextTestRunner().run(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()
if __name__ == '__main__':
unittest.main(defaultTest='test_suite')
......@@ -38,12 +38,12 @@ from zope.interface import implements
from zope.publisher.base import DebugFlags
from zope.publisher.interfaces.browser import IBrowserRequest
from Shared.TaintedString import TaintedString
from ZPublisher.BaseRequest import BaseRequest
from ZPublisher.BaseRequest import quote
from ZPublisher.Converters import get_converter
from ZPublisher.HTTPResponse import HTTPResponse
from ZPublisher.maybe_lock import allocate_lock
from ZPublisher.TaintedString import TaintedString
# Flags
SEQUENCE = 1
......
......@@ -7,145 +7,16 @@
# 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
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""TaintedString legacy module.
__version__='$Revision: 1.2 $'[11:-2]
$Id$
"""
from cgi import escape
# TaintedStrings hold potentially dangerous untrusted data; anything that could
# 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))
from zope.deferredimport import deprecated
deprecated('ZPublisher.TaintedString will be removed in Zope 2.14. Please '
'import from Shared.TaintedString instead.',
TaintedString = 'Shared.TaintedString:TaintedString',
)
......@@ -71,7 +71,7 @@ class HTTPRequestTests(unittest.TestCase):
# Also raises an Assertion if a string which *should* have been
# tainted is found, or when a tainted string is not deemed dangerous.
from ZPublisher.HTTPRequest import record
from ZPublisher.TaintedString import TaintedString
from Shared.TaintedString import TaintedString
retval = 0
......@@ -1015,8 +1015,12 @@ test %s
''' % ('test' * 1000)
def test_suite():
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(RecordTests, 'test'))
suite.addTest(unittest.makeSuite(HTTPRequestTests, 'test'))
suite.addTest(unittest.makeSuite(RecordTests))
suite.addTest(unittest.makeSuite(HTTPRequestTests))
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