Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions exercise/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from course.models import CourseModule, StudentModuleGoal, SubmissionTag
from course.viewbase import CourseInstanceBaseView, CourseModuleBaseView, EnrollableViewMixin
from exercise.forms import StudentModuleGoalForm
from lib.helpers import query_dict_to_list_of_tuples, safe_file_name, is_ajax
from lib.helpers import get_redirect_url_from_referer, query_dict_to_list_of_tuples, safe_file_name, is_ajax
from lib.remote_page import RemotePageNotFound, request_for_response
from lib.viewbase import BaseFormView, BaseRedirectMixin, BaseView
from userprofile.models import UserProfile
Expand Down Expand Up @@ -62,7 +62,7 @@
SubmissionTagging.objects.create(submission=submission, tag=subtag)

# Redirect back to the previous page
return redirect(request.headers.get('referer', '/'))
return redirect(get_redirect_url_from_referer(request))

Check warning

Code scanning / CodeQL

URL redirection from remote source Medium

Untrusted URL redirection depends on a
user-provided value
.


class SubmissionTaggingRemoveView(CourseInstanceBaseView):
Expand All @@ -80,7 +80,7 @@
SubmissionTagging.objects.filter(submission=submission, tag=subtag).delete()

# Redirect back to the previous page
return redirect(request.headers.get('referer', '/'))
return redirect(get_redirect_url_from_referer(request))

Check warning

Code scanning / CodeQL

URL redirection from remote source Medium

Untrusted URL redirection depends on a
user-provided value
.


class ExerciseInfoView(ExerciseBaseView):
Expand Down
20 changes: 20 additions & 0 deletions lib/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from django.conf import settings
from django.utils.crypto import get_random_string as django_get_random_string
from django.utils.deprecation import RemovedInNextVersionWarning
from django.utils.http import url_has_allowed_host_and_scheme
from django.utils.translation import get_language


Expand Down Expand Up @@ -146,6 +147,25 @@ def build_aplus_url(url: str, user_url: bool = False) -> str:
return urlunparse(parsed)


def get_redirect_url_from_referer(request):
referer = request.headers.get('referer', '/')
if url_has_allowed_host_and_scheme(url=referer, allowed_hosts={request.get_host()}):
parsed = urlparse(referer)
path = parsed.path
if parsed.query:
path += '?' + parsed.query
if parsed.fragment:
path += '#' + parsed.fragment

if path.startswith('//'):
referer = '/'
else:
referer = path
else:
referer = '/'
return referer


FILENAME_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._-0123456789"

def safe_file_name(name):
Expand Down
4 changes: 2 additions & 2 deletions userprofile/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

from authorization.permissions import ACCESS
from course.models import CourseInstance
from lib.helpers import settings_text, remove_query_param_from_url, is_ajax
from lib.helpers import get_redirect_url_from_referer, settings_text, remove_query_param_from_url, is_ajax
from lib.viewbase import BaseView
from userprofile.models import UserProfile
from .viewbase import UserProfileView
Expand Down Expand Up @@ -368,4 +368,4 @@
def get(self, request: HttpRequest) -> HttpResponse:
pseudonymize = request.session.get("pseudonymize", False)
request.session["pseudonymize"] = not pseudonymize
return HttpResponseRedirect(request.headers.get("referer", "/"))
return HttpResponseRedirect(get_redirect_url_from_referer(request))

Check warning

Code scanning / CodeQL

URL redirection from remote source Medium

Untrusted URL redirection depends on a
user-provided value
.
Loading