From 88f9ec3c34675c1838410046f31ff9264b78902a Mon Sep 17 00:00:00 2001
From: "J.-S. Caux" <J.S.Caux@uva.nl>
Date: Thu, 14 Nov 2019 12:09:40 +0100
Subject: [PATCH] Add basic queryset filtering for StoredMessage (not yet good
 enough)

This is not secure. A user might change their email to that of
someone else, and then see the messages. Need a verified email class.
---
 apimail/api/views.py             |  4 +++-
 apimail/managers.py              | 37 ++++++++++++++++++++++++++++++++
 apimail/models/stored_message.py |  3 +++
 3 files changed, 43 insertions(+), 1 deletion(-)
 create mode 100644 apimail/managers.py

diff --git a/apimail/api/views.py b/apimail/api/views.py
index 8f64b915b..f5b06b66b 100644
--- a/apimail/api/views.py
+++ b/apimail/api/views.py
@@ -32,7 +32,9 @@ class StoredMessageListAPIView(ListAPIView):
 
 
 class StoredMessageRetrieveAPIView(RetrieveAPIView):
-    queryset = StoredMessage.objects.all()
     permission_classes = (IsAdminUser,)
     serializer_class = StoredMessageSerializer
     lookup_field = 'uuid'
+
+    def get_queryset(self):
+        return StoredMessage.objects.filter_for_user(self.request.user)
diff --git a/apimail/managers.py b/apimail/managers.py
new file mode 100644
index 000000000..63e1eac12
--- /dev/null
+++ b/apimail/managers.py
@@ -0,0 +1,37 @@
+__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)"
+__license__ = "AGPL v3"
+
+
+from django.db import models
+
+
+class StoredMessageQuerySet(models.QuerySet):
+    """
+    All StoredMessage querysets are always filtered for the user.
+    """
+    def filter_for_user(self, request):
+        """
+        Either su or staff, or user's email addresses overlap with sender/recipients.
+        """
+        if not request.user.is_authenticated:
+            return self.none()
+        elif request.user.is_superuser or request.user.is_admin:
+            return self
+        emails = [request.user.email,] if request.user.email else []
+        if request.user.contributor:
+            for pe in request.user.contributor.profile.emails.all():
+                emails.append(pe.email)
+        return self.filter_for_emails(emails=emails)
+
+    def filter_for_emails(self, emails):
+        """
+        Ensure overlap of the emails in emails kwarg with those in sender or recipients.
+        """
+        emails_used = emails
+        if not isinstance(emails, list):
+            emails_used = [emails]
+        emails_lower = [e.lower() for e in emails_used]
+        return self.filter(
+            models.Q(data__sender__in=emails_lower) |
+            models.Q(data__recipients__in=emails_lower) | # if recipients is a single entry
+            models.Q(data__recipients__overlap=emails_lower)) # if recipients is a list
diff --git a/apimail/models/stored_message.py b/apimail/models/stored_message.py
index f3e1bf895..1f5e01b9a 100644
--- a/apimail/models/stored_message.py
+++ b/apimail/models/stored_message.py
@@ -10,6 +10,7 @@ from django.urls import reverse
 
 from scipost.storage import SecureFileStorage
 
+from ..managers import StoredMessageQuerySet
 from ..validators import validate_max_email_attachment_file_size
 
 
@@ -23,6 +24,8 @@ class StoredMessage(models.Model):
         editable=False)
     data = JSONField(default=dict)
 
+    objects = StoredMessageQuerySet.as_manager()
+
     class Meta:
         ordering = ['-data__Date',]
 
-- 
GitLab