From c85625b3d3fa0df32369d4db57b232a2d6b1c2e5 Mon Sep 17 00:00:00 2001 From: Jeff Gehlbach Date: Fri, 19 Jul 2024 10:28:03 -0400 Subject: [PATCH] Issue #16934: Escape config-revision banner values by default Previous commit accidentally contained only docs work. - Default to HTML-escaping banner values before displaying them - Also default to escaping banner values in config form previews - Escape names of dependent objects displayed when deleting parents --- netbox/core/forms/model_forms.py | 6 +++++- netbox/netbox/configuration_example.py | 3 +++ netbox/netbox/settings.py | 1 + netbox/templates/base/layout.html | 18 +++++++++++++++--- netbox/templates/login.html | 6 +++++- netbox/utilities/error_handlers.py | 2 +- 6 files changed, 30 insertions(+), 6 deletions(-) diff --git a/netbox/core/forms/model_forms.py b/netbox/core/forms/model_forms.py index a05377597..49a90d7dd 100644 --- a/netbox/core/forms/model_forms.py +++ b/netbox/core/forms/model_forms.py @@ -4,6 +4,7 @@ import json from django import forms from django.conf import settings from django.forms.fields import JSONField as _JSONField +from django.utils.html import escape from django.utils.translation import gettext_lazy as _ from core.forms.mixins import SyncedDataMixin @@ -213,7 +214,10 @@ class ConfigRevisionForm(forms.ModelForm, metaclass=ConfigFormMetaclass): help_text = self.fields[param.name].help_text if help_text: help_text += '
' # Line break - help_text += _('Current value: {value}').format(value=value or '—') + if param.name.startswith('BANNER_') and settings.ESCAPE_BANNERS: + help_text += _('Current value: {value}').format(value=escape(value) or '—') + else: + help_text += _('Current value: {value}').format(value=value or '—') if value == param.default: help_text += _(' (default)') self.fields[param.name].help_text = help_text diff --git a/netbox/netbox/configuration_example.py b/netbox/netbox/configuration_example.py index 84ead5339..d586839ca 100644 --- a/netbox/netbox/configuration_example.py +++ b/netbox/netbox/configuration_example.py @@ -131,6 +131,9 @@ EMAIL = { 'FROM_EMAIL': '', } +# Setting this to False will allow banners to be rendered without HTML escaping for safety +ESCAPE_BANNERS = True + # Exempt certain models from the enforcement of view permissions. Models listed here will be viewable by all users and # by anonymous users. List models in the form `.`. Add '*' to this list to exempt all models. EXEMPT_VIEW_PERMISSIONS = [ diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 604069061..401cd80e2 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -92,6 +92,7 @@ DEVELOPER = getattr(configuration, 'DEVELOPER', False) DJANGO_ADMIN_ENABLED = getattr(configuration, 'DJANGO_ADMIN_ENABLED', False) DOCS_ROOT = getattr(configuration, 'DOCS_ROOT', os.path.join(os.path.dirname(BASE_DIR), 'docs')) EMAIL = getattr(configuration, 'EMAIL', {}) +ESCAPE_BANNERS = getattr(configuration, 'ESCAPE_BANNERS', True) EVENTS_PIPELINE = getattr(configuration, 'EVENTS_PIPELINE', ( 'extras.events.process_event_queue', )) diff --git a/netbox/templates/base/layout.html b/netbox/templates/base/layout.html index 9ba6fded3..3812ab396 100644 --- a/netbox/templates/base/layout.html +++ b/netbox/templates/base/layout.html @@ -83,7 +83,11 @@ Blocks: {# Top banner #} {% if config.BANNER_TOP %} - {% include 'inc/banner.html' with content=config.BANNER_TOP %} + {% if not settings.ESCAPE_BANNERS %} + {% include 'inc/banner.html' with content=config.BANNER_TOP %} + {% else %} + {% include 'inc/banner.html' with content=config.BANNER_TOP|escape %} + {% endif %} {% endif %} {# /Top banner #} @@ -93,7 +97,11 @@ Blocks: {% endif %} {% if config.MAINTENANCE_MODE and config.BANNER_MAINTENANCE %} - {% include 'inc/alerts/warning.html' with title="Maintenance Mode" message=config.BANNER_MAINTENANCE|safe %} + {% if not settings.ESCAPE_BANNERS %} + {% include 'inc/alerts/warning.html' with title="Maintenance Mode" message=config.BANNER_MAINTENANCE|safe %} + {% else %} + {% include 'inc/alerts/warning.html' with title="Maintenance Mode" message=config.BANNER_MAINTENANCE|escape %} + {% endif %} {% endif %} {# /Alerts #} @@ -116,7 +124,11 @@ Blocks: {# Bottom banner #} {% if config.BANNER_BOTTOM %} - {% include 'inc/banner.html' with content=config.BANNER_BOTTOM %} + {% if not settings.ESCAPE_BANNERS %} + {% include 'inc/banner.html' with content=config.BANNER_BOTTOM %} + {% else %} + {% include 'inc/banner.html' with content=config.BANNER_BOTTOM|escape %} + {% endif %} {% endif %} {# /Bottom banner #} diff --git a/netbox/templates/login.html b/netbox/templates/login.html index f8575e4c1..4e6267223 100644 --- a/netbox/templates/login.html +++ b/netbox/templates/login.html @@ -17,7 +17,11 @@ {# Login banner #} {% if config.BANNER_LOGIN %}
- {{ config.BANNER_LOGIN|safe }} + {% if not settings.ESCAPE_BANNERS %} + {{ config.BANNER_LOGIN|safe }} + {% else %} + {{ config.BANNER_LOGIN|escape }} + {% endif %}
{% endif %} diff --git a/netbox/utilities/error_handlers.py b/netbox/utilities/error_handlers.py index 386ec6f39..4d61a0ab9 100644 --- a/netbox/utilities/error_handlers.py +++ b/netbox/utilities/error_handlers.py @@ -29,7 +29,7 @@ def handle_protectederror(obj_list, request, e): # Formulate the error message err_message = _("Unable to delete {objects}. {count} dependent objects were found: ").format( - objects=', '.join(str(obj) for obj in obj_list), + objects=', '.join(escape(str(obj)) for obj in obj_list), count=len(protected_objects) if len(protected_objects) <= 50 else _('More than 50') )