Repository: matrix-org/synapse

Issue:
we seem to be returning the wrong error code when adding an undefined alias to canonical_alias
we're returning a 404 with `{errcode: "M_NOT_FOUND", error: "Room alias #megolm:sw1v.org not found"}`; https://github.com/matrix-org/matrix-doc/pull/2432#discussion_r388457807 suggests a different conclusion.

The upshot is that the error message in riot is unhelpful:
![Peek 2020-03-19 09-38](https://user-images.githubusercontent.com/1389908/77053780-c18e7000-69c6-11ea-8b5b-ee6ba3bfc63e.gif)



Discussion:
related to #6898 
@richvdh I believe this is working as expected. The validation code throw three errors:
1. `M_INVALID_PARAM` if the form of the alias is wrong.
2. `M_NOT_FOUND` if the alias is completely unknown.
3. `M_BAD_ALIAS` if the alias is found, but does not point to this room.

I think this matches the comment you pointed to, when taking into account the context of the conversation above it.

Note that the logic for this was implemented in #6971, although it is a bit hard to see:
1. `M_INVALID_PARAM` is raised from `RoomAlias.from_string()`
2. `M_NOT_FOUND` is raised via `directory_handler.get_association()`
3. `M_BAD_ALIAS` is raised directly.

Resolving patch:
diff --git a/synapse/handlers/message.py b/synapse/handlers/message.py
--- a/synapse/handlers/message.py
+++ b/synapse/handlers/message.py
@@ -851,6 +851,38 @@ def handle_new_client_event(
                     self.store.remove_push_actions_from_staging, event.event_id
                 )
 
+    @defer.inlineCallbacks
+    def _validate_canonical_alias(
+        self, directory_handler, room_alias_str, expected_room_id
+    ):
+        """
+        Ensure that the given room alias points to the expected room ID.
+
+        Args:
+            directory_handler: The directory handler object.
+            room_alias_str: The room alias to check.
+            expected_room_id: The room ID that the alias should point to.
+        """
+        room_alias = RoomAlias.from_string(room_alias_str)
+        try:
+            mapping = yield directory_handler.get_association(room_alias)
+        except SynapseError as e:
+            # Turn M_NOT_FOUND errors into M_BAD_ALIAS errors.
+            if e.errcode == Codes.NOT_FOUND:
+                raise SynapseError(
+                    400,
+                    "Room alias %s does not point to the room" % (room_alias_str,),
+                    Codes.BAD_ALIAS,
+                )
+            raise
+
+        if mapping["room_id"] != expected_room_id:
+            raise SynapseError(
+                400,
+                "Room alias %s does not point to the room" % (room_alias_str,),
+                Codes.BAD_ALIAS,
+            )
+
     @defer.inlineCallbacks
     def persist_and_notify_client_event(
         self, requester, event, context, ratelimit=True, extra_users=[]
@@ -905,15 +937,9 @@ def persist_and_notify_client_event(
             room_alias_str = event.content.get("alias", None)
             directory_handler = self.hs.get_handlers().directory_handler
             if room_alias_str and room_alias_str != original_alias:
-                room_alias = RoomAlias.from_string(room_alias_str)
-                mapping = yield directory_handler.get_association(room_alias)
-
-                if mapping["room_id"] != event.room_id:
-                    raise SynapseError(
-                        400,
-                        "Room alias %s does not point to the room" % (room_alias_str,),
-                        Codes.BAD_ALIAS,
-                    )
+                yield self._validate_canonical_alias(
+                    directory_handler, room_alias_str, event.room_id
+                )
 
             # Check that alt_aliases is the proper form.
             alt_aliases = event.content.get("alt_aliases", [])
@@ -931,16 +957,9 @@ def persist_and_notify_client_event(
             new_alt_aliases = set(alt_aliases) - set(original_alt_aliases)
             if new_alt_aliases:
                 for alias_str in new_alt_aliases:
-                    room_alias = RoomAlias.from_string(alias_str)
-                    mapping = yield directory_handler.get_association(room_alias)
-
-                    if mapping["room_id"] != event.room_id:
-                        raise SynapseError(
-                            400,
-                            "Room alias %s does not point to the room"
-                            % (room_alias_str,),
-                            Codes.BAD_ALIAS,
-                        )
+                    yield self._validate_canonical_alias(
+                        directory_handler, alias_str, event.room_id
+                    )
 
         federation_handler = self.hs.get_handlers().federation_handler
 


Test patch: