From 1bf2a891dd3c1aea67f722c643810bcfbcd86fc6 Mon Sep 17 00:00:00 2001 From: Benoit Socias Date: Fri, 5 May 2023 11:13:27 +0000 Subject: [PATCH] [IMP] *: make HTML fields with sanitized attributes edited as text-only *: web_editor When an HTML field sanitizes its attributes, it can still be filled with HTML content (blocks, styling, power box commands) using the website builder. This causes problems because those elements can then be broken by the sanitizing. It is possible to break elements so badly that the page cannot be edited anymore to fix the problem. This commit prevents the user from dropping snippet blocks inside the content of such fields. Steps to reproduce: (Unless `slide.slide`'s `description` becomes `sanitize_attributes=False` in the meantime.) - Edit a single Course's slide. - Drop a Carousel into the description field at the bottom. - Save. => Carousel did not work. Worse: - Instead of the Carousel, drop a Countdown. => An error happens on each page reload, and the edit mode cannot be reached anymore. task-3293600 Part-of: odoo/odoo#120588 --- addons/web_editor/models/ir_qweb_fields.py | 32 +++++++++++-------- .../static/src/js/editor/snippets.editor.js | 7 ++-- 2 files changed, 23 insertions(+), 16 deletions(-) diff --git a/addons/web_editor/models/ir_qweb_fields.py b/addons/web_editor/models/ir_qweb_fields.py index af8e172e102..3cccf091d53 100644 --- a/addons/web_editor/models/ir_qweb_fields.py +++ b/addons/web_editor/models/ir_qweb_fields.py @@ -403,19 +403,25 @@ class HTML(models.AbstractModel): if options.get('inherit_branding'): field = record._fields[field_name] if field.sanitize: - if field.sanitize_overridable and not record.user_has_groups('base.group_sanitize_override'): - try: - field.convert_to_column(record[field_name], record) - except UserError: - # The field contains element(s) that would be removed if - # sanitized. It means that someone who was part of a - # group allowing to bypass the sanitation saved that - # field previously. Mark the field as not editable. - attrs['data-oe-sanitize-prevent-edition'] = 1 - if not (field.sanitize_overridable and record.user_has_groups('base.group_sanitize_override')): - # Don't mark the field as 'sanitize' if the sanitize is - # defined as overridable and the user has the right to do so - attrs['data-oe-sanitize'] = 1 if field.sanitize_form else 'allow_form' + if field.sanitize_overridable: + if record.user_has_groups('base.group_sanitize_override'): + # Don't mark the field as 'sanitize' if the sanitize + # is defined as overridable and the user has the right + # to do so + return attrs + else: + try: + field.convert_to_column(record[field_name], record) + except UserError: + # The field contains element(s) that would be + # removed if sanitized. It means that someone who + # was part of a group allowing to bypass the + # sanitation saved that field previously. Mark the + # field as not editable. + attrs['data-oe-sanitize-prevent-edition'] = 1 + return attrs + # The field edition is not fully prevented and the sanitation cannot be bypassed + attrs['data-oe-sanitize'] = 'no_block' if field.sanitize_attributes else 1 if field.sanitize_form else 'allow_form' return attrs diff --git a/addons/web_editor/static/src/js/editor/snippets.editor.js b/addons/web_editor/static/src/js/editor/snippets.editor.js index 5e9640ab41a..8a224822c13 100644 --- a/addons/web_editor/static/src/js/editor/snippets.editor.js +++ b/addons/web_editor/static/src/js/editor/snippets.editor.js @@ -3229,14 +3229,15 @@ var SnippetsMenu = Widget.extend({ * false: always fobid */ _insertDropzone: function ($hook, vertical, style, canBeSanitizedUnless) { + const skip = $hook.closest('[data-oe-sanitize="no_block"]').length; let forbidSanitize; if (canBeSanitizedUnless === 'form') { - forbidSanitize = $hook.closest('[data-oe-sanitize]:not([data-oe-sanitize="allow_form"])').length; + forbidSanitize = $hook.closest('[data-oe-sanitize]:not([data-oe-sanitize="allow_form"]):not([data-oe-sanitize="no_block"])').length; } else { - forbidSanitize = !canBeSanitizedUnless && $hook.closest('[data-oe-sanitize]').length; + forbidSanitize = !canBeSanitizedUnless && $hook.closest('[data-oe-sanitize]:not([data-oe-sanitize="no_block"])').length; } var $dropzone = $('
', { - 'class': 'oe_drop_zone oe_insert' + (vertical ? ' oe_vertical' : '') + + 'class': skip ? 'd-none' : 'oe_drop_zone oe_insert' + (vertical ? ' oe_vertical' : '') + (forbidSanitize ? ' text-center oe_drop_zone_danger' : ''), }); if (style) {