Skip to content

Commit bc08f69

Browse files
Merge pull request from GHSA-pghf-347x-c2gj
* Changes required to support v1.11.x branch Pin requirements to work with python2.7. Style corrections to get tox to pass. Pinning requirements for tox. Setup github test action for v1.X branch Convert to current tox file. Update requirements. Django requires session middleware now. Remove python3.4 from github actions. It's not supported. Remove docs from tox. Support PostgresJSON test. Format code according to black and isort. 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. Force the values to a string for signing. Remove hashing mechanism from forms. * Bump to version 1.11.1
1 parent c201ce3 commit bc08f69

26 files changed

+827
-287
lines changed

.github/workflows/test.yml

+210
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
name: Test
2+
3+
on: [push, pull_request]
4+
5+
jobs:
6+
mysql:
7+
runs-on: ubuntu-latest
8+
strategy:
9+
fail-fast: false
10+
max-parallel: 5
11+
matrix:
12+
python-version: ['2.7', '3.5', '3.6', '3.7']
13+
14+
services:
15+
mariadb:
16+
image: mariadb:10.3
17+
env:
18+
MYSQL_ROOT_PASSWORD: debug_toolbar
19+
options: >-
20+
--health-cmd "mysqladmin ping"
21+
--health-interval 10s
22+
--health-timeout 5s
23+
--health-retries 5
24+
ports:
25+
- 3306:3306
26+
27+
steps:
28+
- uses: actions/checkout@v2
29+
30+
- name: Set up Python ${{ matrix.python-version }}
31+
uses: actions/setup-python@v2
32+
with:
33+
python-version: ${{ matrix.python-version }}
34+
35+
- name: Get pip cache dir
36+
id: pip-cache
37+
run: |
38+
echo "::set-output name=dir::$(pip cache dir)"
39+
40+
- name: Cache
41+
uses: actions/cache@v2
42+
with:
43+
path: ${{ steps.pip-cache.outputs.dir }}
44+
key:
45+
${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.cfg') }}-${{ hashFiles('**/tox.ini') }}
46+
restore-keys: |
47+
${{ matrix.python-version }}-v1-
48+
49+
- name: Install dependencies
50+
run: |
51+
python -m pip install --upgrade pip
52+
python -m pip install --upgrade tox tox-gh-actions
53+
54+
- name: Test with tox
55+
run: tox
56+
env:
57+
DB_BACKEND: mysql
58+
DB_USER: root
59+
DB_PASSWORD: debug_toolbar
60+
DB_HOST: 127.0.0.1
61+
DB_PORT: 3306
62+
63+
- name: Upload coverage
64+
uses: codecov/codecov-action@v1
65+
with:
66+
name: Python ${{ matrix.python-version }}
67+
68+
postgres:
69+
runs-on: ubuntu-latest
70+
strategy:
71+
fail-fast: false
72+
max-parallel: 5
73+
matrix:
74+
python-version: ['2.7', '3.5', '3.6', '3.7']
75+
76+
services:
77+
postgres:
78+
image: 'postgres:9.5'
79+
env:
80+
POSTGRES_DB: debug_toolbar
81+
POSTGRES_USER: debug_toolbar
82+
POSTGRES_PASSWORD: debug_toolbar
83+
ports:
84+
- 5432:5432
85+
options: >-
86+
--health-cmd pg_isready
87+
--health-interval 10s
88+
--health-timeout 5s
89+
--health-retries 5
90+
91+
steps:
92+
- uses: actions/checkout@v2
93+
94+
- name: Set up Python ${{ matrix.python-version }}
95+
uses: actions/setup-python@v2
96+
with:
97+
python-version: ${{ matrix.python-version }}
98+
99+
- name: Get pip cache dir
100+
id: pip-cache
101+
run: |
102+
echo "::set-output name=dir::$(pip cache dir)"
103+
104+
- name: Cache
105+
uses: actions/cache@v2
106+
with:
107+
path: ${{ steps.pip-cache.outputs.dir }}
108+
key:
109+
${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.cfg') }}-${{ hashFiles('**/tox.ini') }}
110+
restore-keys: |
111+
${{ matrix.python-version }}-v1-
112+
113+
- name: Install dependencies
114+
run: |
115+
python -m pip install --upgrade pip
116+
python -m pip install --upgrade tox tox-gh-actions
117+
118+
- name: Test with tox
119+
run: tox
120+
env:
121+
DB_BACKEND: postgresql
122+
DB_HOST: localhost
123+
DB_PORT: 5432
124+
125+
- name: Upload coverage
126+
uses: codecov/codecov-action@v1
127+
with:
128+
name: Python ${{ matrix.python-version }}
129+
130+
sqlite:
131+
runs-on: ubuntu-latest
132+
strategy:
133+
fail-fast: false
134+
max-parallel: 5
135+
matrix:
136+
python-version: ['2.7', '3.5', '3.6', '3.7']
137+
138+
steps:
139+
- uses: actions/checkout@v2
140+
141+
- name: Set up Python ${{ matrix.python-version }}
142+
uses: actions/setup-python@v2
143+
with:
144+
python-version: ${{ matrix.python-version }}
145+
146+
- name: Get pip cache dir
147+
id: pip-cache
148+
run: |
149+
echo "::set-output name=dir::$(pip cache dir)"
150+
151+
- name: Cache
152+
uses: actions/cache@v2
153+
with:
154+
path: ${{ steps.pip-cache.outputs.dir }}
155+
key:
156+
${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.cfg') }}-${{ hashFiles('**/tox.ini') }}
157+
restore-keys: |
158+
${{ matrix.python-version }}-v1-
159+
160+
- name: Install dependencies
161+
run: |
162+
python -m pip install --upgrade pip
163+
python -m pip install --upgrade tox tox-gh-actions
164+
165+
- name: Test with tox
166+
run: tox
167+
env:
168+
DB_BACKEND: sqlite3
169+
DB_NAME: ":memory:"
170+
171+
- name: Upload coverage
172+
uses: codecov/codecov-action@v1
173+
with:
174+
name: Python ${{ matrix.python-version }}
175+
176+
lint:
177+
runs-on: ubuntu-latest
178+
strategy:
179+
fail-fast: false
180+
181+
steps:
182+
- uses: actions/checkout@v2
183+
184+
- name: Set up Python ${{ matrix.python-version }}
185+
uses: actions/setup-python@v2
186+
with:
187+
python-version: 3.7
188+
189+
- name: Get pip cache dir
190+
id: pip-cache
191+
run: |
192+
echo "::set-output name=dir::$(pip cache dir)"
193+
194+
- name: Cache
195+
uses: actions/cache@v2
196+
with:
197+
path: ${{ steps.pip-cache.outputs.dir }}
198+
key:
199+
${{ matrix.python-version }}-v1-${{ hashFiles('**/setup.cfg') }}-${{ hashFiles('**/tox.ini') }}
200+
restore-keys: |
201+
${{ matrix.python-version }}-v1-
202+
203+
- name: Install dependencies
204+
run: |
205+
python -m pip install --upgrade pip
206+
python -m pip install --upgrade tox
207+
208+
- name: Test with tox
209+
run: tox -e style,readme
210+

.travis.yml

-59
This file was deleted.

Makefile

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
.PHONY: flake8 example test coverage translatable_strings update_translations
22

33
style:
4-
isort -rc debug_toolbar example tests
5-
black debug_toolbar example tests setup.py
6-
flake8 debug_toolbar example tests
4+
isort .
5+
black --target-version=py27 .
6+
flake8
77

88
style_check:
9-
isort -rc -c debug_toolbar example tests
10-
black --check debug_toolbar example tests setup.py
9+
isort -c .
10+
black --target-version=py27 --check .
11+
flake8
1112

1213
flake8:
1314
flake8 debug_toolbar example tests

README.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Here's a screenshot of the toolbar in action:
3131
In addition to the built-in panels, a number of third-party panels are
3232
contributed by the community.
3333

34-
The current version of the Debug Toolbar is 1.11. It works on Django ≥ 1.11.
34+
The current version of the Debug Toolbar is 1.11.1. It works on Django ≥ 1.11.
3535

3636
Documentation, including installation and configuration instructions, is
3737
available at https://django-debug-toolbar.readthedocs.io/.

debug_toolbar/decorators.py

+19-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import functools
22

3-
from django.http import Http404
3+
from django.http import Http404, HttpResponseBadRequest
44

55

66
def require_show_toolbar(view):
@@ -15,3 +15,21 @@ def inner(request, *args, **kwargs):
1515
return view(request, *args, **kwargs)
1616

1717
return inner
18+
19+
20+
def signed_data_view(view):
21+
"""Decorator that handles unpacking a signed data form"""
22+
23+
@functools.wraps(view)
24+
def inner(request, *args, **kwargs):
25+
from debug_toolbar.forms import SignedDataForm
26+
27+
data = request.GET if request.method == "GET" else request.POST
28+
signed_form = SignedDataForm(data)
29+
if signed_form.is_valid():
30+
return view(
31+
request, *args, verified_data=signed_form.verified_data(), **kwargs
32+
)
33+
return HttpResponseBadRequest("Invalid signature")
34+
35+
return inner

debug_toolbar/forms.py

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import json
2+
from collections import OrderedDict
3+
4+
from django import forms
5+
from django.core import signing
6+
from django.core.exceptions import ValidationError
7+
from django.utils.encoding import force_str
8+
9+
10+
class SignedDataForm(forms.Form):
11+
"""Helper form that wraps a form to validate its contents on post.
12+
13+
class PanelForm(forms.Form):
14+
# fields
15+
16+
On render:
17+
form = SignedDataForm(initial=PanelForm(initial=data).initial)
18+
19+
On POST:
20+
signed_form = SignedDataForm(request.POST)
21+
if signed_form.is_valid():
22+
panel_form = PanelForm(signed_form.verified_data)
23+
if panel_form.is_valid():
24+
# Success
25+
Or wrap the FBV with ``debug_toolbar.decorators.signed_data_view``
26+
"""
27+
28+
salt = "django_debug_toolbar"
29+
signed = forms.CharField(required=True, widget=forms.HiddenInput)
30+
31+
def __init__(self, *args, **kwargs):
32+
initial = kwargs.pop("initial", None)
33+
if initial:
34+
initial = {"signed": self.sign(initial)}
35+
super(SignedDataForm, self).__init__(*args, initial=initial, **kwargs)
36+
37+
def clean_signed(self):
38+
try:
39+
verified = json.loads(
40+
signing.Signer(salt=self.salt).unsign(self.cleaned_data["signed"])
41+
)
42+
return verified
43+
except signing.BadSignature:
44+
raise ValidationError("Bad signature")
45+
46+
def verified_data(self):
47+
return self.is_valid() and self.cleaned_data["signed"]
48+
49+
@classmethod
50+
def sign(cls, data):
51+
# Sort the data by the keys to create a fixed ordering.
52+
items = sorted(data.items(), key=lambda item: item[0])
53+
return signing.Signer(salt=cls.salt).sign(
54+
json.dumps(OrderedDict((key, force_str(value)) for key, value in items))
55+
)

0 commit comments

Comments
 (0)