Projet

Général

Profil

0001-misc-add-rate-limiting-to-tracking-code-URL-35386.patch

Frédéric Péters, 13 août 2019 14:07

Télécharger (6,92 ko)

Voir les différences:

Subject: [PATCH] misc: add rate limiting to tracking code URL (#35386)

 debian/control           |  1 +
 setup.py                 |  1 +
 tests/conftest.py        |  9 +++++++++
 tests/test_form_pages.py | 27 +++++++++++++++++----------
 wcs/forms/root.py        | 10 ++++++++++
 5 files changed, 38 insertions(+), 10 deletions(-)
debian/control
15 15
    python-hobo,
16 16
    graphviz,
17 17
    python-django-ckeditor,
18
    python-django-ratelimit,
18 19
    python-feedparser,
19 20
    python-imaging,
20 21
    python-pyproj,
setup.py
109 109
        install_requires=[
110 110
            'gadjo>=0.53',
111 111
            'django-ckeditor<=4.5.3',
112
            'django-ratelimit<3',
112 113
            'XStatic-Leaflet',
113 114
            'pyproj',
114 115
        ],
tests/conftest.py
68 68
def http_requests():
69 69
    with HttpRequestsMocking() as http_requests:
70 70
        yield http_requests
71

  
72

  
73
@pytest.fixture
74
def nocache(settings):
75
    settings.CACHES = {
76
        'default': {
77
            'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
78
        }
79
    }
tests/test_form_pages.py
55 55
        t1, t2 = z1.read(name), z2.read(name)
56 56
        assert t1 == t2, 'file "%s" differs' % name
57 57

  
58

  
59 58
def pytest_generate_tests(metafunc):
60 59
    if 'pub' in metafunc.fixturenames:
61 60
        metafunc.parametrize('pub', ['pickle', 'sql', 'pickle-templates', 'pickle-lazy'], indirect=True)
......
1311 1310
            break
1312 1311
    return tracking_code
1313 1312

  
1314
def test_form_tracking_code(pub):
1313
def test_form_tracking_code(pub, nocache):
1315 1314
    formdef = create_formdef()
1316 1315
    formdef.fields = [fields.StringField(id='0', label='string')]
1317 1316
    formdef.enable_tracking_codes = True
......
1412 1411
    assert resp.location == 'http://example.net/test/%s' % formdata_id
1413 1412
    resp = resp.follow()
1414 1413

  
1414
def test_form_tracking_code_rate_limit(pub):
1415
    # three errors
1416
    get_app(pub).get('/code/ABC/load', status=404)
1417
    get_app(pub).get('/code/ABC/load', status=404)
1418
    get_app(pub).get('/code/ABC/load', status=404)
1419
    # and out
1420
    get_app(pub).get('/code/ABC/load', status=403)
1421
    get_app(pub).get('/code/ABC/load', status=403)
1415 1422

  
1416
def test_form_tracking_code_as_user(pub):
1423
def test_form_tracking_code_as_user(pub, nocache):
1417 1424
    user = create_user(pub)
1418 1425
    formdef = create_formdef()
1419 1426
    formdef.fields = [fields.StringField(id='0', label='string')]
......
1493 1500
    resp = app.get('/code/%s/load' % tracking_code,
1494 1501
            headers={'User-agent': 'Googlebot'}, status=403)
1495 1502

  
1496
def test_form_empty_tracking_code(pub):
1503
def test_form_empty_tracking_code(pub, nocache):
1497 1504
    formdef = create_formdef()
1498 1505
    formdef.fields = [fields.StringField(id='0', label='string')]
1499 1506
    formdef.enable_tracking_codes = True
......
1512 1519
    assert resp.location == 'http://example.net/code/%s/load' % tracking_code
1513 1520
    resp = resp.follow(status=404)
1514 1521

  
1515
def test_form_tracking_code_email(pub, emails):
1522
def test_form_tracking_code_email(pub, emails, nocache):
1516 1523
    formdef = create_formdef()
1517 1524
    formdef.data_class().wipe()
1518 1525
    formdef.fields = [fields.StringField(id='0', label='string'),
......
1541 1548
    resp = resp.follow()
1542 1549
    assert resp.forms[1]['f0'].value == 'barfoo'
1543 1550

  
1544
def test_form_tracking_code_remove_draft(pub):
1551
def test_form_tracking_code_remove_draft(pub, nocache):
1545 1552
    formdef = create_formdef()
1546 1553
    formdef.fields = [fields.StringField(id='0', label='string')]
1547 1554
    formdef.enable_tracking_codes = True
......
1587 1594
    assert resp.location == 'http://example.net/'
1588 1595
    assert formdef.data_class().count() == 0
1589 1596

  
1590
def test_form_tracking_code_remove_empty_draft(pub):
1597
def test_form_tracking_code_remove_empty_draft(pub, nocache):
1591 1598
    formdef = create_formdef()
1592 1599
    formdef.fields = [fields.StringField(id='0', label='string')]
1593 1600
    formdef.enable_tracking_codes = True
......
1635 1642
    assert resp.location == 'http://example.net/'
1636 1643
    assert formdef.data_class().count() == 0
1637 1644

  
1638
def test_form_discard_draft(pub):
1645
def test_form_discard_draft(pub, nocache):
1639 1646
    user = create_user(pub)
1640 1647

  
1641 1648
    formdef = create_formdef()
......
1733 1740
    resp = resp.forms[1].submit('cancel')
1734 1741
    assert [x.status for x in formdef.data_class().select()] == ['draft']
1735 1742

  
1736
def test_form_invalid_tracking_code(pub):
1743
def test_form_invalid_tracking_code(pub, nocache):
1737 1744
    formdef = create_formdef()
1738 1745
    formdef.fields = [fields.StringField(id='0', label='string')]
1739 1746
    formdef.enable_tracking_codes = True
......
1785 1792
    assert resp.location == 'http://example.net/code/%s/load' % code.id
1786 1793
    resp = resp.follow(status=404)
1787 1794

  
1788
def test_form_tracking_code_as_variable(pub):
1795
def test_form_tracking_code_as_variable(pub, nocache):
1789 1796
    formdef = create_formdef()
1790 1797
    formdef.fields = [fields.PageField(id='0', label='1st page', type='page'),
1791 1798
            fields.StringField(id='1', label='string'),
wcs/forms/root.py
29 29
from django.utils.six import StringIO
30 30
from django.utils.safestring import mark_safe
31 31

  
32
import ratelimit.utils
33

  
32 34
from quixote import (get_publisher, get_request, get_response, get_session,
33 35
        get_session_manager, redirect)
34 36
from quixote.directory import Directory, AccessControlled
......
148 150
        return r.getvalue()
149 151

  
150 152
    def load(self):
153
        ratelimited = ratelimit.utils.is_ratelimited(
154
                request=get_request().django_request,
155
                group='trackingcode',
156
                key='ip',
157
                rate='3/s',
158
                increment=True)
159
        if ratelimited:
160
            raise errors.AccessForbiddenError()
151 161
        try:
152 162
            tracking_code = get_publisher().tracking_code_class.get(self.code)
153 163
            if tracking_code.formdata_id is None:
154
-