views: Drop use of private Django utility

We are currently using django.utils.http.is_safe_url which is a private method
and may break API anytime. Replace it with similar but limited implementation.

Tests:

- Unit tests.

- Dismiss a notification and the redirect to the same page happens properly.

- Logout, goto to home page or login page. Change the language and it will
redirect back to home page or login page appropriately.

Signed-off-by: Sunil Mohan Adapa <sunil@medhas.org>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
Sunil Mohan Adapa 2020-06-25 15:52:07 -07:00 committed by James Valleroy
parent 5a126e62a8
commit 6f30e12cd7
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
2 changed files with 57 additions and 2 deletions

View File

@ -0,0 +1,31 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""
Tests for common FreedomBox views.
"""
import pytest
from plinth.views import is_safe_url
@pytest.mark.parametrize('url', [
'/plinth/login/',
'/',
'safe',
])
def test_is_safe_url_valid_url(url):
"""Test valid URLs for safe URL checks."""
assert is_safe_url(url)
@pytest.mark.parametrize('url', [
'',
None,
'\\plinth',
'///plinth',
'https://example.com/plinth/login/',
'https:///plinth/login',
])
def test_is_safe_url_invalid_url(url):
"""Test invalid URLs for safe URL checks."""
assert not is_safe_url(url)

View File

@ -4,13 +4,13 @@ Main FreedomBox views.
"""
import time
import urllib.parse
from django.contrib import messages
from django.core.exceptions import ImproperlyConfigured
from django.http import Http404, HttpResponseBadRequest, HttpResponseRedirect
from django.template.response import TemplateResponse
from django.urls import reverse
from django.utils.http import is_safe_url
from django.utils.translation import ugettext as _
from django.views.generic import TemplateView
from django.views.generic.edit import FormView
@ -26,11 +26,35 @@ from . import forms, frontpage
REDIRECT_FIELD_NAME = 'next'
def is_safe_url(url):
"""Check if the URL is safe to redirect to.
Based on Django internal utility.
"""
if url is not None:
url = url.strip()
if not url:
return False
if '\\' in url or url.startswith('///'):
return False
result = urllib.parse.urlparse(url)
# Only accept URLs to the same site and scheme.
if result.scheme or result.netloc:
return False
return True
def _get_redirect_url_from_param(request):
"""Return the redirect URL from 'next' GET/POST param."""
redirect_to = request.GET.get(REDIRECT_FIELD_NAME, '')
redirect_to = request.POST.get(REDIRECT_FIELD_NAME, redirect_to)
if is_safe_url(url=redirect_to, allowed_hosts={request.get_host()}):
if is_safe_url(redirect_to):
return redirect_to
return reverse('index')