Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-django-debug-toolbar for
openSUSE:Factory checked in at 2021-05-10 15:39:13
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-django-debug-toolbar (Old)
and /work/SRC/openSUSE:Factory/.python-django-debug-toolbar.new.2988 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-django-debug-toolbar"
Mon May 10 15:39:13 2021 rev:18 rq:891926 version:3.2.1
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-django-debug-toolbar/python-django-debug-toolbar.changes
2021-01-25 18:24:35.772513753 +0100
+++
/work/SRC/openSUSE:Factory/.python-django-debug-toolbar.new.2988/python-django-debug-toolbar.changes
2021-05-10 15:41:58.320947338 +0200
@@ -1,0 +2,6 @@
+Sun May 9 23:52:34 UTC 2021 - Daniel Molkentin <[email protected]>
+
+- Update to v3.2.1
+ * Fix CVE-2021-30459 by creating signature from all data fields
+
+-------------------------------------------------------------------
Old:
----
django-debug-toolbar-3.2.tar.gz
New:
----
django-debug-toolbar-3.2.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-django-debug-toolbar.spec ++++++
--- /var/tmp/diff_new_pack.gavX1D/_old 2021-05-10 15:41:58.748945664 +0200
+++ /var/tmp/diff_new_pack.gavX1D/_new 2021-05-10 15:41:58.748945664 +0200
@@ -19,7 +19,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define skip_python2 1
Name: python-django-debug-toolbar
-Version: 3.2
+Version: 3.2.1
Release: 0
Summary: A configurable set of panels that display various debug
information
License: BSD-3-Clause
++++++ django-debug-toolbar-3.2.tar.gz -> django-debug-toolbar-3.2.1.tar.gz
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/.github/workflows/test.yml
new/django-debug-toolbar-3.2.1/.github/workflows/test.yml
--- old/django-debug-toolbar-3.2/.github/workflows/test.yml 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/.github/workflows/test.yml 2021-04-14
17:18:10.000000000 +0200
@@ -15,8 +15,7 @@
mariadb:
image: mariadb:10.3
env:
- MYSQL_ROOT_PASSWORD: mysql
- MYSQL_DATABASE: mysql
+ MYSQL_ROOT_PASSWORD: debug_toolbar
options: >-
--health-cmd "mysqladmin ping"
--health-interval 10s
@@ -61,11 +60,10 @@
run: tox
env:
DB_BACKEND: mysql
- DB_NAME: mysql
DB_USER: root
- DB_PASSWORD: mysql
- DB_HOST: "127.0.0.1"
- DB_PORT: "3306"
+ DB_PASSWORD: debug_toolbar
+ DB_HOST: 127.0.0.1
+ DB_PORT: 3306
- name: Upload coverage
uses: codecov/codecov-action@v1
@@ -84,7 +82,9 @@
postgres:
image: 'postgres:9.5'
env:
- POSTGRES_PASSWORD: postgres
+ POSTGRES_DB: debug_toolbar
+ POSTGRES_USER: debug_toolbar
+ POSTGRES_PASSWORD: debug_toolbar
ports:
- 5432:5432
options: >-
@@ -129,9 +129,6 @@
run: tox
env:
DB_BACKEND: postgresql
- DB_NAME: postgres
- DB_USER: postgres
- DB_PASSWORD: postgres
DB_HOST: localhost
DB_PORT: 5432
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/.tx/config
new/django-debug-toolbar-3.2.1/.tx/config
--- old/django-debug-toolbar-3.2/.tx/config 2020-12-03 09:11:15.000000000
+0100
+++ new/django-debug-toolbar-3.2.1/.tx/config 2021-04-14 17:18:10.000000000
+0200
@@ -2,7 +2,7 @@
host = https://www.transifex.com
lang_map = sr@latin:sr_Latn
-[django-debug-toolbar.master]
+[django-debug-toolbar.main]
file_filter = debug_toolbar/locale/<lang>/LC_MESSAGES/django.po
source_file = debug_toolbar/locale/en/LC_MESSAGES/django.po
source_lang = en
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/Makefile
new/django-debug-toolbar-3.2.1/Makefile
--- old/django-debug-toolbar-3.2/Makefile 2020-12-03 09:11:15.000000000
+0100
+++ new/django-debug-toolbar-3.2.1/Makefile 2021-04-14 17:18:10.000000000
+0200
@@ -8,6 +8,7 @@
flake8
npx eslint --ignore-path .gitignore --fix .
npx prettier --ignore-path .gitignore --write $(PRETTIER_TARGETS)
+ ! grep -r '\(style=\|onclick=\|<script>\|<style\)'
debug_toolbar/templates/
style_check: package-lock.json
isort -c .
@@ -15,6 +16,7 @@
flake8
npx eslint --ignore-path .gitignore .
npx prettier --ignore-path .gitignore --check $(PRETTIER_TARGETS)
+ ! grep -r '\(style=\|onclick=\|<script>\|<style\)'
debug_toolbar/templates/
example:
python example/manage.py migrate --noinput
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/README.rst
new/django-debug-toolbar-3.2.1/README.rst
--- old/django-debug-toolbar-3.2/README.rst 2020-12-03 09:11:15.000000000
+0100
+++ new/django-debug-toolbar-3.2.1/README.rst 2021-04-14 17:18:10.000000000
+0200
@@ -10,7 +10,7 @@
:target: https://github.com/jazzband/django-debug-toolbar/actions
:alt: Build Status
-.. image::
https://codecov.io/gh/jazzband/django-debug-toolbar/branch/master/graph/badge.svg
+.. image::
https://codecov.io/gh/jazzband/django-debug-toolbar/branch/main/graph/badge.svg
:target: https://codecov.io/gh/jazzband/django-debug-toolbar
:alt: Test coverage status
@@ -28,13 +28,13 @@
Here's a screenshot of the toolbar in action:
-.. image::
https://raw.github.com/jazzband/django-debug-toolbar/master/example/django-debug-toolbar.png
+.. image::
https://raw.github.com/jazzband/django-debug-toolbar/main/example/django-debug-toolbar.png
:alt: Django Debug Toolbar screenshot
In addition to the built-in panels, a number of third-party panels are
contributed by the community.
-The current stable version of the Debug Toolbar is 3.2. It works on
+The current stable version of the Debug Toolbar is 3.2.1. It works on
Django ??? 2.2.
Documentation, including installation and configuration instructions, is
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/debug_toolbar/__init__.py
new/django-debug-toolbar-3.2.1/debug_toolbar/__init__.py
--- old/django-debug-toolbar-3.2/debug_toolbar/__init__.py 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/debug_toolbar/__init__.py 2021-04-14
17:18:10.000000000 +0200
@@ -1,13 +1,9 @@
__all__ = ["VERSION"]
-try:
- import pkg_resources
-
- VERSION = pkg_resources.get_distribution("django-debug-toolbar").version
-except Exception:
- VERSION = "unknown"
-
+# Do not use pkg_resources to find the version but set it here directly!
+# see issue #1446
+VERSION = "3.2.1"
# Code that discovers files or modules in INSTALLED_APPS imports this module.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/debug_toolbar/decorators.py
new/django-debug-toolbar-3.2.1/debug_toolbar/decorators.py
--- old/django-debug-toolbar-3.2/debug_toolbar/decorators.py 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/debug_toolbar/decorators.py 2021-04-14
17:18:10.000000000 +0200
@@ -1,6 +1,6 @@
import functools
-from django.http import Http404
+from django.http import Http404, HttpResponseBadRequest
def require_show_toolbar(view):
@@ -15,3 +15,21 @@
return view(request, *args, **kwargs)
return inner
+
+
+def signed_data_view(view):
+ """Decorator that handles unpacking a signed data form"""
+
+ @functools.wraps(view)
+ def inner(request, *args, **kwargs):
+ from debug_toolbar.forms import SignedDataForm
+
+ data = request.GET if request.method == "GET" else request.POST
+ signed_form = SignedDataForm(data)
+ if signed_form.is_valid():
+ return view(
+ request, *args, verified_data=signed_form.verified_data(),
**kwargs
+ )
+ return HttpResponseBadRequest("Invalid signature")
+
+ return inner
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/debug_toolbar/forms.py
new/django-debug-toolbar-3.2.1/debug_toolbar/forms.py
--- old/django-debug-toolbar-3.2/debug_toolbar/forms.py 1970-01-01
01:00:00.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/debug_toolbar/forms.py 2021-04-14
17:18:10.000000000 +0200
@@ -0,0 +1,53 @@
+import json
+
+from django import forms
+from django.core import signing
+from django.core.exceptions import ValidationError
+from django.utils.encoding import force_str
+
+
+class SignedDataForm(forms.Form):
+ """Helper form that wraps a form to validate its contents on post.
+
+ class PanelForm(forms.Form):
+ # fields
+
+ On render:
+ form = SignedDataForm(initial=PanelForm(initial=data).initial)
+
+ On POST:
+ signed_form = SignedDataForm(request.POST)
+ if signed_form.is_valid():
+ panel_form = PanelForm(signed_form.verified_data)
+ if panel_form.is_valid():
+ # Success
+ Or wrap the FBV with ``debug_toolbar.decorators.signed_data_view``
+ """
+
+ salt = "django_debug_toolbar"
+ signed = forms.CharField(required=True, widget=forms.HiddenInput)
+
+ def __init__(self, *args, **kwargs):
+ initial = kwargs.pop("initial", None)
+ if initial:
+ initial = {"signed": self.sign(initial)}
+ super().__init__(*args, initial=initial, **kwargs)
+
+ def clean_signed(self):
+ try:
+ verified = json.loads(
+
signing.Signer(salt=self.salt).unsign(self.cleaned_data["signed"])
+ )
+ return verified
+ except signing.BadSignature:
+ raise ValidationError("Bad signature")
+
+ def verified_data(self):
+ return self.is_valid() and self.cleaned_data["signed"]
+
+ @classmethod
+ def sign(cls, data):
+ items = sorted(data.items(), key=lambda item: item[0])
+ return signing.Signer(salt=cls.salt).sign(
+ json.dumps({key: force_str(value) for key, value in items})
+ )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/debug_toolbar/middleware.py
new/django-debug-toolbar-3.2.1/debug_toolbar/middleware.py
--- old/django-debug-toolbar-3.2/debug_toolbar/middleware.py 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/debug_toolbar/middleware.py 2021-04-14
17:18:10.000000000 +0200
@@ -44,7 +44,7 @@
def __call__(self, request):
# Decide whether the toolbar is active for this request.
show_toolbar = get_show_toolbar()
- if not show_toolbar(request) or request.path.startswith("/__debug__/"):
+ if not show_toolbar(request) or
DebugToolbar.is_toolbar_request(request):
return self.get_response(request)
toolbar = DebugToolbar(request, self.get_response)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/debug_toolbar/panels/cache.py
new/django-debug-toolbar-3.2.1/debug_toolbar/panels/cache.py
--- old/django-debug-toolbar-3.2/debug_toolbar/panels/cache.py 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/debug_toolbar/panels/cache.py
2021-04-14 17:18:10.000000000 +0200
@@ -3,9 +3,19 @@
import time
from collections import OrderedDict
+try:
+ from django.utils.connection import ConnectionProxy
+except ImportError:
+ ConnectionProxy = None
+
from django.conf import settings
from django.core import cache
-from django.core.cache import CacheHandler, caches as original_caches
+from django.core.cache import (
+ DEFAULT_CACHE_ALIAS,
+ CacheHandler,
+ cache as original_cache,
+ caches as original_caches,
+)
from django.core.cache.backends.base import BaseCache
from django.dispatch import Signal
from django.middleware import cache as middleware_cache
@@ -246,8 +256,13 @@
else:
cache.caches = CacheHandlerPatch()
+ # Wrap the patched cache inside Django's ConnectionProxy
+ if ConnectionProxy:
+ cache.cache = ConnectionProxy(cache.caches, DEFAULT_CACHE_ALIAS)
+
def disable_instrumentation(self):
cache.caches = original_caches
+ cache.cache = original_cache
# While it can be restored to the original, any views that were
# wrapped with the cache_page decorator will continue to use a
# monkey patched cache.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/debug_toolbar/panels/history/forms.py
new/django-debug-toolbar-3.2.1/debug_toolbar/panels/history/forms.py
--- old/django-debug-toolbar-3.2/debug_toolbar/panels/history/forms.py
2020-12-03 09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/debug_toolbar/panels/history/forms.py
2021-04-14 17:18:10.000000000 +0200
@@ -1,11 +1,4 @@
-import hashlib
-import hmac
-
from django import forms
-from django.conf import settings
-from django.core.exceptions import ValidationError
-from django.utils.crypto import constant_time_compare
-from django.utils.encoding import force_bytes
class HistoryStoreForm(forms.Form):
@@ -16,26 +9,3 @@
"""
store_id = forms.CharField(widget=forms.HiddenInput())
- hash = forms.CharField(widget=forms.HiddenInput())
-
- def __init__(self, *args, **kwargs):
- initial = kwargs.get("initial", None)
-
- if initial is not None:
- initial["hash"] = self.make_hash(initial)
-
- super().__init__(*args, **kwargs)
-
- @staticmethod
- def make_hash(data):
- m = hmac.new(key=force_bytes(settings.SECRET_KEY),
digestmod=hashlib.sha1)
- m.update(force_bytes(data["store_id"]))
- return m.hexdigest()
-
- def clean_hash(self):
- hash = self.cleaned_data["hash"]
-
- if not constant_time_compare(hash, self.make_hash(self.data)):
- raise ValidationError("Tamper alert")
-
- return hash
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/debug_toolbar/panels/history/panel.py
new/django-debug-toolbar-3.2.1/debug_toolbar/panels/history/panel.py
--- old/django-debug-toolbar-3.2/debug_toolbar/panels/history/panel.py
2020-12-03 09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/debug_toolbar/panels/history/panel.py
2021-04-14 17:18:10.000000000 +0200
@@ -8,6 +8,7 @@
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
+from debug_toolbar.forms import SignedDataForm
from debug_toolbar.panels import Panel
from debug_toolbar.panels.history import views
from debug_toolbar.panels.history.forms import HistoryStoreForm
@@ -76,7 +77,9 @@
for id, toolbar in reversed(self.toolbar._store.items()):
stores[id] = {
"toolbar": toolbar,
- "form": HistoryStoreForm(initial={"store_id": id}),
+ "form": SignedDataForm(
+ initial=HistoryStoreForm(initial={"store_id": id}).initial
+ ),
}
return render_to_string(
@@ -84,8 +87,10 @@
{
"current_store_id": self.toolbar.store_id,
"stores": stores,
- "refresh_form": HistoryStoreForm(
- initial={"store_id": self.toolbar.store_id}
+ "refresh_form": SignedDataForm(
+ initial=HistoryStoreForm(
+ initial={"store_id": self.toolbar.store_id}
+ ).initial
),
},
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/debug_toolbar/panels/history/views.py
new/django-debug-toolbar-3.2.1/debug_toolbar/panels/history/views.py
--- old/django-debug-toolbar-3.2/debug_toolbar/panels/history/views.py
2020-12-03 09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/debug_toolbar/panels/history/views.py
2021-04-14 17:18:10.000000000 +0200
@@ -1,15 +1,16 @@
from django.http import HttpResponseBadRequest, JsonResponse
from django.template.loader import render_to_string
-from debug_toolbar.decorators import require_show_toolbar
+from debug_toolbar.decorators import require_show_toolbar, signed_data_view
from debug_toolbar.panels.history.forms import HistoryStoreForm
from debug_toolbar.toolbar import DebugToolbar
@require_show_toolbar
-def history_sidebar(request):
+@signed_data_view
+def history_sidebar(request, verified_data):
"""Returns the selected debug toolbar history snapshot."""
- form = HistoryStoreForm(request.GET)
+ form = HistoryStoreForm(verified_data)
if form.is_valid():
store_id = form.cleaned_data["store_id"]
@@ -32,9 +33,10 @@
@require_show_toolbar
-def history_refresh(request):
+@signed_data_view
+def history_refresh(request, verified_data):
"""Returns the refreshed list of table rows for the History Panel."""
- form = HistoryStoreForm(request.GET)
+ form = HistoryStoreForm(verified_data)
if form.is_valid():
requests = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/debug_toolbar/panels/request.py
new/django-debug-toolbar-3.2.1/debug_toolbar/panels/request.py
--- old/django-debug-toolbar-3.2/debug_toolbar/panels/request.py
2020-12-03 09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/debug_toolbar/panels/request.py
2021-04-14 17:18:10.000000000 +0200
@@ -44,7 +44,16 @@
view_info["view_func"] = get_name_from_obj(func)
view_info["view_args"] = args
view_info["view_kwargs"] = kwargs
- view_info["view_urlname"] = getattr(match, "url_name",
_("<unavailable>"))
+
+ if getattr(match, "url_name", False):
+ url_name = match.url_name
+ if match.namespaces:
+ url_name = ":".join([*match.namespaces, url_name])
+ else:
+ url_name = _("<unavailable>")
+
+ view_info["view_urlname"] = url_name
+
except Http404:
pass
self.record_stats(view_info)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/debug_toolbar/panels/sql/forms.py
new/django-debug-toolbar-3.2.1/debug_toolbar/panels/sql/forms.py
--- old/django-debug-toolbar-3.2/debug_toolbar/panels/sql/forms.py
2020-12-03 09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/debug_toolbar/panels/sql/forms.py
2021-04-14 17:18:10.000000000 +0200
@@ -1,13 +1,8 @@
-import hashlib
-import hmac
import json
from django import forms
-from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import connections
-from django.utils.crypto import constant_time_compare
-from django.utils.encoding import force_bytes
from django.utils.functional import cached_property
from debug_toolbar.panels.sql.utils import reformat_sql
@@ -21,7 +16,6 @@
raw_sql: The sql statement with placeholders
params: JSON encoded parameter values
duration: time for SQL to execute passed in from toolbar just for
redisplay
- hash: the hash of (secret + sql + params) for tamper checking
"""
sql = forms.CharField()
@@ -29,17 +23,6 @@
params = forms.CharField()
alias = forms.CharField(required=False, initial="default")
duration = forms.FloatField()
- hash = forms.CharField()
-
- def __init__(self, *args, **kwargs):
- initial = kwargs.get("initial")
- if initial is not None:
- initial["hash"] = self.make_hash(initial)
-
- super().__init__(*args, **kwargs)
-
- for name in self.fields:
- self.fields[name].widget = forms.HiddenInput()
def clean_raw_sql(self):
value = self.cleaned_data["raw_sql"]
@@ -65,23 +48,9 @@
return value
- def clean_hash(self):
- hash = self.cleaned_data["hash"]
-
- if not constant_time_compare(hash, self.make_hash(self.data)):
- raise ValidationError("Tamper alert")
-
- return hash
-
def reformat_sql(self):
return reformat_sql(self.cleaned_data["sql"], with_toggle=False)
- def make_hash(self, data):
- m = hmac.new(key=force_bytes(settings.SECRET_KEY),
digestmod=hashlib.sha1)
- for item in [data["sql"], data["params"]]:
- m.update(force_bytes(item))
- return m.hexdigest()
-
@property
def connection(self):
return connections[self.cleaned_data["alias"]]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/debug_toolbar/panels/sql/panel.py
new/django-debug-toolbar-3.2.1/debug_toolbar/panels/sql/panel.py
--- old/django-debug-toolbar-3.2/debug_toolbar/panels/sql/panel.py
2020-12-03 09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/debug_toolbar/panels/sql/panel.py
2021-04-14 17:18:10.000000000 +0200
@@ -7,6 +7,7 @@
from django.urls import path
from django.utils.translation import gettext_lazy as _, ngettext_lazy as __
+from debug_toolbar.forms import SignedDataForm
from debug_toolbar.panels import Panel
from debug_toolbar.panels.sql import views
from debug_toolbar.panels.sql.forms import SQLSelectForm
@@ -211,7 +212,9 @@
query["vendor"], query["trans_status"]
)
- query["form"] = SQLSelectForm(auto_id=None,
initial=copy(query))
+ query["form"] = SignedDataForm(
+ auto_id=None,
initial=SQLSelectForm(initial=copy(query)).initial
+ )
if query["sql"]:
query["sql"] = reformat_sql(query["sql"], with_toggle=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/debug_toolbar/panels/sql/utils.py
new/django-debug-toolbar-3.2.1/debug_toolbar/panels/sql/utils.py
--- old/django-debug-toolbar-3.2/debug_toolbar/panels/sql/utils.py
2020-12-03 09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/debug_toolbar/panels/sql/utils.py
2021-04-14 17:18:10.000000000 +0200
@@ -4,6 +4,8 @@
from django.utils.html import escape
from sqlparse import tokens as T
+from debug_toolbar import settings as dt_settings
+
class BoldKeywordFilter:
"""sqlparse filter to bold SQL keywords"""
@@ -31,7 +33,8 @@
def parse_sql(sql, aligned_indent=False):
stack = sqlparse.engine.FilterStack()
- stack.enable_grouping()
+ if dt_settings.get_config()["PRETTIFY_SQL"]:
+ stack.enable_grouping()
if aligned_indent:
stack.stmtprocess.append(
sqlparse.filters.AlignedIndentFilter(char=" ", n="<br/>")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/debug_toolbar/panels/sql/views.py
new/django-debug-toolbar-3.2.1/debug_toolbar/panels/sql/views.py
--- old/django-debug-toolbar-3.2/debug_toolbar/panels/sql/views.py
2020-12-03 09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/debug_toolbar/panels/sql/views.py
2021-04-14 17:18:10.000000000 +0200
@@ -2,15 +2,16 @@
from django.template.loader import render_to_string
from django.views.decorators.csrf import csrf_exempt
-from debug_toolbar.decorators import require_show_toolbar
+from debug_toolbar.decorators import require_show_toolbar, signed_data_view
from debug_toolbar.panels.sql.forms import SQLSelectForm
@csrf_exempt
@require_show_toolbar
-def sql_select(request):
+@signed_data_view
+def sql_select(request, verified_data):
"""Returns the output of the SQL SELECT statement"""
- form = SQLSelectForm(request.POST or None)
+ form = SQLSelectForm(verified_data)
if form.is_valid():
sql = form.cleaned_data["raw_sql"]
@@ -34,9 +35,10 @@
@csrf_exempt
@require_show_toolbar
-def sql_explain(request):
+@signed_data_view
+def sql_explain(request, verified_data):
"""Returns the output of the SQL EXPLAIN on the given query"""
- form = SQLSelectForm(request.POST or None)
+ form = SQLSelectForm(verified_data)
if form.is_valid():
sql = form.cleaned_data["raw_sql"]
@@ -69,9 +71,10 @@
@csrf_exempt
@require_show_toolbar
-def sql_profile(request):
+@signed_data_view
+def sql_profile(request, verified_data):
"""Returns the output of running the SQL and getting the profiling
statistics"""
- form = SQLSelectForm(request.POST or None)
+ form = SQLSelectForm(verified_data)
if form.is_valid():
sql = form.cleaned_data["raw_sql"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/debug_toolbar/settings.py
new/django-debug-toolbar-3.2.1/debug_toolbar/settings.py
--- old/django-debug-toolbar-3.2/debug_toolbar/settings.py 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/debug_toolbar/settings.py 2021-04-14
17:18:10.000000000 +0200
@@ -37,6 +37,7 @@
"django.utils.deprecation",
"django.utils.functional",
),
+ "PRETTIFY_SQL": True,
"PROFILER_MAX_DEPTH": 10,
"SHOW_TEMPLATE_CONTEXT": True,
"SKIP_TEMPLATE_PREFIXES": ("django/forms/widgets/", "admin/widgets/"),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/debug_toolbar/static/debug_toolbar/css/toolbar.css
new/django-debug-toolbar-3.2.1/debug_toolbar/static/debug_toolbar/css/toolbar.css
---
old/django-debug-toolbar-3.2/debug_toolbar/static/debug_toolbar/css/toolbar.css
2020-12-03 09:11:15.000000000 +0100
+++
new/django-debug-toolbar-3.2.1/debug_toolbar/static/debug_toolbar/css/toolbar.css
2021-04-14 17:18:10.000000000 +0200
@@ -601,6 +601,9 @@
#djDebug .djdt-width-60 {
width: 60%;
}
+#djDebug .djdt-max-height-100 {
+ max-height: 100%;
+}
#djDebug .djdt-highlighted {
background-color: lightgrey;
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/debug_toolbar/static/debug_toolbar/js/toolbar.js
new/django-debug-toolbar-3.2.1/debug_toolbar/static/debug_toolbar/js/toolbar.js
---
old/django-debug-toolbar-3.2/debug_toolbar/static/debug_toolbar/js/toolbar.js
2020-12-03 09:11:15.000000000 +0100
+++
new/django-debug-toolbar-3.2.1/debug_toolbar/static/debug_toolbar/js/toolbar.js
2021-04-14 17:18:10.000000000 +0200
@@ -44,6 +44,7 @@
inner.previousElementSibling.remove(); // Remove
AJAX loader
inner.innerHTML = data.content;
$$.executeScripts(data.scripts);
+ $$.applyStyles(inner);
});
}
}
@@ -270,6 +271,9 @@
options.path ? "; path=" + options.path : "",
options.domain ? "; domain=" + options.domain : "",
options.secure ? "; secure" : "",
+ "sameSite" in options
+ ? "; sameSite=" + options.samesite
+ : "; sameSite=Lax",
].join("");
return value;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/debug_toolbar/static/debug_toolbar/js/utils.js
new/django-debug-toolbar-3.2.1/debug_toolbar/static/debug_toolbar/js/utils.js
--- old/django-debug-toolbar-3.2/debug_toolbar/static/debug_toolbar/js/utils.js
2020-12-03 09:11:15.000000000 +0100
+++
new/django-debug-toolbar-3.2.1/debug_toolbar/static/debug_toolbar/js/utils.js
2021-04-14 17:18:10.000000000 +0200
@@ -32,6 +32,26 @@
document.head.appendChild(el);
});
},
+ applyStyles(container) {
+ /*
+ * Given a container element, apply styles set via data-djdt-styles
attribute.
+ * The format is data-djdt-styles="styleName1:value;styleName2:value2"
+ * The style names should use the CSSStyleDeclaration camel cased
names.
+ */
+ container
+ .querySelectorAll("[data-djdt-styles]")
+ .forEach(function (element) {
+ const styles = element.dataset.djdtStyles || "";
+ styles.split(";").forEach(function (styleText) {
+ const styleKeyPair = styleText.split(":");
+ if (styleKeyPair.length === 2) {
+ const name = styleKeyPair[0].trim();
+ const value = styleKeyPair[1].trim();
+ element.style[name] = value;
+ }
+ });
+ });
+ },
};
function ajax(url, init) {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/debug_toolbar/templates/debug_toolbar/panels/history.html
new/django-debug-toolbar-3.2.1/debug_toolbar/templates/debug_toolbar/panels/history.html
---
old/django-debug-toolbar-3.2/debug_toolbar/templates/debug_toolbar/panels/history.html
2020-12-03 09:11:15.000000000 +0100
+++
new/django-debug-toolbar-3.2.1/debug_toolbar/templates/debug_toolbar/panels/history.html
2021-04-14 17:18:10.000000000 +0200
@@ -3,7 +3,7 @@
{{ refresh_form }}
<button class="refreshHistory">Refresh</button>
</form>
-<table style="max-height:100%;">
+<table class="djdt-max-height-100">
<thead>
<tr>
<th>{% trans "Time" %}</th>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/debug_toolbar/templates/debug_toolbar/panels/profiling.html
new/django-debug-toolbar-3.2.1/debug_toolbar/templates/debug_toolbar/panels/profiling.html
---
old/django-debug-toolbar-3.2/debug_toolbar/templates/debug_toolbar/panels/profiling.html
2020-12-03 09:11:15.000000000 +0100
+++
new/django-debug-toolbar-3.2.1/debug_toolbar/templates/debug_toolbar/panels/profiling.html
2021-04-14 17:18:10.000000000 +0200
@@ -14,7 +14,7 @@
{% for call in func_list %}
<tr class="{% for parent_id in call.parent_ids %} djToggleDetails_{{
parent_id }}{% endfor %}" id="profilingMain_{{ call.id }}">
<td>
- <div style="padding-left:{{ call.indent }}px">
+ <div data-djdt-styles="paddingLeft:{{ call.indent }}px">
{% if call.has_subfuncs %}
<button type="button" class="djProfileToggleDetails
djToggleSwitch" data-toggle-name="profilingMain" data-toggle-id="{{ call.id
}}">-</button>
{% else %}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/debug_toolbar/templates/debug_toolbar/panels/sql.html
new/django-debug-toolbar-3.2.1/debug_toolbar/templates/debug_toolbar/panels/sql.html
---
old/django-debug-toolbar-3.2/debug_toolbar/templates/debug_toolbar/panels/sql.html
2020-12-03 09:11:15.000000000 +0100
+++
new/django-debug-toolbar-3.2.1/debug_toolbar/templates/debug_toolbar/panels/sql.html
2021-04-14 17:18:10.000000000 +0200
@@ -2,7 +2,7 @@
<ul>
{% for alias, info in databases %}
<li>
- <strong><span class="djdt-color" style="background-color:rgb({{
info.rgb_color|join:', ' }})"></span> {{ alias }}</strong>
+ <strong><span class="djdt-color"
data-djdt-styles="backgroundColor:rgb({{ info.rgb_color|join:', ' }})"></span>
{{ alias }}</strong>
{{ info.time_spent|floatformat:"2" }} ms ({% blocktrans count
info.num_queries as num %}{{ num }} query{% plural %}{{ num }} queries{%
endblocktrans %}
{% if info.similar_count %}
{% blocktrans with count=info.similar_count trimmed %}
@@ -40,7 +40,7 @@
<tbody>
{% for query in queries %}
<tr class="{% if query.is_slow %} djDebugRowWarning{% endif %}"
id="sqlMain_{{ forloop.counter }}">
- <td><span class="djdt-color" style="background-color:rgb({{
query.rgb_color|join:', '}})"></span></td>
+ <td><span class="djdt-color"
data-djdt-styles="backgroundColor:rgb({{ query.rgb_color|join:',
'}})"></span></td>
<td class="djdt-toggle">
<button type="button" class="djToggleSwitch"
data-toggle-name="sqlMain" data-toggle-id="{{ forloop.counter }}">+</button>
</td>
@@ -48,13 +48,13 @@
<div class="djDebugSql">{{ query.sql|safe }}</div>
{% if query.similar_count %}
<strong>
- <span class="djdt-color" style="background-color:{{
query.similar_color }}"></span>
+ <span class="djdt-color" data-djdt-styles="backgroundColor:{{
query.similar_color }}"></span>
{% blocktrans with count=query.similar_count %}{{ count }}
similar queries.{% endblocktrans %}
</strong>
{% endif %}
{% if query.duplicate_count %}
<strong>
- <span class="djdt-color" style="background-color:{{
query.duplicate_color }}"></span>
+ <span class="djdt-color" data-djdt-styles="backgroundColor:{{
query.duplicate_color }}"></span>
{% blocktrans with dupes=query.duplicate_count %}Duplicated {{
dupes }} times.{% endblocktrans %}
</strong>
{% endif %}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/debug_toolbar/toolbar.py
new/django-debug-toolbar-3.2.1/debug_toolbar/toolbar.py
--- old/django-debug-toolbar-3.2/debug_toolbar/toolbar.py 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/debug_toolbar/toolbar.py 2021-04-14
17:18:10.000000000 +0200
@@ -9,7 +9,8 @@
from django.core.exceptions import ImproperlyConfigured
from django.template import TemplateSyntaxError
from django.template.loader import render_to_string
-from django.urls import path
+from django.urls import path, resolve
+from django.urls.exceptions import Resolver404
from django.utils.module_loading import import_string
from debug_toolbar import settings as dt_settings
@@ -133,6 +134,19 @@
cls._urlpatterns = urlpatterns
return cls._urlpatterns
+ @classmethod
+ def is_toolbar_request(cls, request):
+ """
+ Determine if the request is for a DebugToolbar view.
+ """
+ # The primary caller of this function is in the middleware which may
+ # not have resolver_match set.
+ try:
+ resolver_match = request.resolver_match or resolve(request.path)
+ except Resolver404:
+ return False
+ return resolver_match.namespaces and resolver_match.namespaces[-1] ==
app_name
+
app_name = "djdt"
urlpatterns = DebugToolbar.get_urls()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/docs/changes.rst
new/django-debug-toolbar-3.2.1/docs/changes.rst
--- old/django-debug-toolbar-3.2/docs/changes.rst 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/docs/changes.rst 2021-04-14
17:18:10.000000000 +0200
@@ -1,6 +1,24 @@
Change log
==========
+Next version
+------------
+
+
+3.2.1 (2021-04-14)
+------------------
+
+* Fixed SQL Injection vulnerability, CVE-2021-30459. The toolbar now
+ calculates a signature on all fields for the SQL select, explain,
+ and analyze forms.
+* Changed ``djdt.cookie.set()`` to set ``sameSite=Lax`` by default if
+ callers do not provide a value.
+* Added ``PRETTIFY_SQL`` configuration option to support controlling
+ SQL token grouping. By default it's set to True. When set to False,
+ a performance improvement can be seen by the SQL panel.
+* Fixed issue with toolbar expecting URL paths to start with `/__debug__/`
+ while the documentation indicates it's not required.
+
3.2 (2020-12-03)
----------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/docs/conf.py
new/django-debug-toolbar-3.2.1/docs/conf.py
--- old/django-debug-toolbar-3.2/docs/conf.py 2020-12-03 09:11:15.000000000
+0100
+++ new/django-debug-toolbar-3.2.1/docs/conf.py 2021-04-14 17:18:10.000000000
+0200
@@ -25,7 +25,7 @@
copyright = copyright.format(datetime.date.today().year)
# The full version, including alpha/beta/rc tags
-release = "3.2"
+release = "3.2.1"
# -- General configuration ---------------------------------------------------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/docs/configuration.rst
new/django-debug-toolbar-3.2.1/docs/configuration.rst
--- old/django-debug-toolbar-3.2/docs/configuration.rst 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/docs/configuration.rst 2021-04-14
17:18:10.000000000 +0200
@@ -180,6 +180,39 @@
Useful for eliminating server-related entries which can result
in enormous DOM structures and toolbar rendering delays.
+* ``PRETTIFY_SQL``
+
+ Default: ``True``
+
+ Panel: SQL
+
+ Controls SQL token grouping.
+
+ Token grouping allows pretty print of similar tokens,
+ like aligned indentation for every selected field.
+
+ When set to ``True``, it might cause render slowdowns
+ when a view make long SQL textual queries.
+
+ **Without grouping**::
+
+ SELECT "auth_user"."id", "auth_user"."password", "auth_user"."last_login",
"auth_user"."is_superuser", "auth_user"."username", "auth_user"."first_name",
"auth_user"."last_name"
+ FROM "auth_user"
+ WHERE "auth_user"."username" = '''test_username'''
+ LIMIT 21
+
+ **With grouping**::
+
+ SELECT "auth_user"."id",
+ "auth_user"."password",
+ "auth_user"."last_login",
+ "auth_user"."is_superuser",
+ "auth_user"."username",
+ "auth_user"."first_name",
+ "auth_user"."last_name",
+ FROM "auth_user"
+ WHERE "auth_user"."username" = '''test_username'''
+ LIMIT 21
* ``PROFILER_MAX_DEPTH``
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/docs/contributing.rst
new/django-debug-toolbar-3.2.1/docs/contributing.rst
--- old/django-debug-toolbar-3.2/docs/contributing.rst 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/docs/contributing.rst 2021-04-14
17:18:10.000000000 +0200
@@ -53,7 +53,7 @@
Once you've set up a development environment as explained above, you can run
the test suite for the versions of Django and Python installed in that
-environment::
+environment using the SQLite database::
$ make test
@@ -79,8 +79,23 @@
$ DJANGO_SELENIUM_TESTS=true make coverage
$ DJANGO_SELENIUM_TESTS=true tox
-At this time, there isn't an easy way to test against databases other than
-SQLite.
+To test via `tox` against other databases, you'll need to create the user,
+database and assign the proper permissions. For PostgreSQL in a `psql`
+shell (note this allows the debug_toolbar user the permission to create
+databases)::
+
+ psql> CREATE USER debug_toolbar WITH PASSWORD 'debug_toolbar';
+ psql> ALTER USER debug_toolbar CREATEDB;
+ psql> CREATE DATABASE debug_toolbar;
+ psql> GRANT ALL PRIVILEGES ON DATABASE debug_toolbar to debug_toolbar;
+
+For MySQL/MariaDB in a `mysql` shell::
+
+ mysql> CREATE DATABASE debug_toolbar;
+ mysql> CREATE USER 'debug_toolbar'@'localhost' IDENTIFIED BY
'debug_toolbar';
+ mysql> GRANT ALL PRIVILEGES ON debug_toolbar.* TO
'debug_toolbar'@'localhost';
+ mysql> GRANT ALL PRIVILEGES ON test_debug_toolbar.* TO
'debug_toolbar'@'localhost';
+
Style
-----
@@ -141,8 +156,8 @@
Commit.
#. Bump version numbers in ``docs/changes.rst``, ``docs/conf.py``,
- ``README.rst`` and ``setup.py``. Add the release date to
- ``docs/changes.rst``. Commit.
+ ``README.rst``, ``debug_toolbar/__init__.py`` and ``setup.py``.
+ Add the release date to ``docs/changes.rst``. Commit.
#. Tag the new version.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/docs/installation.rst
new/django-debug-toolbar-3.2.1/docs/installation.rst
--- old/django-debug-toolbar-3.2/docs/installation.rst 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/docs/installation.rst 2021-04-14
17:18:10.000000000 +0200
@@ -83,8 +83,8 @@
------------------------
The Debug Toolbar is shown only if your IP address is listed in the
-:django:setting:`INTERNAL_IPS` setting. This means that for local
-development, you *must* add ``'127.0.0.1'`` to :django:setting:`INTERNAL_IPS`;
+:setting:`INTERNAL_IPS` setting. This means that for local
+development, you *must* add ``'127.0.0.1'`` to :setting:`INTERNAL_IPS`;
you'll need to create this setting if it doesn't already exist in your
settings module::
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/docs/panels.rst
new/django-debug-toolbar-3.2.1/docs/panels.rst
--- old/django-debug-toolbar-3.2/docs/panels.rst 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/docs/panels.rst 2021-04-14
17:18:10.000000000 +0200
@@ -177,6 +177,18 @@
Inspector panel also logs to the console by default, but may be instructed not
to.
+LDAP Tracing
+~~~~~~~~~~~~
+
+URL: https://github.com/danyi1212/django-windowsauth
+
+Path: ``windows_auth.panels.LDAPPanel``
+
+LDAP Operations performed during the request, including timing, request and
response messages,
+the entries received, write changes list, stack-tracing and error debugging.
+This panel also shows connection usage metrics when it is collected.
+`Check out the docs
<https://django-windowsauth.readthedocs.io/en/latest/howto/debug_toolbar.html>`_.
+
Line Profiler
~~~~~~~~~~~~~
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/example/settings.py
new/django-debug-toolbar-3.2.1/example/settings.py
--- old/django-debug-toolbar-3.2/example/settings.py 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/example/settings.py 2021-04-14
17:18:10.000000000 +0200
@@ -73,26 +73,23 @@
# To use another database, set the DB_BACKEND environment variable.
if os.environ.get("DB_BACKEND", "").lower() == "postgresql":
- # % su postgres
- # % createuser debug_toolbar
- # % createdb debug_toolbar -O debug_toolbar
+ # See docs/contributing for instructions on configuring PostgreSQL.
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "debug_toolbar",
"USER": "debug_toolbar",
+ "PASSWORD": "debug_toolbar",
}
}
if os.environ.get("DB_BACKEND", "").lower() == "mysql":
- # % mysql
- # mysql> CREATE DATABASE debug_toolbar;
- # mysql> CREATE USER 'debug_toolbar'@'localhost';
- # mysql> GRANT ALL PRIVILEGES ON debug_toolbar.* TO
'debug_toolbar'@'localhost';
+ # See docs/contributing for instructions on configuring MySQL/MariaDB.
DATABASES = {
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": "debug_toolbar",
"USER": "debug_toolbar",
+ "PASSWORD": "debug_toolbar",
}
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/setup.cfg
new/django-debug-toolbar-3.2.1/setup.cfg
--- old/django-debug-toolbar-3.2/setup.cfg 2020-12-03 09:11:15.000000000
+0100
+++ new/django-debug-toolbar-3.2.1/setup.cfg 2021-04-14 17:18:10.000000000
+0200
@@ -1,6 +1,6 @@
[metadata]
name = django-debug-toolbar
-version = 3.2
+version = 3.2.1
description = A configurable set of panels that display various debug
information about the current request/response.
long_description = file: README.rst
author = Rob Hudson
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/tests/panels/test_history.py
new/django-debug-toolbar-3.2.1/tests/panels/test_history.py
--- old/django-debug-toolbar-3.2/tests/panels/test_history.py 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/tests/panels/test_history.py 2021-04-14
17:18:10.000000000 +0200
@@ -1,9 +1,7 @@
-from unittest.mock import patch
-
from django.test import RequestFactory, override_settings
from django.urls import resolve, reverse
-from debug_toolbar.panels.history.forms import HistoryStoreForm
+from debug_toolbar.forms import SignedDataForm
from debug_toolbar.toolbar import DebugToolbar
from ..base import BaseTestCase, IntegrationTestCase
@@ -83,33 +81,15 @@
response = self.client.get(reverse("djdt:history_sidebar"))
self.assertEqual(response.status_code, 400)
- data = {
- "store_id": "foo",
- "hash": "invalid",
- }
+ data = {"signed": SignedDataForm.sign({"store_id": "foo"}) + "invalid"}
response = self.client.get(reverse("djdt:history_sidebar"), data=data)
self.assertEqual(response.status_code, 400)
- @patch("debug_toolbar.panels.history.views.DebugToolbar.fetch")
- def test_history_sidebar_hash(self, fetch):
- """Validate the hashing mechanism."""
- fetch.return_value.panels = []
- data = {
- "store_id": "foo",
- "hash": "3280d66a3cca10098a44907c5a1fd255265eed31",
- }
- response = self.client.get(reverse("djdt:history_sidebar"), data=data)
- self.assertEqual(response.status_code, 200)
- self.assertEqual(response.json(), {})
-
def test_history_sidebar(self):
"""Validate the history sidebar view."""
self.client.get("/json_view/")
store_id = list(DebugToolbar._store.keys())[0]
- data = {
- "store_id": store_id,
- "hash": HistoryStoreForm.make_hash({"store_id": store_id}),
- }
+ data = {"signed": SignedDataForm.sign({"store_id": store_id})}
response = self.client.get(reverse("djdt:history_sidebar"), data=data)
self.assertEqual(response.status_code, 200)
self.assertEqual(
@@ -130,25 +110,20 @@
},
)
- def test_history_refresh_invalid(self):
+ def test_history_refresh_invalid_signature(self):
response = self.client.get(reverse("djdt:history_refresh"))
self.assertEqual(response.status_code, 400)
- data = {
- "store_id": "foo",
- "hash": "invalid",
- }
+ data = {"signed":
"eyJzdG9yZV9pZCI6ImZvbyIsImhhc2giOiI4YWFiMzIzZGZhODIyMW"}
response = self.client.get(reverse("djdt:history_refresh"), data=data)
self.assertEqual(response.status_code, 400)
+ self.assertEqual(b"Invalid signature", response.content)
def test_history_refresh(self):
"""Verify refresh history response has request variables."""
data = {"foo": "bar"}
self.client.get("/json_view/", data, content_type="application/json")
- data = {
- "store_id": "foo",
- "hash": "3280d66a3cca10098a44907c5a1fd255265eed31",
- }
+ data = {"signed": SignedDataForm.sign({"store_id": "foo"})}
response = self.client.get(reverse("djdt:history_refresh"), data=data)
self.assertEqual(response.status_code, 200)
data = response.json()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/tests/panels/test_request.py
new/django-debug-toolbar-3.2.1/tests/panels/test_request.py
--- old/django-debug-toolbar-3.2/tests/panels/test_request.py 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/tests/panels/test_request.py 2021-04-14
17:18:10.000000000 +0200
@@ -84,3 +84,10 @@
content = self.panel.content
self.assertIn("foo", content)
self.assertIn("bar", content)
+
+ def test_namespaced_url(self):
+ self.request.path = "/admin/login/"
+ response = self.panel.process_request(self.request)
+ self.panel.generate_stats(self.request, response)
+ panel_stats = self.panel.get_stats()
+ self.assertEqual(panel_stats["view_urlname"], "admin:login")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/tests/panels/test_sql.py
new/django-debug-toolbar-3.2.1/tests/panels/test_sql.py
--- old/django-debug-toolbar-3.2/tests/panels/test_sql.py 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/tests/panels/test_sql.py 2021-04-14
17:18:10.000000000 +0200
@@ -9,6 +9,8 @@
from django.shortcuts import render
from django.test.utils import override_settings
+from debug_toolbar import settings as dt_settings
+
from ..base import BaseTestCase
try:
@@ -357,3 +359,40 @@
# ensure the stacktrace is populated
self.assertTrue(len(query[1]["stacktrace"]) > 0)
+
+ @override_settings(
+ DEBUG_TOOLBAR_CONFIG={"PRETTIFY_SQL": True},
+ )
+ def test_prettify_sql(self):
+ """
+ Test case to validate that the PRETTIFY_SQL setting changes the output
+ of the sql when it's toggled. It does not validate what it does
+ though.
+ """
+ list(User.objects.filter(username__istartswith="spam"))
+
+ response = self.panel.process_request(self.request)
+ self.panel.generate_stats(self.request, response)
+ pretty_sql = self.panel._queries[-1][1]["sql"]
+ self.assertEqual(len(self.panel._queries), 1)
+
+ # Reset the queries
+ self.panel._queries = []
+ # Run it again, but with prettyify off. Verify that it's different.
+ dt_settings.get_config()["PRETTIFY_SQL"] = False
+ list(User.objects.filter(username__istartswith="spam"))
+ response = self.panel.process_request(self.request)
+ self.panel.generate_stats(self.request, response)
+ self.assertEqual(len(self.panel._queries), 1)
+ self.assertNotEqual(pretty_sql, self.panel._queries[-1][1]["sql"])
+
+ self.panel._queries = []
+ # Run it again, but with prettyify back on.
+ # This is so we don't have to check what PRETTIFY_SQL does exactly,
+ # but we know it's doing something.
+ dt_settings.get_config()["PRETTIFY_SQL"] = True
+ list(User.objects.filter(username__istartswith="spam"))
+ response = self.panel.process_request(self.request)
+ self.panel.generate_stats(self.request, response)
+ self.assertEqual(len(self.panel._queries), 1)
+ self.assertEqual(pretty_sql, self.panel._queries[-1][1]["sql"])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-debug-toolbar-3.2/tests/panels/test_staticfiles.py
new/django-debug-toolbar-3.2.1/tests/panels/test_staticfiles.py
--- old/django-debug-toolbar-3.2/tests/panels/test_staticfiles.py
2020-12-03 09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/tests/panels/test_staticfiles.py
2021-04-14 17:18:10.000000000 +0200
@@ -1,13 +1,11 @@
import os
+import unittest
+import django
from django.conf import settings
from django.contrib.staticfiles import finders
-from django.core.checks import Warning
-from django.test import SimpleTestCase
from django.test.utils import override_settings
-from debug_toolbar.panels.staticfiles import StaticFilesPanel
-
from ..base import BaseTestCase
PATH_DOES_NOT_EXIST = os.path.join(settings.BASE_DIR, "tests",
"invalid_static")
@@ -54,6 +52,7 @@
)
self.assertValidHTML(content)
+ @unittest.skipIf(django.VERSION >= (4,), "Django>=4 handles missing dirs
itself.")
@override_settings(
STATICFILES_DIRS=[PATH_DOES_NOT_EXIST] + settings.STATICFILES_DIRS,
STATIC_ROOT=PATH_DOES_NOT_EXIST,
@@ -81,20 +80,3 @@
self.assertEqual(
self.panel.get_staticfiles_dirs(),
finders.FileSystemFinder().locations
)
-
-
-@override_settings(DEBUG=True)
-class StaticFilesPanelChecksTestCase(SimpleTestCase):
- @override_settings(STATICFILES_DIRS=[PATH_DOES_NOT_EXIST])
- def test_run_checks(self):
- messages = StaticFilesPanel.run_checks()
- self.assertEqual(
- messages,
- [
- Warning(
- "debug_toolbar requires the STATICFILES_DIRS directories
to exist.",
- hint="Running manage.py collectstatic may help uncover the
issue.",
- id="debug_toolbar.staticfiles.W001",
- )
- ],
- )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/tests/settings.py
new/django-debug-toolbar-3.2.1/tests/settings.py
--- old/django-debug-toolbar-3.2/tests/settings.py 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/tests/settings.py 2021-04-14
17:18:10.000000000 +0200
@@ -81,8 +81,8 @@
DATABASES = {
"default": {
- "ENGINE": "django.db.backends.%s" % os.getenv("DB_BACKEND"),
- "NAME": os.getenv("DB_NAME"),
+ "ENGINE": "django.db.backends.%s" % os.getenv("DB_BACKEND", "sqlite3"),
+ "NAME": os.getenv("DB_NAME", ":memory:"),
"USER": os.getenv("DB_USER"),
"PASSWORD": os.getenv("DB_PASSWORD"),
"HOST": os.getenv("DB_HOST", ""),
@@ -93,6 +93,8 @@
},
}
+DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
+
# Debug Toolbar configuration
DEBUG_TOOLBAR_CONFIG = {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/tests/test_checks.py
new/django-debug-toolbar-3.2.1/tests/test_checks.py
--- old/django-debug-toolbar-3.2/tests/test_checks.py 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/tests/test_checks.py 2021-04-14
17:18:10.000000000 +0200
@@ -1,5 +1,7 @@
import os
+import unittest
+import django
from django.conf import settings
from django.core.checks import Warning, run_checks
from django.test import SimpleTestCase, override_settings
@@ -89,6 +91,7 @@
messages,
)
+ @unittest.skipIf(django.VERSION >= (4,), "Django>=4 handles missing dirs
itself.")
@override_settings(
STATICFILES_DIRS=[PATH_DOES_NOT_EXIST],
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/tests/test_forms.py
new/django-debug-toolbar-3.2.1/tests/test_forms.py
--- old/django-debug-toolbar-3.2/tests/test_forms.py 1970-01-01
01:00:00.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/tests/test_forms.py 2021-04-14
17:18:10.000000000 +0200
@@ -0,0 +1,56 @@
+from datetime import datetime
+
+import django
+from django import forms
+from django.test import TestCase
+
+from debug_toolbar.forms import SignedDataForm
+
+# Django 3.1 uses sha256 by default.
+SIGNATURE = (
+ "v02QBcJplEET6QXHNWejnRcmSENWlw6_RjxLTR7QG9g"
+ if django.VERSION >= (3, 1)
+ else "ukcAFUqYhUUnqT-LupnYoo-KvFg"
+)
+
+DATA = {"value": "foo", "date": datetime(2020, 1, 1)}
+SIGNED_DATA = f'{{"date": "2020-01-01 00:00:00", "value": "foo"}}:{SIGNATURE}'
+
+
+class FooForm(forms.Form):
+ value = forms.CharField()
+ # Include a datetime in the tests because it's not serializable back
+ # to a datetime by SignedDataForm
+ date = forms.DateTimeField()
+
+
+class TestSignedDataForm(TestCase):
+ def test_signed_data(self):
+ data = {"signed": SignedDataForm.sign(DATA)}
+ form = SignedDataForm(data=data)
+ self.assertTrue(form.is_valid())
+ # Check the signature value
+ self.assertEqual(data["signed"], SIGNED_DATA)
+
+ def test_verified_data(self):
+ form = SignedDataForm(data={"signed": SignedDataForm.sign(DATA)})
+ self.assertEqual(
+ form.verified_data(),
+ {
+ "value": "foo",
+ "date": "2020-01-01 00:00:00",
+ },
+ )
+ # Take it back to the foo form to validate the datetime is serialized
+ foo_form = FooForm(data=form.verified_data())
+ self.assertTrue(foo_form.is_valid())
+ self.assertDictEqual(foo_form.cleaned_data, DATA)
+
+ def test_initial_set_signed(self):
+ form = SignedDataForm(initial=DATA)
+ self.assertEqual(form.initial["signed"], SIGNED_DATA)
+
+ def test_prevents_tampering(self):
+ data = {"signed": SIGNED_DATA.replace('"value": "foo"', '"value":
"bar"')}
+ form = SignedDataForm(data=data)
+ self.assertFalse(form.is_valid())
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/tests/test_integration.py
new/django-debug-toolbar-3.2.1/tests/test_integration.py
--- old/django-debug-toolbar-3.2/tests/test_integration.py 2020-12-03
09:11:15.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/tests/test_integration.py 2021-04-14
17:18:10.000000000 +0200
@@ -12,6 +12,7 @@
from django.test import RequestFactory
from django.test.utils import override_settings
+from debug_toolbar.forms import SignedDataForm
from debug_toolbar.middleware import DebugToolbarMiddleware, show_toolbar
from debug_toolbar.panels import Panel
from debug_toolbar.toolbar import DebugToolbar
@@ -101,6 +102,25 @@
self.client.get("/cached_view/")
self.assertEqual(len(self.toolbar.get_panel_by_id("CachePanel").calls), 5)
+ def test_is_toolbar_request(self):
+ self.request.path = "/__debug__/render_panel/"
+ self.assertTrue(self.toolbar.is_toolbar_request(self.request))
+
+ self.request.path = "/invalid/__debug__/render_panel/"
+ self.assertFalse(self.toolbar.is_toolbar_request(self.request))
+
+ self.request.path = "/render_panel/"
+ self.assertFalse(self.toolbar.is_toolbar_request(self.request))
+
+ @override_settings(ROOT_URLCONF="tests.urls_invalid")
+ def test_is_toolbar_request_without_djdt_urls(self):
+ """Test cases when the toolbar urls aren't configured."""
+ self.request.path = "/__debug__/render_panel/"
+ self.assertFalse(self.toolbar.is_toolbar_request(self.request))
+
+ self.request.path = "/render_panel/"
+ self.assertFalse(self.toolbar.is_toolbar_request(self.request))
+
@override_settings(DEBUG=True)
class DebugToolbarIntegrationTestCase(IntegrationTestCase):
@@ -193,12 +213,15 @@
def test_sql_select_checks_show_toolbar(self):
url = "/__debug__/sql_select/"
data = {
- "sql": "SELECT * FROM auth_user",
- "raw_sql": "SELECT * FROM auth_user",
- "params": "{}",
- "alias": "default",
- "duration": "0",
- "hash": "6e12daa636b8c9a8be993307135458f90a877606",
+ "signed": SignedDataForm.sign(
+ {
+ "sql": "SELECT * FROM auth_user",
+ "raw_sql": "SELECT * FROM auth_user",
+ "params": "{}",
+ "alias": "default",
+ "duration": "0",
+ }
+ )
}
response = self.client.post(url, data)
@@ -216,12 +239,15 @@
def test_sql_explain_checks_show_toolbar(self):
url = "/__debug__/sql_explain/"
data = {
- "sql": "SELECT * FROM auth_user",
- "raw_sql": "SELECT * FROM auth_user",
- "params": "{}",
- "alias": "default",
- "duration": "0",
- "hash": "6e12daa636b8c9a8be993307135458f90a877606",
+ "signed": SignedDataForm.sign(
+ {
+ "sql": "SELECT * FROM auth_user",
+ "raw_sql": "SELECT * FROM auth_user",
+ "params": "{}",
+ "alias": "default",
+ "duration": "0",
+ }
+ )
}
response = self.client.post(url, data)
@@ -246,12 +272,15 @@
)
query = base_query + """ '{"foo": "bar"}'"""
data = {
- "sql": query,
- "raw_sql": base_query + " %s",
- "params": '["{\\"foo\\": \\"bar\\"}"]',
- "alias": "default",
- "duration": "0",
- "hash": "2b7172eb2ac8e2a8d6f742f8a28342046e0d00ba",
+ "signed": SignedDataForm.sign(
+ {
+ "sql": query,
+ "raw_sql": base_query + " %s",
+ "params": '["{\\"foo\\": \\"bar\\"}"]',
+ "alias": "default",
+ "duration": "0",
+ }
+ )
}
response = self.client.post(url, data)
self.assertEqual(response.status_code, 200)
@@ -268,12 +297,15 @@
def test_sql_profile_checks_show_toolbar(self):
url = "/__debug__/sql_profile/"
data = {
- "sql": "SELECT * FROM auth_user",
- "raw_sql": "SELECT * FROM auth_user",
- "params": "{}",
- "alias": "default",
- "duration": "0",
- "hash": "6e12daa636b8c9a8be993307135458f90a877606",
+ "signed": SignedDataForm.sign(
+ {
+ "sql": "SELECT * FROM auth_user",
+ "raw_sql": "SELECT * FROM auth_user",
+ "params": "{}",
+ "alias": "default",
+ "duration": "0",
+ }
+ )
}
response = self.client.post(url, data)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/tests/urls.py
new/django-debug-toolbar-3.2.1/tests/urls.py
--- old/django-debug-toolbar-3.2/tests/urls.py 2020-12-03 09:11:15.000000000
+0100
+++ new/django-debug-toolbar-3.2.1/tests/urls.py 2021-04-14
17:18:10.000000000 +0200
@@ -1,3 +1,4 @@
+from django.contrib import admin
from django.contrib.auth.views import LoginView
from django.urls import include, path, re_path
@@ -22,5 +23,6 @@
path("json_view/", views.json_view),
path("redirect/", views.redirect_view),
path("login_without_redirect/",
LoginView.as_view(redirect_field_name=None)),
+ path("admin/", admin.site.urls),
path("__debug__/", include(debug_toolbar.urls)),
]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/tests/urls_invalid.py
new/django-debug-toolbar-3.2.1/tests/urls_invalid.py
--- old/django-debug-toolbar-3.2/tests/urls_invalid.py 1970-01-01
01:00:00.000000000 +0100
+++ new/django-debug-toolbar-3.2.1/tests/urls_invalid.py 2021-04-14
17:18:10.000000000 +0200
@@ -0,0 +1,2 @@
+"""Invalid urls.py file for testing"""
+urlpatterns = []
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-debug-toolbar-3.2/tox.ini
new/django-debug-toolbar-3.2.1/tox.ini
--- old/django-debug-toolbar-3.2/tox.ini 2020-12-03 09:11:15.000000000
+0100
+++ new/django-debug-toolbar-3.2.1/tox.ini 2021-04-14 17:18:10.000000000
+0200
@@ -3,20 +3,20 @@
docs
style
readme
- py{36,37,38,39}-dj22-sqlite
- py{36,37,38,39}-dj{30,31}-sqlite
- py{36,37,38,39}-djmaster-sqlite
- py{37,38,39}-dj{22,30,31}-{postgresql,mysql}
+ py{36,37}-dj{22,30,31,32}-sqlite
+ py{38,39}-dj{22,30,31,32,main}-sqlite
+ py{36,37,38,39}-dj{22,30,31,32}-{postgresql,mysql}
[testenv]
deps =
dj22: Django==2.2.*
dj30: Django==3.0.*
dj31: Django==3.1.*
+ dj32: Django>=3.2a1,<4.0
sqlite: mock
postgresql: psycopg2-binary
mysql: mysqlclient
- djmaster: https://github.com/django/django/archive/master.tar.gz
+ djmain: https://github.com/django/django/archive/main.tar.gz
coverage
Jinja2
html5lib
@@ -35,10 +35,32 @@
PYTHONPATH = {toxinidir}
PYTHONWARNINGS = d
py38-dj31-postgresql: DJANGO_SELENIUM_TESTS = true
+ DB_NAME = {env:DB_NAME:debug_toolbar}
+ DB_USER = {env:DB_USER:debug_toolbar}
+ DB_HOST = {env:DB_HOST:localhost}
+ DB_PASSWORD = {env:DB_PASSWORD:debug_toolbar}
whitelist_externals = make
pip_pre = True
commands = make coverage TEST_ARGS='{posargs:tests}'
+[testenv:py{36,37,38,39}-dj{22,30,31,32}-postgresql]
+setenv =
+ {[testenv]setenv}
+ DB_BACKEND = postgresql
+ DB_PORT = {env:DB_PORT:5432}
+
+[testenv:py{36,37,38,39}-dj{22,30,31,32}-mysql]
+setenv =
+ {[testenv]setenv}
+ DB_BACKEND = mysql
+ DB_PORT = {env:DB_PORT:3306}
+
+[testenv:py{36,37,38,39}-dj{22,30,31,32,main}-sqlite]
+setenv =
+ {[testenv]setenv}
+ DB_BACKEND = sqlite3
+ DB_NAME = ":memory:"
+
[testenv:docs]
commands = make -C {toxinidir}/docs spelling
deps =