summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrendan Abolivier <babolivier@matrix.org>2022-01-28 14:00:12 +0000
committerBrendan Abolivier <babolivier@matrix.org>2022-01-28 14:00:12 +0000
commit4df1d1231be65bf265b5f3f67fa02965bad9cfc6 (patch)
treef7ea3d2dde62c9c3a3f2c62cdce68c6add64fe97
parentAdd tests (diff)
downloadsynapse-4df1d1231be65bf265b5f3f67fa02965bad9cfc6.tar.xz
Incorporate review
-rw-r--r--synapse/config/server.py6
-rw-r--r--synapse/handlers/profile.py24
-rw-r--r--synapse/handlers/room_member.py7
-rw-r--r--tests/handlers/test_profile.py54
-rw-r--r--tests/rest/client/test_profile.py40
5 files changed, 45 insertions, 86 deletions
diff --git a/synapse/config/server.py b/synapse/config/server.py
index 26f1177e64..a460cf25b4 100644
--- a/synapse/config/server.py
+++ b/synapse/config/server.py
@@ -1181,16 +1181,14 @@ class ServerConfig(Config):
         #
         #allow_per_room_profiles: false
 
-        # The largest allowed size for a user avatar. If not defined, no
-        # restriction will be imposed.
+        # The largest allowed file size for a user avatar. Defaults to no restriction.
         #
         # Note that user avatar changes will not work if this is set without
         # using Synapse's media repository.
         #
         #max_avatar_size: 10M
 
-        # Allow mimetypes for a user avatar. If not defined, no restriction will
-        # be imposed.
+        # The MIME types allowed for user avatars. Defaults to no restriction.
         #
         # Note that user avatar changes will not work if this is set without
         # using Synapse's media repository.
diff --git a/synapse/handlers/profile.py b/synapse/handlers/profile.py
index 33f8678e50..36e3ad2ba9 100644
--- a/synapse/handlers/profile.py
+++ b/synapse/handlers/profile.py
@@ -293,7 +293,8 @@ class ProfileHandler:
                 400, "Avatar URL is too long (max %i)" % (MAX_AVATAR_URL_LEN,)
             )
 
-        await self.check_avatar_size_and_mime_type(new_avatar_url)
+        if not await self.check_avatar_size_and_mime_type(new_avatar_url):
+            raise SynapseError(403, "This avatar is not allowed", Codes.FORBIDDEN)
 
         avatar_url_to_set: Optional[str] = new_avatar_url
         if new_avatar_url == "":
@@ -316,22 +317,8 @@ class ProfileHandler:
 
         await self._update_join_states(requester, target_user)
 
-    async def check_avatar_size_and_mime_type(self, mxc: str) -> None:
-        """Check that the size and content type of the avatar at the given MXC URI are
-        within the configured limits.
-
-        Args:
-            mxc: The MXC URI at which the avatar can be found.
-
-        Raises:
-            SynapseError with an M_FORBIDDEN error code if the avatar doesn't fit within
-            the limits allowed by the configuration.
-        """
-        if not await self._check_avatar_size_and_mime_type(mxc):
-            raise SynapseError(403, "This avatar is not allowed", Codes.FORBIDDEN)
-
     @cached()
-    async def _check_avatar_size_and_mime_type(self, mxc: str) -> bool:
+    async def check_avatar_size_and_mime_type(self, mxc: str) -> bool:
         """Check that the size and content type of the avatar at the given MXC URI are
         within the configured limits.
 
@@ -365,9 +352,10 @@ class ProfileHandler:
             # Ensure avatar does not exceed max allowed avatar size
             if media_info["media_length"] > self.max_avatar_size:
                 logger.warning(
-                    "Forbidding avatar change to %s: avatar must be less than %s bytes",
+                    "Forbidding avatar change to %s: %d bytes is above the allowed size "
+                    "limit",
                     mxc,
-                    self.max_avatar_size,
+                    media_info["media_length"],
                 )
                 return False
 
diff --git a/synapse/handlers/room_member.py b/synapse/handlers/room_member.py
index 4e979dd8e2..3dd5e1b6e4 100644
--- a/synapse/handlers/room_member.py
+++ b/synapse/handlers/room_member.py
@@ -591,9 +591,10 @@ class RoomMemberHandler(metaclass=abc.ABCMeta):
             )
 
         if "avatar_url" in content:
-            await self.profile_handler.check_avatar_size_and_mime_type(
-                content["avatar_url"]
-            )
+            if not await self.profile_handler.check_avatar_size_and_mime_type(
+                content["avatar_url"],
+            ):
+                raise SynapseError(403, "This avatar is not allowed", Codes.FORBIDDEN)
 
         # The event content should *not* include the authorising user as
         # it won't be properly signed. Strip it out since it might come
diff --git a/tests/handlers/test_profile.py b/tests/handlers/test_profile.py
index b7d6187a21..60235e5699 100644
--- a/tests/handlers/test_profile.py
+++ b/tests/handlers/test_profile.py
@@ -257,30 +257,22 @@ class ProfileTestCase(unittest.HomeserverTestCase):
         # The first check that's done by this method is whether the file exists; if we
         # don't get an error on a non-existing file then it means all of the checks were
         # successfully skipped.
-        allowed = self.get_success(
-            self.handler._check_avatar_size_and_mime_type("mxc://test/unknown_file")
+        res = self.get_success(
+            self.handler.check_avatar_size_and_mime_type("mxc://test/unknown_file")
         )
-        self.assertTrue(allowed)
+        self.assertTrue(res)
 
-    @unittest.override_config(
-        {
-            "max_avatar_size": 50,
-        }
-    )
+    @unittest.override_config({"max_avatar_size": 50})
     def test_avatar_constraints_missing(self):
         """Tests that an avatar isn't allowed if the file at the given MXC URI couldn't
         be found.
         """
-        allowed = self.get_success(
-            self.handler._check_avatar_size_and_mime_type("mxc://test/unknown_file")
+        res = self.get_success(
+            self.handler.check_avatar_size_and_mime_type("mxc://test/unknown_file")
         )
-        self.assertFalse(allowed)
+        self.assertFalse(res)
 
-    @unittest.override_config(
-        {
-            "max_avatar_size": 50,
-        }
-    )
+    @unittest.override_config({"max_avatar_size": 50})
     def test_avatar_constraints_file_size(self):
         """Tests that a file that's above the allowed file size is forbidden but one
         that's below it is allowed.
@@ -292,21 +284,17 @@ class ProfileTestCase(unittest.HomeserverTestCase):
             }
         )
 
-        allowed = self.get_success(
-            self.handler._check_avatar_size_and_mime_type("mxc://test/small")
+        res = self.get_success(
+            self.handler.check_avatar_size_and_mime_type("mxc://test/small")
         )
-        self.assertTrue(allowed)
+        self.assertTrue(res)
 
-        allowed = self.get_success(
-            self.handler._check_avatar_size_and_mime_type("mxc://test/big")
+        res = self.get_success(
+            self.handler.check_avatar_size_and_mime_type("mxc://test/big")
         )
-        self.assertFalse(allowed)
+        self.assertFalse(res)
 
-    @unittest.override_config(
-        {
-            "allowed_avatar_mimetypes": ["image/png"],
-        }
-    )
+    @unittest.override_config({"allowed_avatar_mimetypes": ["image/png"]})
     def test_avatar_constraint_mime_type(self):
         """Tests that a file with an unauthorised MIME type is forbidden but one with
         an authorised content type is allowed.
@@ -318,15 +306,15 @@ class ProfileTestCase(unittest.HomeserverTestCase):
             }
         )
 
-        allowed = self.get_success(
-            self.handler._check_avatar_size_and_mime_type("mxc://test/good")
+        res = self.get_success(
+            self.handler.check_avatar_size_and_mime_type("mxc://test/good")
         )
-        self.assertTrue(allowed)
+        self.assertTrue(res)
 
-        allowed = self.get_success(
-            self.handler._check_avatar_size_and_mime_type("mxc://test/bad")
+        res = self.get_success(
+            self.handler.check_avatar_size_and_mime_type("mxc://test/bad")
         )
-        self.assertFalse(allowed)
+        self.assertFalse(res)
 
     def _setup_local_files(self, names_and_props: Dict[str, Dict[str, Any]]):
         """Stores metadata about files in the database.
diff --git a/tests/rest/client/test_profile.py b/tests/rest/client/test_profile.py
index 140e62a46a..ead883ded8 100644
--- a/tests/rest/client/test_profile.py
+++ b/tests/rest/client/test_profile.py
@@ -155,11 +155,7 @@ class ProfileTestCase(unittest.HomeserverTestCase):
         self.assertEqual(channel.code, 200, channel.result)
         return channel.json_body.get("avatar_url")
 
-    @unittest.override_config(
-        {
-            "max_avatar_size": 50,
-        }
-    )
+    @unittest.override_config({"max_avatar_size": 50})
     def test_avatar_size_limit_global(self):
         """Tests that the maximum size limit for avatars is enforced when updating a
         global profile.
@@ -173,7 +169,7 @@ class ProfileTestCase(unittest.HomeserverTestCase):
 
         channel = self.make_request(
             "PUT",
-            "/profile/%s/avatar_url" % (self.owner,),
+            f"/profile/{self.owner}/avatar_url",
             content={"avatar_url": "mxc://test/big"},
             access_token=self.owner_tok,
         )
@@ -184,17 +180,13 @@ class ProfileTestCase(unittest.HomeserverTestCase):
 
         channel = self.make_request(
             "PUT",
-            "/profile/%s/avatar_url" % (self.owner,),
+            f"/profile/{self.owner}/avatar_url",
             content={"avatar_url": "mxc://test/small"},
             access_token=self.owner_tok,
         )
         self.assertEqual(channel.code, 200, channel.result)
 
-    @unittest.override_config(
-        {
-            "max_avatar_size": 50,
-        }
-    )
+    @unittest.override_config({"max_avatar_size": 50})
     def test_avatar_size_limit_per_room(self):
         """Tests that the maximum size limit for avatars is enforced when updating a
         per-room profile.
@@ -210,7 +202,7 @@ class ProfileTestCase(unittest.HomeserverTestCase):
 
         channel = self.make_request(
             "PUT",
-            "/rooms/%s/state/m.room.member/%s" % (room_id, self.owner),
+            f"/rooms/{room_id}/state/m.room.member/{self.owner}",
             content={"membership": "join", "avatar_url": "mxc://test/big"},
             access_token=self.owner_tok,
         )
@@ -221,17 +213,13 @@ class ProfileTestCase(unittest.HomeserverTestCase):
 
         channel = self.make_request(
             "PUT",
-            "/rooms/%s/state/m.room.member/%s" % (room_id, self.owner),
+            f"/rooms/{room_id}/state/m.room.member/{self.owner}",
             content={"membership": "join", "avatar_url": "mxc://test/small"},
             access_token=self.owner_tok,
         )
         self.assertEqual(channel.code, 200, channel.result)
 
-    @unittest.override_config(
-        {
-            "allowed_avatar_mimetypes": ["image/png"],
-        }
-    )
+    @unittest.override_config({"allowed_avatar_mimetypes": ["image/png"]})
     def test_avatar_allowed_mime_type_global(self):
         """Tests that the MIME type whitelist for avatars is enforced when updating a
         global profile.
@@ -245,7 +233,7 @@ class ProfileTestCase(unittest.HomeserverTestCase):
 
         channel = self.make_request(
             "PUT",
-            "/profile/%s/avatar_url" % (self.owner,),
+            f"/profile/{self.owner}/avatar_url",
             content={"avatar_url": "mxc://test/bad"},
             access_token=self.owner_tok,
         )
@@ -256,17 +244,13 @@ class ProfileTestCase(unittest.HomeserverTestCase):
 
         channel = self.make_request(
             "PUT",
-            "/profile/%s/avatar_url" % (self.owner,),
+            f"/profile/{self.owner}/avatar_url",
             content={"avatar_url": "mxc://test/good"},
             access_token=self.owner_tok,
         )
         self.assertEqual(channel.code, 200, channel.result)
 
-    @unittest.override_config(
-        {
-            "allowed_avatar_mimetypes": ["image/png"],
-        }
-    )
+    @unittest.override_config({"allowed_avatar_mimetypes": ["image/png"]})
     def test_avatar_allowed_mime_type_per_room(self):
         """Tests that the MIME type whitelist for avatars is enforced when updating a
         per-room profile.
@@ -282,7 +266,7 @@ class ProfileTestCase(unittest.HomeserverTestCase):
 
         channel = self.make_request(
             "PUT",
-            "/rooms/%s/state/m.room.member/%s" % (room_id, self.owner),
+            f"/rooms/{room_id}/state/m.room.member/{self.owner}",
             content={"membership": "join", "avatar_url": "mxc://test/bad"},
             access_token=self.owner_tok,
         )
@@ -293,7 +277,7 @@ class ProfileTestCase(unittest.HomeserverTestCase):
 
         channel = self.make_request(
             "PUT",
-            "/rooms/%s/state/m.room.member/%s" % (room_id, self.owner),
+            f"/rooms/{room_id}/state/m.room.member/{self.owner}",
             content={"membership": "join", "avatar_url": "mxc://test/good"},
             access_token=self.owner_tok,
         )