# -*- coding: utf-8 -*- from odoo import models class IrQweb(models.AbstractModel): """Add ``raise_on_forbidden_code_for_model`` option for qweb. When this option is activated, only a whitelist of expressions is allowed for the given model. """ _inherit = "ir.qweb" allowed_directives = ( "out", "inner-content", "att", "tag-open", "tag-close", ) def _get_template_cache_keys(self): return super()._get_template_cache_keys() + ["raise_on_forbidden_code_for_model"] def _compile_directive(self, el, compile_context, directive, level): if ( "raise_on_forbidden_code_for_model" in compile_context and directive not in self.allowed_directives ): raise PermissionError("This directive is not allowed for this rendering mode.") return super()._compile_directive(el, compile_context, directive, level) def _compile_directive_att(self, el, compile_context, level): if "raise_on_forbidden_code_for_model" in compile_context: if set(el.attrib) - {"t-out", "t-tag-open", "t-tag-close", "t-inner-content"}: raise PermissionError("This directive is not allowed for this rendering mode.") return super()._compile_directive_att(el, compile_context, level) def _compile_expr(self, expr, raise_on_missing=False): model = self.env.context.get("raise_on_forbidden_code_for_model") if model is not None and not self._is_expression_allowed(expr, model): raise PermissionError("This directive is not allowed for this rendering mode.") return super()._compile_expr(expr, raise_on_missing) def _compile_directive_out(self, el, compile_context, level): if "raise_on_forbidden_code_for_model" in compile_context: if len(el) != 0: raise PermissionError("No child allowed for t-out.") if set(el.attrib) - {'t-out', 't-tag-open', 't-tag-close'}: raise PermissionError("No other attribute allowed for t-out.") return super()._compile_directive_out(el, compile_context, level) def _is_expression_allowed(self, expression, model): return model and expression.strip() in self.env[model].mail_allowed_qweb_expressions()