[IMP] base: renamed __terp__ to __openerp__
bzr revid: odo@openerp.com-20100427121305-o0rby3wr3gwr3ydx
This commit is contained in:
+224
-49
@@ -1,66 +1,241 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2004-2010 OpenERP s.a. (<http://www.openerp.com>).
|
||||
#
|
||||
# Copyright P. Christeas <p_christ@hol.gr> 2008,2009
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# WARNING: This program as such is intended to be used by professional
|
||||
# programmers who take the whole responsability of assessing all potential
|
||||
# consequences resulting from its eventual inadequacies and bugs
|
||||
# End users who are looking for a ready-to-use solution with commercial
|
||||
# garantees and support are strongly adviced to contract a Free Software
|
||||
# Service Company
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# This program is Free Software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
###############################################################################
|
||||
##############################################################################
|
||||
|
||||
__export_bis = {}
|
||||
import sys
|
||||
"""
|
||||
safe_eval module - methods intended to provide more restricted alternatives to
|
||||
evaluate simple and/or untrusted code.
|
||||
|
||||
Methods in this module are typically used as alternatives to eval() to parse
|
||||
OpenERP domain strings, conditions and expressions, mostly based on locals
|
||||
condition/math builtins.
|
||||
"""
|
||||
|
||||
def __init_ebis():
|
||||
global __export_bis
|
||||
# Module partially ripped from/inspired by several different sources:
|
||||
# - http://code.activestate.com/recipes/286134/
|
||||
# - safe_eval in lp:~xrg/openobject-server/optimize-5.0
|
||||
# - safe_eval in tryton http://hg.tryton.org/hgwebdir.cgi/trytond/rev/bbb5f73319ad
|
||||
# - python 2.6's ast.literal_eval
|
||||
|
||||
_evars = [ 'abs', 'all', 'any', 'basestring' , 'bool',
|
||||
'chr', 'cmp','complex', 'dict', 'divmod', 'enumerate',
|
||||
'float', 'frozenset', 'getattr', 'hasattr', 'hash',
|
||||
'hex', 'id','int', 'iter', 'len', 'list', 'long', 'map', 'max',
|
||||
'min', 'oct', 'ord','pow', 'range', 'reduce', 'repr',
|
||||
'reversed', 'round', 'set', 'setattr', 'slice','sorted', 'str',
|
||||
'sum', 'tuple','type', 'unichr','unicode', 'xrange',
|
||||
'True','False', 'None', 'NotImplemented', 'Ellipsis', ]
|
||||
from opcode import HAVE_ARGUMENT, opmap, opname
|
||||
|
||||
if sys.version_info[0:2] >= (2,6):
|
||||
_evars.extend(['bin', 'format', 'next'])
|
||||
for v in _evars:
|
||||
__export_bis[v] = __builtins__[v]
|
||||
_CONST_CODES = set(opmap[x] for x in [
|
||||
'POP_TOP', 'ROT_TWO', 'ROT_THREE', 'ROT_FOUR', 'DUP_TOP',
|
||||
'BUILD_LIST', 'BUILD_MAP', 'BUILD_TUPLE',
|
||||
'LOAD_CONST', 'RETURN_VALUE', 'STORE_SUBSCR'] if x in opmap)
|
||||
|
||||
_EXPR_CODES = _CONST_CODES.union(set(opmap[x] for x in [
|
||||
'UNARY_POSITIVE', 'UNARY_NEGATIVE', 'UNARY_NOT',
|
||||
'UNARY_INVERT', 'BINARY_POWER', 'BINARY_MULTIPLY',
|
||||
'BINARY_DIVIDE', 'BINARY_FLOOR_DIVIDE', 'BINARY_TRUE_DIVIDE',
|
||||
'BINARY_MODULO', 'BINARY_ADD', 'BINARY_SUBTRACT', 'BINARY_SUBSCR',
|
||||
'BINARY_LSHIFT', 'BINARY_RSHIFT', 'BINARY_AND', 'BINARY_XOR',
|
||||
'BINARY_OR'] if x in opmap))
|
||||
|
||||
_SAFE_CODES = _EXPR_CODES.union(set(opmap[x] for x in [
|
||||
'STORE_MAP', 'LOAD_NAME', 'CALL_FUNCTION', 'COMPARE_OP', 'LOAD_ATTR',
|
||||
'STORE_NAME', 'GET_ITER', 'FOR_ITER', 'LIST_APPEND', 'JUMP_ABSOLUTE',
|
||||
'DELETE_NAME', 'JUMP_IF_TRUE', 'JUMP_IF_FALSE',
|
||||
] if x in opmap))
|
||||
|
||||
|
||||
__init_ebis()
|
||||
def _get_opcodes(codeobj):
|
||||
"""_get_opcodes(codeobj) -> [opcodes]
|
||||
|
||||
Extract the actual opcodes as a list from a code object
|
||||
|
||||
>>> c = compile("[1 + 2, (1,2)]", "", "eval")
|
||||
>>> _get_opcodes(c)
|
||||
[100, 100, 23, 100, 100, 102, 103, 83]
|
||||
"""
|
||||
i = 0
|
||||
opcodes = []
|
||||
s = codeobj.co_code
|
||||
while i < len(s):
|
||||
code = ord(s[i])
|
||||
opcodes.append(code)
|
||||
if code >= HAVE_ARGUMENT:
|
||||
i += 3
|
||||
else:
|
||||
i += 1
|
||||
return opcodes
|
||||
|
||||
def test_expr(expr, allowed_codes):
|
||||
"""test_expr(expression) -> code_object
|
||||
|
||||
Test that the expression contains only the allowed opcodes.
|
||||
If the expression is valid and contains only allowed codes,
|
||||
return the compiled code object. Otherwise raise a ValueError.
|
||||
"""
|
||||
try:
|
||||
code_obj = compile(expr, "", "eval")
|
||||
except:
|
||||
raise ValueError("%s is not a valid expression" % expr)
|
||||
for code in _get_opcodes(code_obj):
|
||||
if code not in allowed_codes:
|
||||
raise ValueError("opcode %s not allowed (%r)" % (opname[code], expr))
|
||||
return code_obj
|
||||
|
||||
|
||||
def safe_eval(expr,sglobals,slocals = None):
|
||||
""" A little safer version of eval().
|
||||
This one, will use fewer builtin functions, so that only
|
||||
arithmetic and logic expressions can really work """
|
||||
def const_eval(expr):
|
||||
"""const_eval(expression) -> value
|
||||
|
||||
global __export_bis
|
||||
Safe Python constant evaluation
|
||||
|
||||
Evaluates a string that contains an expression describing
|
||||
a Python constant. Strings that are not valid Python expressions
|
||||
or that contain other code besides the constant raise ValueError.
|
||||
|
||||
>>> const_eval("10")
|
||||
10
|
||||
>>> const_eval("[1,2, (3,4), {'foo':'bar'}]")
|
||||
[1, 2, (3, 4), {'foo': 'bar'}]
|
||||
>>> const_eval("1+2")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: opcode BINARY_ADD not allowed
|
||||
"""
|
||||
c = test_expr(expr, _CONST_CODES)
|
||||
return eval(c)
|
||||
|
||||
def expr_eval(expr):
|
||||
"""expr_eval(expression) -> value
|
||||
|
||||
Restricted Python expression evaluation
|
||||
|
||||
Evaluates a string that contains an expression that only
|
||||
uses Python constants. This can be used to e.g. evaluate
|
||||
a numerical expression from an untrusted source.
|
||||
|
||||
>>> expr_eval("1+2")
|
||||
3
|
||||
>>> expr_eval("[1,2]*2")
|
||||
[1, 2, 1, 2]
|
||||
>>> expr_eval("__import__('sys').modules")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: opcode LOAD_NAME not allowed
|
||||
"""
|
||||
c = test_expr(expr, _EXPR_CODES)
|
||||
return eval(c)
|
||||
|
||||
|
||||
# Port of Python 2.6's ast.literal_eval for use under Python 2.5
|
||||
SAFE_CONSTANTS = {'None': None, 'True': True, 'False': False}
|
||||
|
||||
try:
|
||||
# first, try importing directly
|
||||
from ast import literal_eval
|
||||
except ImportError:
|
||||
from _ast import *
|
||||
|
||||
def _convert(node):
|
||||
if isinstance(node, Str):
|
||||
return node.s
|
||||
elif isinstance(node, Num):
|
||||
return node.n
|
||||
elif isinstance(node, Tuple):
|
||||
return tuple(map(_convert, node.elts))
|
||||
elif isinstance(node, List):
|
||||
return list(map(_convert, node.elts))
|
||||
elif isinstance(node, Dict):
|
||||
return dict((_convert(k), _convert(v)) for k, v
|
||||
in zip(node.keys, node.values))
|
||||
elif isinstance(node, Name):
|
||||
if node.id in SAFE_CONSTANTS:
|
||||
return SAFE_CONSTANTS[node.id]
|
||||
raise ValueError('malformed or disallowed expression')
|
||||
|
||||
def parse(expr, filename='<unknown>', mode='eval'):
|
||||
"""parse(source[, filename], mode]] -> code object
|
||||
Parse an expression into an AST node.
|
||||
Equivalent to compile(expr, filename, mode, PyCF_ONLY_AST).
|
||||
"""
|
||||
return compile(expr, filename, mode, PyCF_ONLY_AST)
|
||||
|
||||
def literal_eval(node_or_string):
|
||||
"""literal_eval(expression) -> value
|
||||
Safely evaluate an expression node or a string containing a Python
|
||||
expression. The string or node provided may only consist of the
|
||||
following Python literal structures: strings, numbers, tuples,
|
||||
lists, dicts, booleans, and None.
|
||||
|
||||
>>> literal_eval('[1,True,"spam"]')
|
||||
[1, True, 'spam']
|
||||
|
||||
>>> literal_eval('1+3')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: malformed or disallowed expression
|
||||
"""
|
||||
if isinstance(node_or_string, basestring):
|
||||
node_or_string = parse(node_or_string)
|
||||
if isinstance(node_or_string, Expression):
|
||||
node_or_string = node_or_string.body
|
||||
return _convert(node_or_string)
|
||||
|
||||
|
||||
|
||||
def safe_eval(expr, context = None):
|
||||
"""safe_eval(expression, context) -> value
|
||||
|
||||
System-restricted Python expression evaluation
|
||||
|
||||
Evaluates a string that contains an expression that mostly
|
||||
uses Python constants, arithmetic expressions and the
|
||||
use of the objects provided in context.
|
||||
|
||||
This can be used to e.g. evaluate
|
||||
an OpenERP domain expression from an untrusted expr.
|
||||
|
||||
>>> safe_eval("__import__('sys').modules")
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: opcode LOAD_NAME not allowed
|
||||
|
||||
"""
|
||||
if '__subclasses__' in expr:
|
||||
raise ValueError('expression not allowed (__subclasses__)')
|
||||
code_obj = compile(expr, '', 'eval')
|
||||
byte_codes = code_obj.co_code
|
||||
i = 0
|
||||
while i < len(byte_codes):
|
||||
op_code = ord(byte_codes[i])
|
||||
if op_code not in _SAFE_CODES:
|
||||
raise ValueError('opcode %byte_codes not allowed' % dis.opname[op_code])
|
||||
if op_code >= HAVE_ARGUMENT:
|
||||
i += 3
|
||||
else:
|
||||
i += 1
|
||||
return eval(code_obj, {'__builtins__': {
|
||||
'True': True,
|
||||
'False': False,
|
||||
'None': None,
|
||||
'str': str,
|
||||
'globals': locals,
|
||||
'locals': locals,
|
||||
'bool': bool,
|
||||
'dict': dict,
|
||||
'list': list,
|
||||
'tuple': tuple,
|
||||
}
|
||||
}, context)
|
||||
|
||||
if not sglobals.has_key('__builtins__'):
|
||||
# we copy, because we wouldn't want successive calls to safe_eval
|
||||
# to be able to alter the builtins.
|
||||
sglobals['__builtins__'] = __export_bis.copy()
|
||||
|
||||
return eval(expr,sglobals,slocals)
|
||||
|
||||
#eof
|
||||
|
||||
Reference in New Issue
Block a user