[ADD] safe_eval: final round of adjustments, seems stable AFAICT (please be careful if you notice any error due to it - contact me if on doubt on how to fix properly)
bzr revid: odo@openerp.com-20100604003940-e32elbetzxop8c3b
This commit is contained in:
parent
534740885e
commit
0961c0f5cd
|
@ -78,7 +78,8 @@
|
|||
<form string="Users">
|
||||
<notebook colspan="4">
|
||||
<page string="Current Activity">
|
||||
<field name="company_id" widget="selection" readonly="0" context="{'user_preference':True}"/>
|
||||
<field name="company_id" widget="selection" readonly="0"
|
||||
context="{'user_id': self, 'user_preference': 1}"/>
|
||||
<newline/>
|
||||
<separator colspan="4" string="Preferences"/>
|
||||
</page>
|
||||
|
@ -110,7 +111,7 @@
|
|||
<page string="User">
|
||||
<field name="address_id" select="1"/>
|
||||
<field name="user_email" widget="email"/>
|
||||
<field name="company_id" required="1"/>
|
||||
<field name="company_id" required="1" context="{'user_id': self, 'user_preference': 1}"/>
|
||||
<field name="action_id" required="True"/>
|
||||
<field domain="[('usage','=','menu')]" name="menu_id" required="True"/>
|
||||
<field name="context_lang"/>
|
||||
|
|
|
@ -92,11 +92,18 @@ class res_company(osv.osv):
|
|||
def search(self, cr, uid, args, offset=0, limit=None, order=None,
|
||||
context=None, count=False):
|
||||
|
||||
user_preference = context and context.get('user_preference', False) or False
|
||||
if context is None:
|
||||
context = {}
|
||||
user_preference = context.get('user_preference', False)
|
||||
if user_preference:
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
cmp_ids = list(set([user.company_id.id] + [cmp.id for cmp in user.company_ids]))
|
||||
# TODO: improve this as soon as the client sends the proper
|
||||
# combination of active_id and active_model we'll be able to
|
||||
# use active_id here to restrict to the user being modified instead
|
||||
# of current user.
|
||||
user_id = context.get('user_id', uid)
|
||||
|
||||
user = self.pool.get('res.users').browse(cr, uid, user_id, context=context)
|
||||
cmp_ids = list(set([user.company_id.id] + [cmp.id for cmp in user.company_ids]))
|
||||
return cmp_ids
|
||||
return super(res_company, self).search(cr, uid, args, offset=offset, limit=limit, order=order,
|
||||
context=context, count=count)
|
||||
|
|
|
@ -233,8 +233,13 @@ class users(osv.osv):
|
|||
'menu_id': fields.many2one('ir.actions.actions', 'Menu Action'),
|
||||
'groups_id': fields.many2many('res.groups', 'res_groups_users_rel', 'uid', 'gid', 'Groups'),
|
||||
'roles_id': fields.many2many('res.roles', 'res_roles_users_rel', 'uid', 'rid', 'Roles'),
|
||||
|
||||
# Special behavior for this field: res.company.search() will only return the companies
|
||||
# available to the current user (should be the user's companies?), when the user_preference
|
||||
# context is set.
|
||||
'company_id': fields.many2one('res.company', 'Company', required=True,
|
||||
help="The company this user is currently working for."),
|
||||
help="The company this user is currently working for.", context={'user_preference': True}),
|
||||
|
||||
'company_ids':fields.many2many('res.company','res_company_users_rel','user_id','cid','Companies'),
|
||||
'context_lang': fields.selection(_lang_get, 'Language', required=True,
|
||||
help="Sets the language for the user's user interface, when UI "
|
||||
|
@ -277,7 +282,7 @@ class users(osv.osv):
|
|||
return all(((this.company_id in this.company_ids) or not this.company_ids) for this in self.browse(cr, uid, ids, context))
|
||||
|
||||
_constraints = [
|
||||
(_check_company, 'The chosen company is not in the allowed companies', ['company_id', 'company_ids']),
|
||||
(_check_company, 'The chosen company is not in the allowed companies for this user', ['company_id', 'company_ids']),
|
||||
]
|
||||
|
||||
_sql_constraints = [
|
||||
|
|
|
@ -1228,17 +1228,23 @@ class orm_template(object):
|
|||
name = node.get('name')
|
||||
default = self.default_get(cr, user, [name], context=context).get(name)
|
||||
if default:
|
||||
attrs['selection'] = relation.name_get(cr, 1, default, context=context)
|
||||
attrs['selection'] = relation.name_get(cr, 1, [default], context=context)
|
||||
else:
|
||||
attrs['selection'] = []
|
||||
# We can not use the 'string' domain has it is defined according to the record !
|
||||
else:
|
||||
# If domain and context are strings, we keep them for client-side, otherwise
|
||||
# we evaluate them server-side to consider them when generating the list of
|
||||
# possible values
|
||||
# TODO: find a way to remove this hack, by allow dynamic domains
|
||||
dom = []
|
||||
if column._domain and not isinstance(column._domain, (str, unicode)):
|
||||
if column._domain and not isinstance(column._domain, basestring):
|
||||
dom = column._domain
|
||||
dom += eval(node.get('domain','[]'), {'uid':user, 'time':time})
|
||||
context.update(eval(node.get('context','{}')))
|
||||
attrs['selection'] = relation._name_search(cr, user, '', dom, context=context, limit=None, name_get_uid=1)
|
||||
search_context = dict(context)
|
||||
if column._context and not isinstance(column._context, basestring):
|
||||
search_context.update(column._context)
|
||||
attrs['selection'] = relation._name_search(cr, user, '', dom, context=search_context, limit=None, name_get_uid=1)
|
||||
if (node.get('required') and not int(node.get('required'))) or not column.required:
|
||||
attrs['selection'].append((False,''))
|
||||
fields[node.get('name')] = attrs
|
||||
|
|
|
@ -35,9 +35,14 @@ import netsvc
|
|||
import osv
|
||||
import pooler
|
||||
from config import config
|
||||
from tools.safe_eval import safe_eval as eval
|
||||
from yaml_import import convert_yaml_import
|
||||
|
||||
# Import of XML records requires the unsafe eval as well,
|
||||
# almost everywhere, which is ok because it supposedly comes
|
||||
# from trusted data, but at least we make it obvious now.
|
||||
unsafe_eval = eval
|
||||
from tools.safe_eval import safe_eval as eval
|
||||
|
||||
class ConvertError(Exception):
|
||||
def __init__(self, doc, orig_excpt):
|
||||
self.d = doc
|
||||
|
@ -63,7 +68,7 @@ def _eval_xml(self,node, pool, cr, uid, idref, context=None):
|
|||
f_search = node.get("search",'').encode('utf-8')
|
||||
f_use = node.get("use",'id').encode('ascii')
|
||||
f_name = node.get("name",'').encode('utf-8')
|
||||
q = eval(f_search, idref)
|
||||
q = unsafe_eval(f_search, idref)
|
||||
ids = pool.get(f_model).search(cr, uid, q)
|
||||
if f_use != 'id':
|
||||
ids = map(lambda x: x[f_use], pool.get(f_model).read(cr, uid, ids, [f_use]))
|
||||
|
@ -97,10 +102,10 @@ def _eval_xml(self,node, pool, cr, uid, idref, context=None):
|
|||
pytz=pytzclass()
|
||||
idref2['pytz'] = pytz
|
||||
try:
|
||||
return eval(a_eval, idref2)
|
||||
except:
|
||||
logger = netsvc.Logger()
|
||||
logger.notifyChannel("init", netsvc.LOG_WARNING, 'could eval(%s) for %s in %s, please get back and fix it!' % (a_eval,node.get('name'),context))
|
||||
return unsafe_eval(a_eval, idref2)
|
||||
except Exception, e:
|
||||
logger = logging.getLogger('init')
|
||||
logger.warning('couldn\'t eval(%s) for %s in %s, please get back and fix it!' % (a_eval,node.get('name'),context), exc_info=True)
|
||||
return ""
|
||||
if t == 'xml':
|
||||
def _process(s, idref):
|
||||
|
@ -145,7 +150,7 @@ def _eval_xml(self,node, pool, cr, uid, idref, context=None):
|
|||
a_eval = node.get('eval','')
|
||||
if a_eval:
|
||||
idref['ref'] = lambda x: self.id_get(cr, False, x)
|
||||
args = eval(a_eval, idref)
|
||||
args = unsafe_eval(a_eval, idref)
|
||||
for n in node:
|
||||
return_val = _eval_xml(self,n, pool, cr, uid, idref, context)
|
||||
if return_val is not None:
|
||||
|
@ -206,13 +211,13 @@ class xml_import(object):
|
|||
def get_context(self, data_node, node, eval_dict):
|
||||
data_node_context = (len(data_node) and data_node.get('context','').encode('utf8'))
|
||||
if data_node_context:
|
||||
context = eval(data_node_context, eval_dict)
|
||||
context = unsafe_eval(data_node_context, eval_dict)
|
||||
else:
|
||||
context = {}
|
||||
|
||||
node_context = node.get("context",'').encode('utf8')
|
||||
if node_context:
|
||||
context.update(eval(node_context, eval_dict))
|
||||
context.update(unsafe_eval(node_context, eval_dict))
|
||||
|
||||
return context
|
||||
|
||||
|
@ -242,7 +247,7 @@ form: module.record_id""" % (xml_id,)
|
|||
d_id = rec.get("id",'')
|
||||
ids = []
|
||||
if d_search:
|
||||
ids = self.pool.get(d_model).search(cr,self.uid,eval(d_search))
|
||||
ids = self.pool.get(d_model).search(cr, self.uid, unsafe_eval(d_search))
|
||||
if d_id:
|
||||
try:
|
||||
ids.append(self.id_get(cr, d_model, d_id))
|
||||
|
@ -405,7 +410,7 @@ form: module.record_id""" % (xml_id,)
|
|||
def ref(str_id):
|
||||
return self.id_get(cr, None, str_id)
|
||||
|
||||
context=eval(context, locals_dict=locals())
|
||||
context = unsafe_eval(context)
|
||||
# domain = eval(domain) # XXX need to test this line -> uid, active_id, active_ids, ...
|
||||
|
||||
res = {
|
||||
|
@ -625,7 +630,7 @@ form: module.record_id""" % (xml_id,)
|
|||
if rec_id:
|
||||
ids = [self.id_get(cr, rec_model, rec_id)]
|
||||
elif rec_src:
|
||||
q = eval(rec_src, eval_dict)
|
||||
q = unsafe_eval(rec_src, eval_dict)
|
||||
ids = self.pool.get(rec_model).search(cr, uid, q, context=context)
|
||||
if rec_src_count:
|
||||
count = int(rec_src_count)
|
||||
|
@ -660,7 +665,7 @@ form: module.record_id""" % (xml_id,)
|
|||
for test in rec.findall('./test'):
|
||||
f_expr = test.get("expr",'').encode('utf-8')
|
||||
expected_value = _eval_xml(self, test, self.pool, cr, uid, self.idref, context=context) or True
|
||||
expression_value = eval(f_expr, globals_dict, nocopy=True)
|
||||
expression_value = unsafe_eval(f_expr, globals_dict)
|
||||
if expression_value != expected_value: # assertion failed
|
||||
self.assert_report.record_assertion(False, severity)
|
||||
msg = 'assertion "%s" failed!\n' \
|
||||
|
@ -684,7 +689,7 @@ form: module.record_id""" % (xml_id,)
|
|||
rec_id = rec.get("id",'').encode('ascii')
|
||||
rec_context = rec.get("context", None)
|
||||
if rec_context:
|
||||
rec_context = eval(rec_context)
|
||||
rec_context = unsafe_eval(rec_context)
|
||||
self._test_xml_id(rec_id)
|
||||
if self.isnoupdate(data_node) and self.mode != 'init':
|
||||
# check if the xml record has an id string
|
||||
|
@ -724,7 +729,7 @@ form: module.record_id""" % (xml_id,)
|
|||
f_val = False
|
||||
|
||||
if f_search:
|
||||
q = eval(f_search, self.idref)
|
||||
q = unsafe_eval(f_search, self.idref)
|
||||
field = []
|
||||
assert f_model, 'Define an attribute model="..." in your .XML file !'
|
||||
f_obj = self.pool.get(f_model)
|
||||
|
|
|
@ -33,6 +33,7 @@ condition/math builtins.
|
|||
# - python 2.6's ast.literal_eval
|
||||
|
||||
from opcode import HAVE_ARGUMENT, opmap, opname
|
||||
from types import CodeType
|
||||
|
||||
__all__ = ['test_expr', 'literal_eval', 'safe_eval', 'const_eval', 'ext_eval' ]
|
||||
|
||||
|
@ -211,6 +212,9 @@ def safe_eval(expr, globals_dict=None, locals_dict=None, mode="eval", nocopy=Fal
|
|||
ValueError: opcode LOAD_NAME not allowed
|
||||
|
||||
"""
|
||||
if isinstance(expr, CodeType):
|
||||
raise ValueError("safe_eval does not allow direct evaluation of code objects.")
|
||||
|
||||
if '__subclasses__' in expr:
|
||||
raise ValueError('expression not allowed (__subclasses__)')
|
||||
|
||||
|
@ -220,6 +224,12 @@ def safe_eval(expr, globals_dict=None, locals_dict=None, mode="eval", nocopy=Fal
|
|||
# prevent altering the globals/locals from within the sandbox
|
||||
# by taking a copy.
|
||||
if not nocopy:
|
||||
# isinstance() does not work below, we want *exactly* the dict class
|
||||
if (globals_dict is not None and type(globals_dict) is not dict) \
|
||||
or (locals_dict is not None and type(locals_dict) is not dict):
|
||||
logging.getLogger('safe_eval').warning('Looks like you are trying to pass a dynamic environment,"\
|
||||
"you should probably pass nocopy=True to safe_eval()')
|
||||
|
||||
globals_dict = dict(globals_dict)
|
||||
if locals_dict is not None:
|
||||
locals_dict = dict(locals_dict)
|
||||
|
@ -241,5 +251,4 @@ def safe_eval(expr, globals_dict=None, locals_dict=None, mode="eval", nocopy=Fal
|
|||
|
||||
return eval(test_expr(expr,_SAFE_OPCODES, mode=mode), globals_dict, locals_dict)
|
||||
|
||||
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
|
|
@ -7,10 +7,14 @@ import pooler
|
|||
import netsvc
|
||||
import misc
|
||||
from config import config
|
||||
from tools.safe_eval import safe_eval as eval
|
||||
import yaml_tag
|
||||
import yaml
|
||||
|
||||
# YAML import needs both safe and unsafe eval, but let's
|
||||
# default to /safe/.
|
||||
unsafe_eval = eval
|
||||
from tools.safe_eval import safe_eval as eval
|
||||
|
||||
logger_channel = 'tests'
|
||||
|
||||
class YamlImportException(Exception):
|
||||
|
@ -234,8 +238,9 @@ class YamlInterpreter(object):
|
|||
record = model.browse(self.cr, self.uid, id, context)
|
||||
for test in expressions:
|
||||
try:
|
||||
success = eval(test, self.eval_context, RecordDictWrapper(record))
|
||||
success = unsafe_eval(test, self.eval_context, RecordDictWrapper(record))
|
||||
except Exception, e:
|
||||
self.logger.debug('Exception during evaluation of !assert block in yaml_file %s.', self.filename, exc_info=True)
|
||||
raise YamlImportAbortion(e)
|
||||
if not success:
|
||||
msg = 'Assertion "%s" FAILED\ntest: %s\n'
|
||||
|
@ -367,12 +372,13 @@ class YamlInterpreter(object):
|
|||
code_context = {'model': model, 'cr': self.cr, 'uid': self.uid, 'log': log, 'context': self.context}
|
||||
code_context.update({'self': model}) # remove me when no !python block test uses 'self' anymore
|
||||
try:
|
||||
code = compile(statements, self.filename, 'exec')
|
||||
eval(code, {'ref': self.get_id}, code_context)
|
||||
code_obj = compile(statements, self.filename, 'exec')
|
||||
unsafe_eval(code_obj, {'ref': self.get_id}, code_context)
|
||||
except AssertionError, e:
|
||||
self._log_assert_failure(python.severity, 'AssertionError in Python code %s: %s', python.name, e)
|
||||
return
|
||||
except Exception, e:
|
||||
self.logger.debug('Exception during evaluation of !python block in yaml_file %s.', self.filename, exc_info=True)
|
||||
raise YamlImportAbortion(e)
|
||||
else:
|
||||
self.assert_report.record(True, python.severity)
|
||||
|
|
|
@ -55,7 +55,7 @@ def _eval_expr(cr, ident, workitem, action):
|
|||
ret=False
|
||||
else:
|
||||
env = Env(cr, uid, model, ids)
|
||||
ret = eval(line, env)
|
||||
ret = eval(line, env, nocopy=True)
|
||||
return ret
|
||||
|
||||
def execute_action(cr, ident, workitem, activity):
|
||||
|
|
Loading…
Reference in New Issue