diff --git a/clientapi/routing/createroom.go b/clientapi/routing/createroom.go index a07ef2f50..ebca78a47 100644 --- a/clientapi/routing/createroom.go +++ b/clientapi/routing/createroom.go @@ -22,6 +22,7 @@ import ( "strings" "time" + "github.com/getsentry/sentry-go" appserviceAPI "github.com/matrix-org/dendrite/appservice/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" roomserverVersion "github.com/matrix-org/dendrite/roomserver/version" @@ -556,23 +557,33 @@ func createRoom( fclient.NewInviteV2StrippedState(inviteEvent.Event), ) // Send the invite event to the roomserver. - var inviteRes roomserverAPI.PerformInviteResponse event := inviteEvent.Headered(roomVersion) - if err := rsAPI.PerformInvite(ctx, &roomserverAPI.PerformInviteRequest{ + err = rsAPI.PerformInvite(ctx, &roomserverAPI.PerformInviteRequest{ Event: event, InviteRoomState: inviteStrippedState, RoomVersion: event.RoomVersion, SendAsServer: string(userDomain), - }, &inviteRes); err != nil { + }) + switch e := err.(type) { + case roomserverAPI.ErrInvalidID: + return util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.Unknown(e.Error()), + } + case roomserverAPI.ErrNotAllowed: + return util.JSONResponse{ + Code: http.StatusForbidden, + JSON: jsonerror.Forbidden(e.Error()), + } + case nil: + default: util.GetLogger(ctx).WithError(err).Error("PerformInvite failed") + sentry.CaptureException(err) return util.JSONResponse{ Code: http.StatusInternalServerError, JSON: jsonerror.InternalServerError(), } } - if inviteRes.Error != nil { - return inviteRes.Error.JSONResponse() - } } } diff --git a/clientapi/routing/membership.go b/clientapi/routing/membership.go index 13de4d008..982e0feda 100644 --- a/clientapi/routing/membership.go +++ b/clientapi/routing/membership.go @@ -20,6 +20,7 @@ import ( "net/http" "time" + "github.com/getsentry/sentry-go" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" @@ -264,22 +265,33 @@ func sendInvite( return jsonerror.InternalServerError(), err } - var inviteRes api.PerformInviteResponse - if err := rsAPI.PerformInvite(ctx, &api.PerformInviteRequest{ + err = rsAPI.PerformInvite(ctx, &api.PerformInviteRequest{ Event: event, InviteRoomState: nil, // ask the roomserver to draw up invite room state for us RoomVersion: event.RoomVersion, SendAsServer: string(device.UserDomain()), - }, &inviteRes); err != nil { + }) + + switch e := err.(type) { + case roomserverAPI.ErrInvalidID: + return util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.Unknown(e.Error()), + }, e + case roomserverAPI.ErrNotAllowed: + return util.JSONResponse{ + Code: http.StatusForbidden, + JSON: jsonerror.Forbidden(e.Error()), + }, e + case nil: + default: util.GetLogger(ctx).WithError(err).Error("PerformInvite failed") + sentry.CaptureException(err) return util.JSONResponse{ Code: http.StatusInternalServerError, JSON: jsonerror.InternalServerError(), }, err } - if inviteRes.Error != nil { - return inviteRes.Error.JSONResponse(), inviteRes.Error - } return util.JSONResponse{ Code: http.StatusOK, diff --git a/federationapi/routing/invite.go b/federationapi/routing/invite.go index 880718922..421c5b2e4 100644 --- a/federationapi/routing/invite.go +++ b/federationapi/routing/invite.go @@ -20,6 +20,7 @@ import ( "fmt" "net/http" + "github.com/getsentry/sentry-go" "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/setup/config" @@ -204,17 +205,36 @@ func processInvite( SendAsServer: string(api.DoNotSendToOtherServers), TransactionID: nil, } - response := &api.PerformInviteResponse{} - if err := rsAPI.PerformInvite(ctx, request, response); err != nil { + + if err := rsAPI.PerformInvite(ctx, request); err != nil { util.GetLogger(ctx).WithError(err).Error("PerformInvite failed") return util.JSONResponse{ Code: http.StatusInternalServerError, JSON: jsonerror.InternalServerError(), } } - if response.Error != nil { - return response.Error.JSONResponse() + + switch e := err.(type) { + case api.ErrInvalidID: + return util.JSONResponse{ + Code: http.StatusBadRequest, + JSON: jsonerror.Unknown(e.Error()), + } + case api.ErrNotAllowed: + return util.JSONResponse{ + Code: http.StatusForbidden, + JSON: jsonerror.Forbidden(e.Error()), + } + case nil: + default: + util.GetLogger(ctx).WithError(err).Error("PerformInvite failed") + sentry.CaptureException(err) + return util.JSONResponse{ + Code: http.StatusInternalServerError, + JSON: jsonerror.InternalServerError(), + } } + // Return the signed event to the originating server, it should then tell // the other servers in the room that we have been invited. if isInviteV2 { diff --git a/roomserver/api/api.go b/roomserver/api/api.go index 5d06c59c9..a9a7fc865 100644 --- a/roomserver/api/api.go +++ b/roomserver/api/api.go @@ -11,6 +11,25 @@ import ( userapi "github.com/matrix-org/dendrite/userapi/api" ) +// ErrInvalidID is an error returned if the userID is invalid +type ErrInvalidID struct { + Err error +} + +func (e ErrInvalidID) Error() string { + return e.Err.Error() +} + +// ErrNotAllowed is an error returned if the user is not allowed +// to execute some action (e.g. invite) +type ErrNotAllowed struct { + Err error +} + +func (e ErrNotAllowed) Error() string { + return e.Err.Error() +} + // RoomserverInputAPI is used to write events to the room server. type RoomserverInternalAPI interface { SyncRoomserverAPI @@ -157,7 +176,7 @@ type ClientRoomserverAPI interface { PerformAdminDownloadState(ctx context.Context, roomID, userID string, serverName spec.ServerName) error PerformPeek(ctx context.Context, req *PerformPeekRequest, res *PerformPeekResponse) error PerformUnpeek(ctx context.Context, req *PerformUnpeekRequest, res *PerformUnpeekResponse) error - PerformInvite(ctx context.Context, req *PerformInviteRequest, res *PerformInviteResponse) error + PerformInvite(ctx context.Context, req *PerformInviteRequest) error PerformJoin(ctx context.Context, req *PerformJoinRequest, res *PerformJoinResponse) error PerformLeave(ctx context.Context, req *PerformLeaveRequest, res *PerformLeaveResponse) error PerformPublish(ctx context.Context, req *PerformPublishRequest, res *PerformPublishResponse) error @@ -202,7 +221,7 @@ type FederationRoomserverAPI interface { QueryRoomsForUser(ctx context.Context, req *QueryRoomsForUserRequest, res *QueryRoomsForUserResponse) error QueryRestrictedJoinAllowed(ctx context.Context, req *QueryRestrictedJoinAllowedRequest, res *QueryRestrictedJoinAllowedResponse) error PerformInboundPeek(ctx context.Context, req *PerformInboundPeekRequest, res *PerformInboundPeekResponse) error - PerformInvite(ctx context.Context, req *PerformInviteRequest, res *PerformInviteResponse) error + PerformInvite(ctx context.Context, req *PerformInviteRequest) error // Query a given amount (or less) of events prior to a given set of events. PerformBackfill(ctx context.Context, req *PerformBackfillRequest, res *PerformBackfillResponse) error } diff --git a/roomserver/api/perform.go b/roomserver/api/perform.go index 67d6e52f2..8d94b118f 100644 --- a/roomserver/api/perform.go +++ b/roomserver/api/perform.go @@ -112,10 +112,6 @@ type PerformInviteRequest struct { TransactionID *TransactionID `json:"transaction_id"` } -type PerformInviteResponse struct { - Error *PerformError -} - type PerformPeekRequest struct { RoomIDOrAlias string `json:"room_id_or_alias"` UserID string `json:"user_id"` diff --git a/roomserver/internal/api.go b/roomserver/internal/api.go index 975e77966..81904c8b8 100644 --- a/roomserver/internal/api.go +++ b/roomserver/internal/api.go @@ -209,11 +209,9 @@ func (r *RoomserverInternalAPI) SetAppserviceAPI(asAPI asAPI.AppServiceInternalA func (r *RoomserverInternalAPI) PerformInvite( ctx context.Context, req *api.PerformInviteRequest, - res *api.PerformInviteResponse, ) error { - outputEvents, err := r.Inviter.PerformInvite(ctx, req, res) + outputEvents, err := r.Inviter.PerformInvite(ctx, req) if err != nil { - sentry.CaptureException(err) return err } if len(outputEvents) == 0 { diff --git a/roomserver/internal/perform/perform_invite.go b/roomserver/internal/perform/perform_invite.go index a23cdea10..eb0134cfb 100644 --- a/roomserver/internal/perform/perform_invite.go +++ b/roomserver/internal/perform/perform_invite.go @@ -45,7 +45,6 @@ type Inviter struct { func (r *Inviter) PerformInvite( ctx context.Context, req *api.PerformInviteRequest, - res *api.PerformInviteResponse, ) ([]api.OutputEvent, error) { var outputUpdates []api.OutputEvent event := req.Event @@ -66,20 +65,12 @@ func (r *Inviter) PerformInvite( _, domain, err := gomatrixserverlib.SplitID('@', targetUserID) if err != nil { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: fmt.Sprintf("The user ID %q is invalid!", targetUserID), - } - return nil, nil + return nil, api.ErrInvalidID{Err: fmt.Errorf("the user ID %s is invalid", targetUserID)} } isTargetLocal := r.Cfg.Matrix.IsLocalServerName(domain) isOriginLocal := r.Cfg.Matrix.IsLocalServerName(senderDomain) if !isOriginLocal && !isTargetLocal { - res.Error = &api.PerformError{ - Code: api.PerformErrorBadRequest, - Msg: "The invite must be either from or to a local user", - } - return nil, nil + return nil, api.ErrInvalidID{Err: fmt.Errorf("the invite must be either from or to a local user")} } logger := util.GetLogger(ctx).WithFields(map[string]interface{}{ @@ -175,12 +166,8 @@ func (r *Inviter) PerformInvite( // For now we will implement option 2. Since in the abesence of a retry // mechanism it will be equivalent to option 1, and we don't have a // signalling mechanism to implement option 3. - res.Error = &api.PerformError{ - Code: api.PerformErrorNotAllowed, - Msg: "User is already joined to room", - } logger.Debugf("user already joined") - return nil, nil + return nil, api.ErrNotAllowed{Err: fmt.Errorf("user is already joined to room")} } // If the invite originated remotely then we can't send an @@ -201,11 +188,7 @@ func (r *Inviter) PerformInvite( logger.WithError(err).WithField("event_id", event.EventID()).WithField("auth_event_ids", event.AuthEventIDs()).Error( "processInviteEvent.checkAuthEvents failed for event", ) - res.Error = &api.PerformError{ - Msg: err.Error(), - Code: api.PerformErrorNotAllowed, - } - return nil, nil + return nil, api.ErrNotAllowed{Err: err} } // If the invite originated from us and the target isn't local then we @@ -220,12 +203,8 @@ func (r *Inviter) PerformInvite( } fsRes := &federationAPI.PerformInviteResponse{} if err = r.FSAPI.PerformInvite(ctx, fsReq, fsRes); err != nil { - res.Error = &api.PerformError{ - Msg: err.Error(), - Code: api.PerformErrorNotAllowed, - } logger.WithError(err).WithField("event_id", event.EventID()).Error("r.FSAPI.PerformInvite failed") - return nil, nil + return nil, api.ErrNotAllowed{Err: err} } event = fsRes.Event logger.Debugf("Federated PerformInvite success with event ID %s", event.EventID()) @@ -251,11 +230,8 @@ func (r *Inviter) PerformInvite( return nil, fmt.Errorf("r.Inputer.InputRoomEvents: %w", err) } if err = inputRes.Err(); err != nil { - res.Error = &api.PerformError{ - Msg: fmt.Sprintf("r.InputRoomEvents: %s", err.Error()), - Code: api.PerformErrorNotAllowed, - } logger.WithError(err).WithField("event_id", event.EventID()).Error("r.InputRoomEvents failed") + return nil, api.ErrNotAllowed{Err: err} } // Don't notify the sync api of this event in the same way as a federated invite so the invitee