From 8cebcedfa2aa2f8e7508d5ebec37595bfe7bd156 Mon Sep 17 00:00:00 2001 From: Nguyen Viet Dung <29406816+magnified103@users.noreply.github.com> Date: Fri, 26 Jul 2024 13:06:01 +0700 Subject: [PATCH] Protect stateful admin endpoints against CSRF --- judge/admin/contest.py | 7 ++++++- judge/admin/runtime.py | 5 +++++ judge/admin/submission.py | 3 +++ templates/admin/base_site.html | 15 +++++++++++++++ templates/admin/judge/contest/change_form.html | 2 +- templates/admin/judge/contest/change_list.html | 2 +- templates/admin/judge/judge/change_form.html | 8 ++++---- templates/admin/judge/submission/change_form.html | 2 +- 8 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 templates/admin/base_site.html diff --git a/judge/admin/contest.py b/judge/admin/contest.py index f6e45b2f05..0d8c02551c 100644 --- a/judge/admin/contest.py +++ b/judge/admin/contest.py @@ -8,8 +8,10 @@ from django.shortcuts import get_object_or_404 from django.urls import path, reverse, reverse_lazy from django.utils import timezone +from django.utils.decorators import method_decorator from django.utils.html import format_html from django.utils.translation import gettext_lazy as _, ngettext +from django.views.decorators.http import require_POST from reversion.admin import VersionAdmin from django_ace import AceWidget @@ -73,7 +75,7 @@ class ContestProblemInline(SortableInlineAdminMixin, admin.TabularInline): def rejudge_column(self, obj): if obj.id is None: return '' - return format_html('{1}', + return format_html('{1}', reverse('admin:judge_contest_rejudge', args=(obj.contest.id, obj.id)), _('Rejudge')) @@ -272,6 +274,7 @@ def get_urls(self): path('/judge//', self.rejudge_view, name='judge_contest_rejudge'), ] + super(ContestAdmin, self).get_urls() + @method_decorator(require_POST) def rejudge_view(self, request, contest_id, problem_id): contest = get_object_or_404(Contest, id=contest_id) if not self.has_change_permission(request, contest): @@ -285,6 +288,7 @@ def rejudge_view(self, request, contest_id, problem_id): len(queryset)) % len(queryset)) return HttpResponseRedirect(reverse('admin:judge_contest_change', args=(contest_id,))) + @method_decorator(require_POST) def rate_all_view(self, request): if not request.user.has_perm('judge.contest_rating'): raise PermissionDenied() @@ -296,6 +300,7 @@ def rate_all_view(self, request): rate_contest(contest) return HttpResponseRedirect(reverse('admin:judge_contest_changelist')) + @method_decorator(require_POST) def rate_view(self, request, id): if not request.user.has_perm('judge.contest_rating'): raise PermissionDenied() diff --git a/judge/admin/runtime.py b/judge/admin/runtime.py index 12e0798269..db5b271b38 100644 --- a/judge/admin/runtime.py +++ b/judge/admin/runtime.py @@ -4,9 +4,11 @@ from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404 from django.urls import path, reverse +from django.utils.decorators import method_decorator from django.utils.html import format_html from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ +from django.views.decorators.http import require_POST from reversion.admin import VersionAdmin from django_ace import AceWidget @@ -85,18 +87,21 @@ def disconnect_judge(self, id, force=False): judge.disconnect(force=force) return HttpResponseRedirect(reverse('admin:judge_judge_changelist')) + @method_decorator(require_POST) def disconnect_view(self, request, id): judge = get_object_or_404(Judge, id=id) if not self.has_change_permission(request, judge): raise PermissionDenied() return self.disconnect_judge(id) + @method_decorator(require_POST) def terminate_view(self, request, id): judge = get_object_or_404(Judge, id=id) if not self.has_change_permission(request, judge): raise PermissionDenied() return self.disconnect_judge(id, force=True) + @method_decorator(require_POST) def disable_view(self, request, id): judge = get_object_or_404(Judge, id=id) if not self.has_change_permission(request, judge): diff --git a/judge/admin/submission.py b/judge/admin/submission.py index aa3889d304..ba2fcf229e 100644 --- a/judge/admin/submission.py +++ b/judge/admin/submission.py @@ -9,8 +9,10 @@ from django.http import HttpResponseRedirect from django.shortcuts import get_object_or_404 from django.urls import path, reverse +from django.utils.decorators import method_decorator from django.utils.html import format_html from django.utils.translation import gettext, gettext_lazy as _, ngettext, pgettext +from django.views.decorators.http import require_POST from reversion.admin import VersionAdmin from django_ace import AceWidget @@ -250,6 +252,7 @@ def get_urls(self): path('/judge/', self.judge_view, name='judge_submission_rejudge'), ] + super(SubmissionAdmin, self).get_urls() + @method_decorator(require_POST) def judge_view(self, request, id): if not request.user.has_perm('judge.rejudge_submission') or not request.user.has_perm('judge.edit_own_problem'): raise PermissionDenied() diff --git a/templates/admin/base_site.html b/templates/admin/base_site.html new file mode 100644 index 0000000000..c5c2e2ca1d --- /dev/null +++ b/templates/admin/base_site.html @@ -0,0 +1,15 @@ +{% extends "admin/base_site.html" %} + +{% block pretitle %}{{ block.super }} + + +{% endblock %} diff --git a/templates/admin/judge/contest/change_form.html b/templates/admin/judge/contest/change_form.html index 7f540f654b..1a692032ef 100644 --- a/templates/admin/judge/contest/change_form.html +++ b/templates/admin/judge/contest/change_form.html @@ -15,7 +15,7 @@ {% block after_field_sets %}{{ block.super }} {% if original and original.is_rated and original.ended and perms.judge.contest_rating %} diff --git a/templates/admin/judge/contest/change_list.html b/templates/admin/judge/contest/change_list.html index ae409fc83c..6095ef3030 100644 --- a/templates/admin/judge/contest/change_list.html +++ b/templates/admin/judge/contest/change_list.html @@ -5,7 +5,7 @@ {{ block.super }} {% if not is_popup and perms.judge.contest_rating %}
  • - + {% trans "Rate all ratable contests" %}
  • diff --git a/templates/admin/judge/judge/change_form.html b/templates/admin/judge/judge/change_form.html index 738d8a5c33..a97af4a16d 100644 --- a/templates/admin/judge/judge/change_form.html +++ b/templates/admin/judge/judge/change_form.html @@ -14,24 +14,24 @@ {% block after_field_sets %}{{ block.super }} {% if original %} {% if not original.is_disabled %} {% else %} diff --git a/templates/admin/judge/submission/change_form.html b/templates/admin/judge/submission/change_form.html index 0b5e5bf6c0..96ebba97bf 100644 --- a/templates/admin/judge/submission/change_form.html +++ b/templates/admin/judge/submission/change_form.html @@ -12,7 +12,7 @@ {% block after_field_sets %}{{ block.super }} {% if original and not original.is_locked %}