From 1135193dfde2a844d38dab4bd50a69658891abcb Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 20 Oct 2017 23:51:07 +0100 Subject: [PATCH] Validate group ids when parsing May as well do it whenever we parse a Group ID. We check the sigil and basic structure here so it makes sense to check the grammar in the same place. --- synapse/groups/groups_server.py | 21 +++++---------------- synapse/types.py | 17 +++++++++++++++++ tests/test_types.py | 24 +++++++++++++++++++++++- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/synapse/groups/groups_server.py b/synapse/groups/groups_server.py index 3599bfe9cf..23beb3187e 100644 --- a/synapse/groups/groups_server.py +++ b/synapse/groups/groups_server.py @@ -15,7 +15,6 @@ import logging -from synapse import types from synapse.api.errors import SynapseError from synapse.types import GroupID, RoomID, UserID, get_domain_from_id from twisted.internet import defer @@ -696,9 +695,11 @@ class GroupsServerHandler(object): def create_group(self, group_id, user_id, content): group = yield self.check_group_is_ours(group_id) - _validate_group_id(group_id) - logger.info("Attempting to create group with ID: %r", group_id) + + # parsing the id into a GroupID validates it. + group_id_obj = GroupID.from_string(group_id) + if group: raise SynapseError(400, "Group already exists") @@ -708,7 +709,7 @@ class GroupsServerHandler(object): raise SynapseError( 403, "Only server admin can create group on this server", ) - localpart = GroupID.from_string(group_id).localpart + localpart = group_id_obj.localpart if not localpart.startswith(self.hs.config.group_creation_prefix): raise SynapseError( 400, @@ -784,15 +785,3 @@ def _parse_visibility_from_contents(content): is_public = True return is_public - - -def _validate_group_id(group_id): - """Validates the group ID is valid for creation on this home server - """ - localpart = GroupID.from_string(group_id).localpart - - if types.contains_invalid_mxid_characters(localpart): - raise SynapseError( - 400, - "Group ID can only contain characters a-z, 0-9, or '=_-./'", - ) diff --git a/synapse/types.py b/synapse/types.py index 88eb818de4..5e3d1fc0b2 100644 --- a/synapse/types.py +++ b/synapse/types.py @@ -161,6 +161,23 @@ class GroupID(DomainSpecificString): """Structure representing a group ID.""" SIGIL = "+" + @classmethod + def from_string(cls, s): + group_id = super(GroupID, cls).from_string(s) + if not group_id.localpart: + raise SynapseError( + 400, + "Group ID cannot be empty", + ) + + if contains_invalid_mxid_characters(group_id.localpart): + raise SynapseError( + 400, + "Group ID can only contain characters a-z, 0-9, or '=_-./'", + ) + + return group_id + mxid_localpart_allowed_characters = set("_-./=" + string.ascii_lowercase + string.digits) diff --git a/tests/test_types.py b/tests/test_types.py index 24d61dbe54..115def2287 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -17,7 +17,7 @@ from tests import unittest from synapse.api.errors import SynapseError from synapse.server import HomeServer -from synapse.types import UserID, RoomAlias +from synapse.types import UserID, RoomAlias, GroupID mock_homeserver = HomeServer(hostname="my.domain") @@ -60,3 +60,25 @@ class RoomAliasTestCase(unittest.TestCase): room = RoomAlias("channel", "my.domain") self.assertEquals(room.to_string(), "#channel:my.domain") + + +class GroupIDTestCase(unittest.TestCase): + def test_parse(self): + group_id = GroupID.from_string("+group/=_-.123:my.domain") + self.assertEqual("group/=_-.123", group_id.localpart) + self.assertEqual("my.domain", group_id.domain) + + def test_validate(self): + bad_ids = [ + "$badsigil:domain", + "+:empty", + ] + [ + "+group" + c + ":domain" for c in "A%?æ£" + ] + for id_string in bad_ids: + try: + GroupID.from_string(id_string) + self.fail("Parsing '%s' should raise exception" % id_string) + except SynapseError as exc: + self.assertEqual(400, exc.code) + self.assertEqual("M_UNKNOWN", exc.errcode)