From 4a88cdf682bd3842282e569748efb43bbca75917 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Tue, 23 Jun 2020 16:19:00 +0100 Subject: [PATCH] Pass join errors through internal API boundaries Required for certain invite sytests. We will need to think of a better way of handling this going forwards. --- clientapi/routing/joinroom.go | 26 ++++++++++++++++++++++++-- roomserver/api/perform.go | 16 ++++++++++++++++ roomserver/internal/perform_join.go | 10 ++++++++++ roomserver/inthttp/server.go | 2 +- 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/clientapi/routing/joinroom.go b/clientapi/routing/joinroom.go index db890d03f..2e5cc3a16 100644 --- a/clientapi/routing/joinroom.go +++ b/clientapi/routing/joinroom.go @@ -15,6 +15,7 @@ package routing import ( + "errors" "net/http" "github.com/matrix-org/dendrite/clientapi/httputil" @@ -62,11 +63,32 @@ func JoinRoomByIDOrAlias( } // Ask the roomserver to perform the join. - if err := rsAPI.PerformJoin(req.Context(), &joinReq, &joinRes); err != nil { + err = rsAPI.PerformJoin(req.Context(), &joinReq, &joinRes) + // Handle known errors first, if this is 0 then there will be no matches (eg on success) + switch joinRes.Error { + case roomserverAPI.JoinErrorBadRequest: return util.JSONResponse{ Code: http.StatusBadRequest, - JSON: jsonerror.Unknown(err.Error()), + JSON: jsonerror.Unknown(joinRes.ErrMsg), } + case roomserverAPI.JoinErrorNoRoom: + return util.JSONResponse{ + Code: http.StatusNotFound, + JSON: jsonerror.NotFound(joinRes.ErrMsg), + } + case roomserverAPI.JoinErrorNotAllowed: + return util.JSONResponse{ + Code: http.StatusForbidden, + JSON: jsonerror.Forbidden(joinRes.ErrMsg), + } + } + // this is always populated on generic errors + if joinRes.ErrMsg != "" { + return util.ErrorResponse(errors.New(joinRes.ErrMsg)) + } + // this is set on network errors in polylith mode + if err != nil { + return util.ErrorResponse(err) } return util.JSONResponse{ diff --git a/roomserver/api/perform.go b/roomserver/api/perform.go index 3e5cae1b6..0f5394c94 100644 --- a/roomserver/api/perform.go +++ b/roomserver/api/perform.go @@ -5,6 +5,17 @@ import ( "github.com/matrix-org/util" ) +type JoinError int + +const ( + // JoinErrorNotAllowed means the user is not allowed to join this room (e.g join_rule:invite or banned) + JoinErrorNotAllowed JoinError = 1 + // JoinErrorBadRequest means the request was wrong in some way (invalid user ID, wrong server, etc) + JoinErrorBadRequest JoinError = 2 + // JoinErrorNoRoom means that the room being joined doesn't exist. + JoinErrorNoRoom JoinError = 3 +) + type PerformJoinRequest struct { RoomIDOrAlias string `json:"room_id_or_alias"` UserID string `json:"user_id"` @@ -13,7 +24,12 @@ type PerformJoinRequest struct { } type PerformJoinResponse struct { + // The room ID, populated on success. RoomID string `json:"room_id"` + // The reason why the join failed. Can be blank. + Error JoinError `json:"error"` + // Debugging description of the error. Always present on failure. + ErrMsg string `json:"err_msg"` } type PerformLeaveRequest struct { diff --git a/roomserver/internal/perform_join.go b/roomserver/internal/perform_join.go index 1c951bb15..44f842404 100644 --- a/roomserver/internal/perform_join.go +++ b/roomserver/internal/perform_join.go @@ -2,6 +2,7 @@ package internal import ( "context" + "errors" "fmt" "strings" "time" @@ -21,9 +22,11 @@ func (r *RoomserverInternalAPI) PerformJoin( ) error { _, domain, err := gomatrixserverlib.SplitID('@', req.UserID) if err != nil { + res.Error = api.JoinErrorBadRequest return fmt.Errorf("Supplied user ID %q in incorrect format", req.UserID) } if domain != r.Cfg.Matrix.ServerName { + res.Error = api.JoinErrorBadRequest return fmt.Errorf("User %q does not belong to this homeserver", req.UserID) } if strings.HasPrefix(req.RoomIDOrAlias, "!") { @@ -32,6 +35,7 @@ func (r *RoomserverInternalAPI) PerformJoin( if strings.HasPrefix(req.RoomIDOrAlias, "#") { return r.performJoinRoomByAlias(ctx, req, res) } + res.Error = api.JoinErrorBadRequest return fmt.Errorf("Room ID or alias %q is invalid", req.RoomIDOrAlias) } @@ -99,6 +103,7 @@ func (r *RoomserverInternalAPI) performJoinRoomByID( // Get the domain part of the room ID. _, domain, err := gomatrixserverlib.SplitID('!', req.RoomIDOrAlias) if err != nil { + res.Error = api.JoinErrorBadRequest return fmt.Errorf("Room ID %q is invalid", req.RoomIDOrAlias) } req.ServerNames = append(req.ServerNames, domain) @@ -198,6 +203,10 @@ func (r *RoomserverInternalAPI) performJoinRoomByID( } inputRes := api.InputRoomEventsResponse{} if err = r.InputRoomEvents(ctx, &inputReq, &inputRes); err != nil { + var notAllowed *gomatrixserverlib.NotAllowed + if errors.As(err, ¬Allowed) { + res.Error = api.JoinErrorNotAllowed + } return fmt.Errorf("r.InputRoomEvents: %w", err) } } @@ -207,6 +216,7 @@ func (r *RoomserverInternalAPI) performJoinRoomByID( // room. If it is then there's nothing more to do - the room just // hasn't been created yet. if domain == r.Cfg.Matrix.ServerName { + res.Error = api.JoinErrorNoRoom return fmt.Errorf("Room ID %q does not exist", req.RoomIDOrAlias) } diff --git a/roomserver/inthttp/server.go b/roomserver/inthttp/server.go index 822acd15b..e3b81daa5 100644 --- a/roomserver/inthttp/server.go +++ b/roomserver/inthttp/server.go @@ -34,7 +34,7 @@ func AddRoutes(r api.RoomserverInternalAPI, internalAPIMux *mux.Router) { return util.MessageResponse(http.StatusBadRequest, err.Error()) } if err := r.PerformJoin(req.Context(), &request, &response); err != nil { - return util.ErrorResponse(err) + response.ErrMsg = err.Error() } return util.JSONResponse{Code: http.StatusOK, JSON: &response} }),