[Zope-Checkins] CVS: Zope3/lib/python/Zope/RestrictedPython - RestrictedExpressionEngine.py:1.1.2.1

Shane Hathaway shane@cvs.zope.org
Wed, 13 Mar 2002 23:17:02 -0500


Update of /cvs-repository/Zope3/lib/python/Zope/RestrictedPython
In directory cvs.zope.org:/tmp/cvs-serv17502

Added Files:
      Tag: Zope-3x-branch
	RestrictedExpressionEngine.py 
Log Message:
Added RestrictedExpressionEngine, which is derived from several pieces
of the Zope.PageTemplate package.


=== Added File Zope3/lib/python/Zope/RestrictedPython/RestrictedExpressionEngine.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 1.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.
##############################################################################
"""Restricted TALES engine creation.

The restricted expression engine differs from the basic engine as follows:

  - Python expressions are compiled and executed with security.

  - Path expressions are traversed using ITraverser.restrictedTraverse().

  - The 'modules' name refers to a secure module importer
    rather than the simple module importer.

$Id: RestrictedExpressionEngine.py,v 1.1.2.1 2002/03/14 04:17:01 shane Exp $
"""

from Zope.PageTemplate.Expressions import StringExpr, NotExpr, DeferExpr, \
     PathExpr
from Zope.PageTemplate.PythonExpr import PythonExpr
from Zope.PageTemplate.TALES import ExpressionEngine, CompilerError
from Zope.RestrictedPython import compile_restricted_eval
from Zope.RestrictedPython.ZopeGuards import \
     safe_builtins, guarded_getattr, guarded_getitem
from Zope.ComponentArchitecture import getAdapter
from Zope.App.Traversing.ITraverser import ITraverser
from Zope.App.Traversing.Traverser import Traverser


class ZRPythonExpr(PythonExpr):
    _globals = {
        '__debug__':    __debug__,
        '__builtins__': safe_builtins,
        '_getattr_':    guarded_getattr,
        '_getitem_':    guarded_getitem,
        }

    def __init__(self, name, text, engine):
        self.text = text = text.replace('\n', ' ').strip()
        code, err, warn, use = compile_restricted_eval(text, str(self))
        if err:
            raise CompilerError, ('Python expression error:\n%s' %
                                  ("\n".join(err)))
        self._varnames = use.keys()
        self._code = code

    def __call__(self, econtext):
        __traceback_info__ = self.text
        vars = self._bind_used_names(econtext)
        vars.update(self._globals)
        return eval(self._code, vars)


class SecureModuleImporter:
    def __getitem__(self, module):
        mod = safe_builtins['__import__'](module)
        path = module.split('.')
        for name in path[1:]:
            mod = guarded_getattr(mod, name)
        return mod


def restrictedTraverse(ob, path_items):
    a = getAdapter(ob, ITraverser, None)
    if a is None:
        a = Traverser(ob)
    return a.restrictedTraverse(path_items)

def createRestrictedPathExpr(type, expr, engine):
    return PathExpr(type, expr, engine, restrictedTraverse)


def createRestrictedEngine():
    """Returns an expression engine set up with restrictions."""
    e = ExpressionEngine()
    reg = e.registerType
    for pt in PathExpr._default_type_names:
        reg(pt, createRestrictedPathExpr)
    reg('string', StringExpr)
    reg('python', ZRPythonExpr)
    reg('not', NotExpr)
    reg('defer', DeferExpr)
    e.registerBaseName('modules', SecureModuleImporter())
    return e