Skip to content

Commit

Permalink
Merge pull request from GHSA-pghf-347x-c2gj
Browse files Browse the repository at this point in the history
* Changes required to support v2.2.x branch

Style corrections for tox.

Remove djmaster from tox requirements.

Switch to Github actions and latest toolbar tox/settings approach.

Skip tests that are invalid for old versions.

* Fix CVE-2021-30459 by creating signature from all data fields.

Backport of 1c6ba3c1302bf545f8356dcd26255ab7db1ec408

Create a signature based on all fields in the form and attach
to validate that the data being sent back is what the server
generated initially.

Change the hashing algorithm to SHA256

Force the values to a string for signing.

Remove hashing mechanism from forms.

Support sha1 algorithm for django < 3.1

* Bump to version 2.2.1
  • Loading branch information
tim-schilling committed Apr 14, 2021
1 parent e154955 commit 5e6750b
Show file tree
Hide file tree
Showing 22 changed files with 679 additions and 123 deletions.
196 changes: 196 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
name: Test

on: [push, pull_request]

jobs:
mysql:
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 5
matrix:
python-version: ['3.5', '3.6', '3.7', '3.8']

services:
mariadb:
image: mariadb:10.3
env:
MYSQL_ROOT_PASSWORD: debug_toolbar
options: >-
--health-cmd "mysqladmin ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 3306:3306

steps:
- uses: actions/checkout@v2

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}

- name: Get pip cache dir
id: pip-cache
run: |
echo "::set-output name=dir::$(pip cache dir)"
- name: Cache
uses: actions/cache@v2
with:
path: ${{ steps.pip-cache.outputs.dir }}
key:
${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.cfg') }}-${{ hashFiles('**/tox.ini') }}
restore-keys: |
${{ matrix.python-version }}-v1-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install --upgrade tox tox-gh-actions
- name: Test with tox
run: tox
env:
DB_BACKEND: mysql
DB_USER: root
DB_PASSWORD: debug_toolbar
DB_HOST: 127.0.0.1
DB_PORT: 3306

- name: Upload coverage
uses: codecov/codecov-action@v1
with:
name: Python ${{ matrix.python-version }}

postgres:
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 5
matrix:
python-version: ['3.5', '3.6', '3.7', '3.8']

services:
postgres:
image: 'postgres:9.5'
env:
POSTGRES_DB: debug_toolbar
POSTGRES_USER: debug_toolbar
POSTGRES_PASSWORD: debug_toolbar
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v2

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}

- name: Get pip cache dir
id: pip-cache
run: |
echo "::set-output name=dir::$(pip cache dir)"
- name: Cache
uses: actions/cache@v2
with:
path: ${{ steps.pip-cache.outputs.dir }}
key:
${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.cfg') }}-${{ hashFiles('**/tox.ini') }}
restore-keys: |
${{ matrix.python-version }}-v1-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install --upgrade tox tox-gh-actions
- name: Test with tox
run: tox
env:
DB_BACKEND: postgresql
DB_HOST: localhost
DB_PORT: 5432

- name: Upload coverage
uses: codecov/codecov-action@v1
with:
name: Python ${{ matrix.python-version }}

sqlite:
runs-on: ubuntu-latest
strategy:
fail-fast: false
max-parallel: 5
matrix:
python-version: ['3.5', '3.6', '3.7', '3.8']

steps:
- uses: actions/checkout@v2

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}

- name: Get pip cache dir
id: pip-cache
run: |
echo "::set-output name=dir::$(pip cache dir)"
- name: Cache
uses: actions/cache@v2
with:
path: ${{ steps.pip-cache.outputs.dir }}
key:
${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.cfg') }}-${{ hashFiles('**/tox.ini') }}
restore-keys: |
${{ matrix.python-version }}-v1-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install --upgrade tox tox-gh-actions
- name: Test with tox
run: tox
env:
DB_BACKEND: sqlite3
DB_NAME: ":memory:"

- name: Upload coverage
uses: codecov/codecov-action@v1
with:
name: Python ${{ matrix.python-version }}

lint:
runs-on: ubuntu-latest
strategy:
fail-fast: false

steps:
- uses: actions/checkout@v2

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: 3.7

- name: Get pip cache dir
id: pip-cache
run: |
echo "::set-output name=dir::$(pip cache dir)"
- name: Cache
uses: actions/cache@v2
with:
path: ${{ steps.pip-cache.outputs.dir }}
key:
${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.cfg') }}-${{ hashFiles('**/tox.ini') }}
restore-keys: |
${{ matrix.python-version }}-v1-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install --upgrade tox
- name: Test with tox
run: tox -e style,readme
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Here's a screenshot of the toolbar in action:
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 2.2. It works on
The current stable version of the Debug Toolbar is 2.2.1. It works on
Django ≥ 1.11.

Documentation, including installation and configuration instructions, is
Expand Down
20 changes: 19 additions & 1 deletion debug_toolbar/decorators.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import functools

from django.http import Http404
from django.http import Http404, HttpResponseBadRequest


def require_show_toolbar(view):
Expand All @@ -15,3 +15,21 @@ def inner(request, *args, **kwargs):
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
54 changes: 54 additions & 0 deletions debug_toolbar/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import json
from collections import OrderedDict

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(OrderedDict((key, force_str(value)) for key, value in items))
)
26 changes: 16 additions & 10 deletions debug_toolbar/panels/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,20 +216,26 @@ def _store_call_info(
@property
def nav_subtitle(self):
cache_calls = len(self.calls)
return __(
"%(cache_calls)d call in %(time).2fms",
"%(cache_calls)d calls in %(time).2fms",
cache_calls,
) % {"cache_calls": cache_calls, "time": self.total_time}
return (
__(
"%(cache_calls)d call in %(time).2fms",
"%(cache_calls)d calls in %(time).2fms",
cache_calls,
)
% {"cache_calls": cache_calls, "time": self.total_time}
)

@property
def title(self):
count = len(getattr(settings, "CACHES", ["default"]))
return __(
"Cache calls from %(count)d backend",
"Cache calls from %(count)d backends",
count,
) % {"count": count}
return (
__(
"Cache calls from %(count)d backend",
"Cache calls from %(count)d backends",
count,
)
% {"count": count}
)

def enable_instrumentation(self):
if isinstance(middleware_cache.caches, CacheHandlerPatch):
Expand Down
11 changes: 11 additions & 0 deletions debug_toolbar/panels/history/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django import forms


class HistoryStoreForm(forms.Form):
"""
Validate params
store_id: The key for the store instance to be fetched.
"""

store_id = forms.CharField(widget=forms.HiddenInput())
Loading

0 comments on commit 5e6750b

Please sign in to comment.