Skip to content

Commit b6239c9

Browse files
committed
[fix] Replace regex URLs with custom Path Converters #682
Replaced legacy regex 're_path' with strict Django 'path' converters and updated tests to manually construct invalid URLs for 404 testing. Fixes #682
1 parent d3fbb24 commit b6239c9

6 files changed

Lines changed: 46 additions & 68 deletions

File tree

openwisp_controller/config/admin.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
from django.shortcuts import get_object_or_404
2121
from django.template.loader import get_template
2222
from django.template.response import TemplateResponse
23-
from django.urls import path, register_converter, reverse
23+
from django.urls import path, reverse
2424
from django.utils.html import format_html, mark_safe
2525
from django.utils.translation import gettext_lazy as _
2626
from django.utils.translation import ngettext_lazy
@@ -42,20 +42,14 @@
4242
from ..admin import MultitenantAdminMixin
4343
from . import settings as app_settings
4444
from .base.vpn import AbstractVpn
45-
from .converters import UUIDAnyConverter, UUIDAnyOrFKConverter
4645
from .exportable import DeviceResource
4746
from .filters import DeviceGroupFilter, GroupFilter, TemplatesFilter
4847
from .utils import send_file
4948
from .widgets import DeviceGroupJsonSchemaWidget, JsonSchemaWidget
5049

51-
register_converter(UUIDAnyConverter, "uuid_any")
52-
register_converter(UUIDAnyOrFKConverter, "uuid_or_fk")
53-
5450
logger = logging.getLogger(__name__)
5551
prefix = "config/"
56-
uuid_regex = (
57-
r"[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}"
58-
)
52+
5953
Config = load_model("config", "Config")
6054
Device = load_model("config", "Device")
6155
DeviceGroup = load_model("config", "DeviceGroup")

openwisp_controller/config/apps.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@ def register_path_converters(self):
6161
converters = get_converters()
6262
if "uuid_any" not in converters:
6363
register_converter(UUIDAnyConverter, "uuid_any")
64-
if "uuid_any_or_fk" not in converters:
65-
register_converter(UUIDAnyOrFKConverter, "uuid_any_or_fk")
64+
if "uuid_or_fk" not in converters:
65+
register_converter(UUIDAnyOrFKConverter, "uuid_or_fk")
6666

6767
def __setmodels__(self):
6868
self.device_model = load_model("config", "Device")

openwisp_controller/config/tests/pytest.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,14 @@
55
from channels.security.websocket import AllowedHostsOriginValidator
66
from channels.testing import WebsocketCommunicator
77
from django.contrib.auth.models import Permission
8-
from django.urls import re_path
8+
from django.urls import path
99
from swapper import load_model
1010

1111
from ..base.channels_consumer import BaseDeviceConsumer
1212
from .utils import CreateDeviceMixin
1313

1414
Device = load_model("config", "Device")
1515

16-
uuid_regex = (
17-
r"[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}"
18-
)
19-
2016

2117
@pytest.mark.asyncio
2218
@pytest.mark.django_db(transaction=True)
@@ -28,8 +24,8 @@ class TestDeviceConsumer(CreateDeviceMixin):
2824
AuthMiddlewareStack(
2925
URLRouter(
3026
[
31-
re_path(
32-
rf"^ws/controller/device/(?P<pk>{uuid_regex})/$",
27+
path(
28+
"ws/controller/device/<uuid_any:pk>/",
3329
BaseDeviceConsumer.as_asgi(),
3430
)
3531
]

openwisp_controller/config/tests/test_controller.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,8 @@ def test_device_checksum_requested_signal_is_emitted(self):
272272

273273
def test_device_checksum_bad_uuid(self):
274274
d = self._create_device_config()
275-
pk = "{}-wrong".format(d.pk)
276-
valid = reverse("controller:device_checksum", args=[pk])
277-
bad = valid + "junk/"
275+
valid = reverse("controller:device_checksum", args=[d.pk])
276+
bad = valid.replace(str(d.pk), f"{d.pk}-wrong")
278277
resp = self.client.get(bad, {"key": d.key})
279278
self.assertEqual(resp.status_code, 404)
280279

@@ -338,9 +337,9 @@ def test_deactivated_device_download_config(self):
338337

339338
def test_device_download_config_bad_uuid(self):
340339
d = self._create_device_config()
341-
pk = "{}-wrong".format(d.pk)
342-
bad_path = f"/controller/device/download-config/{pk}/"
343-
response = self.client.get(bad_path, {"key": d.key})
340+
valid = reverse("controller:device_download_config", args=[d.pk])
341+
bad = valid.replace(str(d.pk), f"{d.pk}-wrong")
342+
response = self.client.get(bad, {"key": d.key})
344343
self.assertEqual(response.status_code, 404)
345344

346345
def test_vpn_checksum_requested_signal_is_emitted(self):
@@ -397,9 +396,9 @@ def test_vpn_checksum(self):
397396

398397
def test_vpn_checksum_bad_uuid(self):
399398
v = self._create_vpn()
400-
pk = "{}-wrong".format(v.pk)
401-
bad_path = f"/controller/vpn/checksum/{pk}/"
402-
response = self.client.get(bad_path, {"key": v.key})
399+
valid = reverse("controller:vpn_checksum", args=[v.pk])
400+
bad = valid.replace(str(v.pk), f"{v.pk}-wrong")
401+
response = self.client.get(bad, {"key": v.key})
403402
self.assertEqual(response.status_code, 404)
404403

405404
@capture_any_output()
@@ -513,9 +512,9 @@ def test_vpn_download_config(self):
513512

514513
def test_vpn_download_config_bad_uuid(self):
515514
v = self._create_vpn()
516-
pk = "{}-wrong".format(v.pk)
517-
bad_path = f"/controller/vpn/download-config/{pk}/"
518-
response = self.client.get(bad_path, {"key": v.key})
515+
valid_url = reverse("controller:vpn_download_config", args=[v.pk])
516+
bad_url = valid_url.replace(str(v.pk), f"{v.pk}-wrong")
517+
response = self.client.get(bad_url, {"key": v.key})
519518
self.assertEqual(response.status_code, 404)
520519

521520
@capture_any_output()
@@ -970,9 +969,9 @@ def test_deactivated_device_report_status(self):
970969

971970
def test_device_report_status_bad_uuid(self):
972971
d = self._create_device_config()
973-
pk = "{}-wrong".format(d.pk)
974-
bad_path = f"/controller/device/report-status/{pk}/"
975-
response = self.client.post(bad_path, {"key": d.key})
972+
valid_url = reverse("controller:device_report_status", args=[d.pk])
973+
bad_url = valid_url.replace(str(d.pk), f"{d.pk}-wrong")
974+
response = self.client.post(bad_url, {"key": d.key})
976975
self.assertEqual(response.status_code, 404)
977976

978977
@capture_any_output()
@@ -1080,15 +1079,15 @@ def test_deactivated_device_update_info(self):
10801079

10811080
def test_device_update_info_bad_uuid(self):
10821081
d = self._create_device_config()
1083-
pk = "{}-wrong".format(d.pk)
10841082
params = {
10851083
"key": d.key,
10861084
"model": "TP-Link TL-WDR4300 v2",
10871085
"os": "OpenWrt 18.06-SNAPSHOT r7312-e60be11330",
10881086
"system": "Atheros AR9344 rev 3",
10891087
}
1090-
bad_path = f"/controller/device/update-info/{pk}/"
1091-
response = self.client.post(bad_path, params)
1088+
valid_url = reverse("controller:device_update_info", args=[d.pk])
1089+
bad_url = valid_url.replace(str(d.pk), f"{d.pk}-wrong")
1090+
response = self.client.post(bad_url, params)
10921091
self.assertEqual(response.status_code, 404)
10931092

10941093
def test_device_update_info_400(self):

openwisp_controller/config/urls.py

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
1-
from django.urls import path, register_converter
1+
from django.urls import path
22

3-
from .converters import UUIDAnyConverter, UUIDAnyOrFKConverter
43
from .views import schema
54

6-
register_converter(UUIDAnyConverter, "uuid_any")
7-
register_converter(UUIDAnyOrFKConverter, "uuid_or_fk")
8-
9-
10-
register_converter(UUIDAnyConverter, "uuid_any")
11-
register_converter(UUIDAnyOrFKConverter, "uuid_or_fk")
12-
135
app_name = "openwisp_controller"
146
urlpatterns = [path("config/schema.json", schema, name="schema")]

openwisp_controller/config/utils.py

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,12 @@
66
from django.db.models import Q
77
from django.http import Http404, HttpResponse
88
from django.shortcuts import get_object_or_404 as base_get_object_or_404
9-
from django.urls import path, re_path
9+
from django.urls import path
1010
from django.utils.translation import gettext_lazy as _
1111
from openwisp_notifications.signals import notify
1212
from openwisp_notifications.utils import _get_object_link
1313

1414
logger = logging.getLogger(__name__)
15-
uuid_regex = (
16-
r"[0-9a-fA-F]{8}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{4}-?[0-9a-fA-F]{12}"
17-
)
1815

1916

2017
def get_object_or_404(model, **kwargs):
@@ -123,23 +120,23 @@ def get_controller_urls(views_module):
123120
used by third party apps to reduce boilerplate
124121
"""
125122
urls = [
126-
re_path(
127-
rf"controller/device/checksum/(?P<pk>{uuid_regex})/$",
123+
path(
124+
"controller/device/checksum/<uuid_any:pk>/",
128125
views_module.device_checksum,
129126
name="device_checksum",
130127
),
131-
re_path(
132-
rf"controller/device/download-config/(?P<pk>{uuid_regex})/$",
128+
path(
129+
"controller/device/download-config/<uuid_any:pk>/",
133130
views_module.device_download_config,
134131
name="device_download_config",
135132
),
136-
re_path(
137-
rf"controller/device/update-info/(?P<pk>{uuid_regex})/$",
133+
path(
134+
"controller/device/update-info/<uuid_any:pk>/",
138135
views_module.device_update_info,
139136
name="device_update_info",
140137
),
141-
re_path(
142-
rf"controller/device/report-status/(?P<pk>{uuid_regex})/$",
138+
path(
139+
"controller/device/report-status/<uuid_any:pk>/",
143140
views_module.device_report_status,
144141
name="device_report_status",
145142
),
@@ -148,34 +145,34 @@ def get_controller_urls(views_module):
148145
views_module.device_register,
149146
name="device_register",
150147
),
151-
re_path(
152-
rf"controller/vpn/checksum/(?P<pk>{uuid_regex})/$",
148+
path(
149+
"controller/vpn/checksum/<uuid_any:pk>/",
153150
views_module.vpn_checksum,
154151
name="vpn_checksum",
155152
),
156-
re_path(
157-
rf"controller/vpn/download-config/(?P<pk>{uuid_regex})/$",
153+
path(
154+
"controller/vpn/download-config/<uuid_any:pk>/",
158155
views_module.vpn_download_config,
159156
name="vpn_download_config",
160157
),
161158
# legacy URLs
162-
re_path(
163-
rf"controller/checksum/(?P<pk>{uuid_regex})/$",
159+
path(
160+
"controller/checksum/<uuid_any:pk>/",
164161
views_module.device_checksum,
165162
name="checksum_legacy",
166163
),
167-
re_path(
168-
rf"controller/download-config/(?P<pk>{uuid_regex})/$",
164+
path(
165+
"controller/download-config/<uuid_any:pk>/",
169166
views_module.device_download_config,
170167
name="download_config_legacy",
171168
),
172-
re_path(
173-
rf"controller/update-info/(?P<pk>{uuid_regex})/$",
169+
path(
170+
"controller/update-info/<uuid_any:pk>/",
174171
views_module.device_update_info,
175172
name="update_info_legacy",
176173
),
177-
re_path(
178-
rf"controller/report-status/(?P<pk>{uuid_regex})/$",
174+
path(
175+
"controller/report-status/<uuid_any:pk>/",
179176
views_module.device_report_status,
180177
name="report_status_legacy",
181178
),

0 commit comments

Comments
 (0)