]> git.ipfire.org Git - dbl.git/commitdiff
reports: Implement some basic permissions check
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 3 Mar 2026 11:26:14 +0000 (11:26 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 3 Mar 2026 11:26:14 +0000 (11:26 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/dbl/api/reports.py
src/dbl/reports.py
src/dbl/users.py

index 6e1a8e84ac7c986c40051f8e00316eea474c8de3..0bcb2c2fc258968154956521978b9f913a3964f2 100644 (file)
@@ -106,6 +106,11 @@ async def close_report(
                report: reports.Report = fastapi.Depends(get_report_from_path),
                user: users.User = fastapi.Depends(require_current_user),
 ) -> fastapi.Response:
+       # Check for permissions
+       if not await report.has_perm(user, accept=data.accept):
+               raise fastapi.HTTPError(403, "You don't have permission to change this report")
+
+       # Close the report
        await report.close(
                closed_by = user,
                accept    = data.accept,
index 3b46d72d22775ed2efb6c69cfeabd9e5de503333..6e1876dad7f630b4b08a017eab3653dbd4c5640a 100644 (file)
@@ -250,6 +250,27 @@ class Report(sqlmodel.SQLModel, database.BackendMixin, table=True):
        # Accepted?
        accepted : bool = False
 
+       # Permissions check
+       async def has_perm(self, user, accept=False):
+               """
+                       Returns True if the given user has permission to make changes to this report.
+               """
+               # Admins and moderators have all permissions
+               if user.is_admin() or user.is_moderator():
+                       return True
+
+               # The owners have some permissions...
+               if self.reported_by == user.uid:
+                       # Users cannot accept their own reports
+                       if accept:
+                               return False
+
+                       # Otherwise users can manage their own reports
+                       return True
+
+               # Everybody else has no permissions
+               return False
+
        # Close!
 
        async def close(self, closed_by=None, accept=True, update_stats=True):
@@ -257,10 +278,12 @@ class Report(sqlmodel.SQLModel, database.BackendMixin, table=True):
                        Called when a moderator has made a decision
                """
                # Prevent a report from being closed again
-               if self.is_closed()
+               if self.is_closed():
                        raise RuntimeError("Report %s has already been closed" % self)
 
-               # XXX Check for permissions
+               # Check for permissions
+               if not await self.has_perm(closed_by, accept=accept):
+                       raise RuntimeError("%s does not have permission to change report %s" % (closed_by, self.id))
 
                # Only the the user ID in the database
                if isinstance(closed_by, users.User):
index 5ea7f827b90fa241eb763a047a9666bc753fa58f..df019ffc45888820e842cf4cedcac237bff13307 100644 (file)
@@ -20,6 +20,7 @@
 
 import email.message
 import email.utils
+import functools
 import ldap
 import logging
 import smtplib
@@ -167,6 +168,20 @@ class User(LDAPObject):
                """
                return self._get_string("mail")
 
+       @functools.cache
+       def is_admin(self):
+               """
+                       Returns True if this user is an admin
+               """
+               return self in self.backend.users.admins
+
+       @functools.cache
+       def is_moderator(self):
+               """
+                       Returns True if this user is a moderator
+               """
+               return self in self.backend.users.moderators
+
        def sendmail(self, message, sender=None, headers=None):
                """
                        Sends the given message to this user