From 330be16516a813b557e896c9a3d2d421515d2535 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Mon, 19 Sep 2022 09:51:41 -0700 Subject: [PATCH] Adds permissions checking for admin models --- bookwyrm/forms/admin.py | 11 +++++++++-- bookwyrm/forms/custom_form.py | 8 ++++++-- bookwyrm/models/antispam.py | 21 ++++++++++++++++++--- bookwyrm/models/report.py | 2 +- bookwyrm/tests/views/admin/test_automod.py | 1 + 5 files changed, 35 insertions(+), 8 deletions(-) diff --git a/bookwyrm/forms/admin.py b/bookwyrm/forms/admin.py index 4141327d3..ea0f8ccc7 100644 --- a/bookwyrm/forms/admin.py +++ b/bookwyrm/forms/admin.py @@ -2,13 +2,14 @@ import datetime from django import forms +from django.core.exceptions import PermissionDenied from django.forms import widgets from django.utils import timezone from django.utils.translation import gettext_lazy as _ from django_celery_beat.models import IntervalSchedule from bookwyrm import models -from .custom_form import CustomForm +from .custom_form import CustomForm, StyledForm # pylint: disable=missing-class-docstring @@ -130,7 +131,7 @@ class AutoModRuleForm(CustomForm): fields = ["string_match", "flag_users", "flag_statuses", "created_by"] -class IntervalScheduleForm(CustomForm): +class IntervalScheduleForm(StyledForm): class Meta: model = IntervalSchedule fields = ["every", "period"] @@ -139,3 +140,9 @@ class IntervalScheduleForm(CustomForm): "every": forms.NumberInput(attrs={"aria-describedby": "desc_every"}), "period": forms.Select(attrs={"aria-describedby": "desc_period"}), } + + def save(self, request, *args, **kwargs): + """This is an outside model so the perms check works differently""" + if not request.user.has_perm("bookwyrm.moderate_user"): + raise PermissionDenied() + return super().save(*args, **kwargs) diff --git a/bookwyrm/forms/custom_form.py b/bookwyrm/forms/custom_form.py index 3c2b4685f..10f72f967 100644 --- a/bookwyrm/forms/custom_form.py +++ b/bookwyrm/forms/custom_form.py @@ -4,7 +4,7 @@ from django.forms import ModelForm from django.forms.widgets import Textarea -class CustomForm(ModelForm): +class StyledForm(ModelForm): """add css classes to the forms""" def __init__(self, *args, **kwargs): @@ -16,7 +16,7 @@ class CustomForm(ModelForm): css_classes["checkbox"] = "checkbox" css_classes["textarea"] = "textarea" # pylint: disable=super-with-arguments - super(CustomForm, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) for visible in self.visible_fields(): if hasattr(visible.field.widget, "input_type"): input_type = visible.field.widget.input_type @@ -25,6 +25,10 @@ class CustomForm(ModelForm): visible.field.widget.attrs["rows"] = 5 visible.field.widget.attrs["class"] = css_classes[input_type] + +class CustomForm(StyledForm): + """Check permissions on save""" + def save(self, request, *args, **kwargs): """Save and check perms""" self.instance.raise_not_editable(request.user) diff --git a/bookwyrm/models/antispam.py b/bookwyrm/models/antispam.py index 628f4525c..40d663a22 100644 --- a/bookwyrm/models/antispam.py +++ b/bookwyrm/models/antispam.py @@ -3,6 +3,7 @@ from functools import reduce import operator from django.apps import apps +from django.core.exceptions import PermissionDenied from django.db import models, transaction from django.db.models import Q from django.utils.translation import gettext_lazy as _ @@ -12,7 +13,21 @@ from .base_model import BookWyrmModel from .user import User -class EmailBlocklist(BookWyrmModel): +class AdminModel(BookWyrmModel): + """Overrides the permissions methods""" + + class Meta: + """this is just here to provide default fields for other models""" + + abstract = True + + def raise_not_editable(self, viewer): + if viewer.has_perm("bookwyrm.moderate_user"): + return + raise PermissionDenied() + + +class EmailBlocklist(AdminModel): """blocked email addresses""" domain = models.CharField(max_length=255, unique=True) @@ -29,7 +44,7 @@ class EmailBlocklist(BookWyrmModel): return User.objects.filter(email__endswith=f"@{self.domain}") -class IPBlocklist(BookWyrmModel): +class IPBlocklist(AdminModel): """blocked ip addresses""" address = models.CharField(max_length=255, unique=True) @@ -41,7 +56,7 @@ class IPBlocklist(BookWyrmModel): ordering = ("-created_date",) -class AutoMod(BookWyrmModel): +class AutoMod(AdminModel): """rules to automatically flag suspicious activity""" string_match = models.CharField(max_length=200, unique=True) diff --git a/bookwyrm/models/report.py b/bookwyrm/models/report.py index 19d3b62f1..f6e665053 100644 --- a/bookwyrm/models/report.py +++ b/bookwyrm/models/report.py @@ -25,7 +25,7 @@ class Report(BookWyrmModel): def raise_not_editable(self, viewer): """instead of user being the owner field, it's reporter""" - if self.reporter == viewer: + if self.reporter == viewer or viewer.has_perm("bookwyrm.moderate_user"): return raise PermissionDenied() diff --git a/bookwyrm/tests/views/admin/test_automod.py b/bookwyrm/tests/views/admin/test_automod.py index 95db4d52f..a1c03d436 100644 --- a/bookwyrm/tests/views/admin/test_automod.py +++ b/bookwyrm/tests/views/admin/test_automod.py @@ -15,6 +15,7 @@ from bookwyrm.tests.validate_html import validate_html class AutomodViews(TestCase): """every response to a get request, html or json""" + # pylint: disable=invalid-name def setUp(self): """we need basic test data and mocks""" self.factory = RequestFactory()