From 0f1abd34982108c70caae513619a5d911ea9fe73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C4=93teris=20Caune?= Date: Mon, 14 Dec 2020 19:08:36 +0200 Subject: [PATCH] Add tighter parameter checks in hc.front.views.serve_doc --- CHANGELOG.md | 6 ++++++ hc/front/tests/test_serve_doc.py | 31 +++++++++++++++++++++++++++++++ hc/front/views.py | 6 ++++++ 3 files changed, 43 insertions(+) create mode 100644 hc/front/tests/test_serve_doc.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 3de2b359..44bb9aaa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Changelog All notable changes to this project will be documented in this file. +## v1.19.0 - Unreleased + +## Improvements +- Add tighter parameter checks in hc.front.views.serve_doc + + ## v1.18.0 - 2020-12-09 ## Improvements diff --git a/hc/front/tests/test_serve_doc.py b/hc/front/tests/test_serve_doc.py new file mode 100644 index 00000000..88aaf83b --- /dev/null +++ b/hc/front/tests/test_serve_doc.py @@ -0,0 +1,31 @@ +from unittest.mock import patch +from django.test import TestCase + + +class ServeDocTestCase(TestCase): + def test_it_serves_introduction(self): + r = self.client.get("/docs/") + self.assertEqual(r.status_code, 200) + + self.assertContains(r, "keeps silent") + + def test_it_serves_subpage(self): + r = self.client.get("/docs/reliability_tips/") + self.assertEqual(r.status_code, 200) + + self.assertContains(r, "Pinging Reliability Tips") + + def test_it_handles_bad_url(self): + r = self.client.get("/docs/does_not_exist/") + self.assertEqual(r.status_code, 404) + + @patch("hc.front.views.os.path.exists") + def test_it_rejects_bad_characters(self, mock_exists): + r = self.client.get("/docs/NAUGHTY/") + self.assertEqual(r.status_code, 404) + + # URL dispatcher's slug filter lets the uppercase letters through, + # but the view should still reject them, before any filesystem + # operations + + self.assertFalse(mock_exists.called) diff --git a/hc/front/views.py b/hc/front/views.py index ea1b0add..f4ece3c6 100644 --- a/hc/front/views.py +++ b/hc/front/views.py @@ -1,6 +1,7 @@ from datetime import datetime, timedelta as td import json import os +import re from secrets import token_urlsafe from urllib.parse import urlencode @@ -314,6 +315,11 @@ def dashboard(request): def serve_doc(request, doc="introduction"): + # Filenames in /templates/docs/ consist of lowercase letters and underscores, + # -- make sure we don't accept anything else + if not re.match(r"^[a-z_]+$", doc): + raise Http404("not found") + path = os.path.join(settings.BASE_DIR, "templates/docs", doc + ".html") if not os.path.exists(path): raise Http404("not found")