Loading django/views/debug.py +15 −1 Original line number Diff line number Diff line Loading @@ -33,6 +33,19 @@ def linebreak_iter(template_source): yield len(template_source) + 1 class CallableSettingWrapper(object): """ Object to wrap callable appearing in settings * Not to call in the debug page (#21345). * Not to break the debug page if the callable forbidding to set attributes (#23070). """ def __init__(self, callable_setting): self._wrapped = callable_setting def __repr__(self): return repr(self._wrapped) def cleanse_setting(key, value): """Cleanse an individual setting key/value of sensitive content. Loading @@ -52,7 +65,8 @@ def cleanse_setting(key, value): cleansed = value if callable(cleansed): cleansed.do_not_call_in_templates = True # For fixing #21345 and #23070 cleansed = CallableSettingWrapper(cleansed) return cleansed Loading tests/view_tests/tests/test_debug.py +31 −1 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ from django.test import TestCase, RequestFactory, override_settings from django.test.utils import override_with_test_loader from django.utils.encoding import force_text, force_bytes from django.utils import six from django.views.debug import ExceptionReporter from django.views.debug import CallableSettingWrapper, ExceptionReporter from .. import BrokenException, except_args from ..views import (sensitive_view, non_sensitive_view, paranoid_view, Loading @@ -29,6 +29,21 @@ from ..views import (sensitive_view, non_sensitive_view, paranoid_view, multivalue_dict_key_error) class CallableSettingWrapperTests(TestCase): """ Unittests for CallableSettingWrapper """ def test_repr(self): class WrappedCallable(object): def __repr__(self): return "repr from the wrapped callable" def __call__(self): pass actual = repr(CallableSettingWrapper(WrappedCallable())) self.assertEqual(actual, "repr from the wrapped callable") @override_settings(DEBUG=True, TEMPLATE_DEBUG=True, ROOT_URLCONF="view_tests.urls") class DebugViewTests(TestCase): Loading Loading @@ -660,6 +675,21 @@ class ExceptionReporterFilterTests(TestCase, ExceptionReportTestMixin): response = self.client.get('/raises500/') self.assertNotContains(response, "This should not be displayed", status_code=500) def test_callable_settings_forbidding_to_set_attributes(self): """ Callable settings which forbid to set attributes should not break the debug page (#23070). """ class CallableSettingWithSlots(object): __slots__ = [] def __call__(self): return "This should not be displayed" with self.settings(DEBUG=True, WITH_SLOTS=CallableSettingWithSlots()): response = self.client.get('/raises500/') self.assertNotContains(response, "This should not be displayed", status_code=500) def test_dict_setting_with_non_str_key(self): """ A dict setting containing a non-string key should not break the Loading Loading
django/views/debug.py +15 −1 Original line number Diff line number Diff line Loading @@ -33,6 +33,19 @@ def linebreak_iter(template_source): yield len(template_source) + 1 class CallableSettingWrapper(object): """ Object to wrap callable appearing in settings * Not to call in the debug page (#21345). * Not to break the debug page if the callable forbidding to set attributes (#23070). """ def __init__(self, callable_setting): self._wrapped = callable_setting def __repr__(self): return repr(self._wrapped) def cleanse_setting(key, value): """Cleanse an individual setting key/value of sensitive content. Loading @@ -52,7 +65,8 @@ def cleanse_setting(key, value): cleansed = value if callable(cleansed): cleansed.do_not_call_in_templates = True # For fixing #21345 and #23070 cleansed = CallableSettingWrapper(cleansed) return cleansed Loading
tests/view_tests/tests/test_debug.py +31 −1 Original line number Diff line number Diff line Loading @@ -20,7 +20,7 @@ from django.test import TestCase, RequestFactory, override_settings from django.test.utils import override_with_test_loader from django.utils.encoding import force_text, force_bytes from django.utils import six from django.views.debug import ExceptionReporter from django.views.debug import CallableSettingWrapper, ExceptionReporter from .. import BrokenException, except_args from ..views import (sensitive_view, non_sensitive_view, paranoid_view, Loading @@ -29,6 +29,21 @@ from ..views import (sensitive_view, non_sensitive_view, paranoid_view, multivalue_dict_key_error) class CallableSettingWrapperTests(TestCase): """ Unittests for CallableSettingWrapper """ def test_repr(self): class WrappedCallable(object): def __repr__(self): return "repr from the wrapped callable" def __call__(self): pass actual = repr(CallableSettingWrapper(WrappedCallable())) self.assertEqual(actual, "repr from the wrapped callable") @override_settings(DEBUG=True, TEMPLATE_DEBUG=True, ROOT_URLCONF="view_tests.urls") class DebugViewTests(TestCase): Loading Loading @@ -660,6 +675,21 @@ class ExceptionReporterFilterTests(TestCase, ExceptionReportTestMixin): response = self.client.get('/raises500/') self.assertNotContains(response, "This should not be displayed", status_code=500) def test_callable_settings_forbidding_to_set_attributes(self): """ Callable settings which forbid to set attributes should not break the debug page (#23070). """ class CallableSettingWithSlots(object): __slots__ = [] def __call__(self): return "This should not be displayed" with self.settings(DEBUG=True, WITH_SLOTS=CallableSettingWithSlots()): response = self.client.get('/raises500/') self.assertNotContains(response, "This should not be displayed", status_code=500) def test_dict_setting_with_non_str_key(self): """ A dict setting containing a non-string key should not break the Loading