diff --git a/clientapi/routing/admin.go b/clientapi/routing/admin.go index 4d2cea681..cc3c8e4ce 100644 --- a/clientapi/routing/admin.go +++ b/clientapi/routing/admin.go @@ -31,7 +31,7 @@ func AdminEvacuateRoom(req *http.Request, rsAPI roomserverAPI.ClientRoomserverAP } affected, err := rsAPI.PerformAdminEvacuateRoom(req.Context(), vars["roomID"]) - switch err { + switch err.(type) { case nil: case eventutil.ErrRoomNoExists: return util.JSONResponse{ @@ -231,10 +231,10 @@ func AdminDownloadState(req *http.Request, device *api.Device, rsAPI roomserverA } } if err = rsAPI.PerformAdminDownloadState(req.Context(), roomID, device.UserID, spec.ServerName(serverName)); err != nil { - if errors.Is(err, eventutil.ErrRoomNoExists) { + if errors.Is(err, eventutil.ErrRoomNoExists{}) { return util.JSONResponse{ Code: 200, - JSON: spec.NotFound(eventutil.ErrRoomNoExists.Error()), + JSON: spec.NotFound(err.Error()), } } logrus.WithError(err).WithFields(logrus.Fields{ diff --git a/clientapi/routing/joinroom.go b/clientapi/routing/joinroom.go index a67d51327..0c3801b51 100644 --- a/clientapi/routing/joinroom.go +++ b/clientapi/routing/joinroom.go @@ -16,7 +16,6 @@ package routing import ( "encoding/json" - "errors" "net/http" "time" @@ -114,17 +113,16 @@ func JoinRoomByIDOrAlias( Code: e.Code, JSON: json.RawMessage(e.Message), } + case eventutil.ErrRoomNoExists: + response = util.JSONResponse{ + Code: http.StatusNotFound, + JSON: spec.NotFound(e.Error()), + } default: response = util.JSONResponse{ Code: http.StatusInternalServerError, JSON: spec.InternalServerError(), } - if errors.Is(err, eventutil.ErrRoomNoExists) { - response = util.JSONResponse{ - Code: http.StatusNotFound, - JSON: spec.NotFound(e.Error()), - } - } } done <- response }() diff --git a/clientapi/routing/membership.go b/clientapi/routing/membership.go index 9b95ba5d8..029018171 100644 --- a/clientapi/routing/membership.go +++ b/clientapi/routing/membership.go @@ -398,28 +398,33 @@ func checkAndProcessThreepid( req.Context(), device, body, cfg, rsAPI, profileAPI, roomID, evTime, ) - if err == threepid.ErrMissingParameter { + switch e := err.(type) { + case nil: + case threepid.ErrMissingParameter: + util.GetLogger(req.Context()).WithError(err).Error("threepid.CheckAndProcessInvite failed") return inviteStored, &util.JSONResponse{ Code: http.StatusBadRequest, JSON: spec.BadJSON(err.Error()), } - } else if err == threepid.ErrNotTrusted { + case threepid.ErrNotTrusted: + util.GetLogger(req.Context()).WithError(err).Error("threepid.CheckAndProcessInvite failed") return inviteStored, &util.JSONResponse{ Code: http.StatusBadRequest, JSON: spec.NotTrusted(body.IDServer), } - } else if err == eventutil.ErrRoomNoExists { + case eventutil.ErrRoomNoExists: + util.GetLogger(req.Context()).WithError(err).Error("threepid.CheckAndProcessInvite failed") return inviteStored, &util.JSONResponse{ Code: http.StatusNotFound, JSON: spec.NotFound(err.Error()), } - } else if e, ok := err.(gomatrixserverlib.BadJSONError); ok { + case gomatrixserverlib.BadJSONError: + util.GetLogger(req.Context()).WithError(err).Error("threepid.CheckAndProcessInvite failed") return inviteStored, &util.JSONResponse{ Code: http.StatusBadRequest, JSON: spec.BadJSON(e.Error()), } - } - if err != nil { + default: util.GetLogger(req.Context()).WithError(err).Error("threepid.CheckAndProcessInvite failed") er := spec.InternalServerError() return inviteStored, &er diff --git a/clientapi/routing/redaction.go b/clientapi/routing/redaction.go index 12391d266..779de6e84 100644 --- a/clientapi/routing/redaction.go +++ b/clientapi/routing/redaction.go @@ -16,6 +16,7 @@ package routing import ( "context" + "errors" "net/http" "time" @@ -131,7 +132,7 @@ func SendRedaction( var queryRes roomserverAPI.QueryLatestEventsAndStateResponse e, err := eventutil.QueryAndBuildEvent(req.Context(), &proto, cfg.Matrix, identity, time.Now(), rsAPI, &queryRes) - if err == eventutil.ErrRoomNoExists { + if errors.Is(err, eventutil.ErrRoomNoExists{}) { return util.JSONResponse{ Code: http.StatusNotFound, JSON: spec.NotFound("Room does not exist"), diff --git a/clientapi/routing/sendevent.go b/clientapi/routing/sendevent.go index 2e3cd4112..685e39d8f 100644 --- a/clientapi/routing/sendevent.go +++ b/clientapi/routing/sendevent.go @@ -284,28 +284,30 @@ func generateSendEvent( var queryRes api.QueryLatestEventsAndStateResponse e, err := eventutil.QueryAndBuildEvent(ctx, &proto, cfg.Matrix, identity, evTime, rsAPI, &queryRes) - if err == eventutil.ErrRoomNoExists { + switch specificErr := err.(type) { + case nil: + case eventutil.ErrRoomNoExists: return nil, &util.JSONResponse{ Code: http.StatusNotFound, JSON: spec.NotFound("Room does not exist"), } - } else if e, ok := err.(gomatrixserverlib.BadJSONError); ok { + case gomatrixserverlib.BadJSONError: return nil, &util.JSONResponse{ Code: http.StatusBadRequest, - JSON: spec.BadJSON(e.Error()), + JSON: spec.BadJSON(specificErr.Error()), } - } else if e, ok := err.(gomatrixserverlib.EventValidationError); ok { - if e.Code == gomatrixserverlib.EventValidationTooLarge { + case gomatrixserverlib.EventValidationError: + if specificErr.Code == gomatrixserverlib.EventValidationTooLarge { return nil, &util.JSONResponse{ Code: http.StatusRequestEntityTooLarge, - JSON: spec.BadJSON(e.Error()), + JSON: spec.BadJSON(specificErr.Error()), } } return nil, &util.JSONResponse{ Code: http.StatusBadRequest, - JSON: spec.BadJSON(e.Error()), + JSON: spec.BadJSON(specificErr.Error()), } - } else if err != nil { + default: util.GetLogger(ctx).WithError(err).Error("eventutil.BuildEvent failed") resErr := spec.InternalServerError() return nil, &resErr diff --git a/clientapi/routing/threepid.go b/clientapi/routing/threepid.go index 64fa59e40..5802234cd 100644 --- a/clientapi/routing/threepid.go +++ b/clientapi/routing/threepid.go @@ -74,12 +74,15 @@ func RequestEmailToken(req *http.Request, threePIDAPI api.ClientUserAPI, cfg *co } resp.SID, err = threepid.CreateSession(req.Context(), body, cfg, client) - if err == threepid.ErrNotTrusted { + switch err.(type) { + case nil: + case threepid.ErrNotTrusted: + util.GetLogger(req.Context()).WithError(err).Error("threepid.CreateSession failed") return util.JSONResponse{ Code: http.StatusBadRequest, JSON: spec.NotTrusted(body.IDServer), } - } else if err != nil { + default: util.GetLogger(req.Context()).WithError(err).Error("threepid.CreateSession failed") return spec.InternalServerError() } @@ -102,12 +105,15 @@ func CheckAndSave3PIDAssociation( // Check if the association has been validated verified, address, medium, err := threepid.CheckAssociation(req.Context(), body.Creds, cfg, client) - if err == threepid.ErrNotTrusted { + switch err.(type) { + case nil: + case threepid.ErrNotTrusted: + util.GetLogger(req.Context()).WithError(err).Error("threepid.CheckAssociation failed") return util.JSONResponse{ Code: http.StatusBadRequest, JSON: spec.NotTrusted(body.Creds.IDServer), } - } else if err != nil { + default: util.GetLogger(req.Context()).WithError(err).Error("threepid.CheckAssociation failed") return spec.InternalServerError() } diff --git a/clientapi/routing/upgrade_room.go b/clientapi/routing/upgrade_room.go index 43f8d3e24..6ad35af86 100644 --- a/clientapi/routing/upgrade_room.go +++ b/clientapi/routing/upgrade_room.go @@ -68,7 +68,7 @@ func UpgradeRoom( JSON: spec.Forbidden(e.Error()), } default: - if errors.Is(err, eventutil.ErrRoomNoExists) { + if errors.Is(err, eventutil.ErrRoomNoExists{}) { return util.JSONResponse{ Code: http.StatusNotFound, JSON: spec.NotFound("Room does not exist"), diff --git a/clientapi/threepid/invites.go b/clientapi/threepid/invites.go index 2e9c1261e..c296939d5 100644 --- a/clientapi/threepid/invites.go +++ b/clientapi/threepid/invites.go @@ -64,14 +64,34 @@ type idServerStoreInviteResponse struct { } var ( - // ErrMissingParameter is the error raised if a request for 3PID invite has - // an incomplete body - ErrMissingParameter = errors.New("'address', 'id_server' and 'medium' must all be supplied") - // ErrNotTrusted is the error raised if an identity server isn't in the list - // of trusted servers in the configuration file. - ErrNotTrusted = errors.New("untrusted server") + errMissingParameter = fmt.Errorf("'address', 'id_server' and 'medium' must all be supplied") + errNotTrusted = fmt.Errorf("untrusted server") ) +// ErrMissingParameter is the error raised if a request for 3PID invite has +// an incomplete body +type ErrMissingParameter struct{} + +func (e ErrMissingParameter) Error() string { + return errMissingParameter.Error() +} + +func (e ErrMissingParameter) Unwrap() error { + return errMissingParameter +} + +// ErrNotTrusted is the error raised if an identity server isn't in the list +// of trusted servers in the configuration file. +type ErrNotTrusted struct{} + +func (e ErrNotTrusted) Error() string { + return errNotTrusted.Error() +} + +func (e ErrNotTrusted) Unwrap() error { + return errNotTrusted +} + // CheckAndProcessInvite analyses the body of an incoming membership request. // If the fields relative to a third-party-invite are all supplied, lookups the // matching Matrix ID from the given identity server. If no Matrix ID is @@ -99,7 +119,7 @@ func CheckAndProcessInvite( } else if body.Address == "" || body.IDServer == "" || body.Medium == "" { // If at least one of the 3PID-specific fields is supplied but not all // of them, return an error - err = ErrMissingParameter + err = ErrMissingParameter{} return } diff --git a/clientapi/threepid/threepid.go b/clientapi/threepid/threepid.go index 1fe573b1b..a5b5666fd 100644 --- a/clientapi/threepid/threepid.go +++ b/clientapi/threepid/threepid.go @@ -186,5 +186,5 @@ func isTrusted(idServer string, cfg *config.ClientAPI) error { return nil } } - return ErrNotTrusted + return ErrNotTrusted{} } diff --git a/federationapi/routing/join.go b/federationapi/routing/join.go index fc0f9eb0b..220292abc 100644 --- a/federationapi/routing/join.go +++ b/federationapi/routing/join.go @@ -119,20 +119,24 @@ func MakeJoin( RoomVersion: roomVersion, } event, err := eventutil.QueryAndBuildEvent(httpReq.Context(), proto, cfg.Matrix, identity, time.Now(), rsAPI, &queryRes) - if err == eventutil.ErrRoomNoExists { + switch e := err.(type) { + case nil: + case eventutil.ErrRoomNoExists: + util.GetLogger(httpReq.Context()).WithError(err).Error("eventutil.BuildEvent failed") return nil, nil, &util.JSONResponse{ Code: http.StatusNotFound, JSON: spec.NotFound("Room does not exist"), } - } else if e, ok := err.(gomatrixserverlib.BadJSONError); ok { + case gomatrixserverlib.BadJSONError: + util.GetLogger(httpReq.Context()).WithError(err).Error("eventutil.BuildEvent failed") return nil, nil, &util.JSONResponse{ Code: http.StatusBadRequest, JSON: spec.BadJSON(e.Error()), } - } else if err != nil { + default: util.GetLogger(httpReq.Context()).WithError(err).Error("eventutil.BuildEvent failed") - e := spec.InternalServerError() - return nil, nil, &e + internalErr := spec.InternalServerError() + return nil, nil, &internalErr } stateEvents := make([]gomatrixserverlib.PDU, len(queryRes.StateEvents)) diff --git a/federationapi/routing/leave.go b/federationapi/routing/leave.go index fdfbf15d7..c3443b9b8 100644 --- a/federationapi/routing/leave.go +++ b/federationapi/routing/leave.go @@ -75,17 +75,21 @@ func MakeLeave( var queryRes api.QueryLatestEventsAndStateResponse event, err := eventutil.QueryAndBuildEvent(httpReq.Context(), &proto, cfg.Matrix, identity, time.Now(), rsAPI, &queryRes) - if err == eventutil.ErrRoomNoExists { + switch e := err.(type) { + case nil: + case eventutil.ErrRoomNoExists: + util.GetLogger(httpReq.Context()).WithError(err).Error("eventutil.BuildEvent failed") return util.JSONResponse{ Code: http.StatusNotFound, JSON: spec.NotFound("Room does not exist"), } - } else if e, ok := err.(gomatrixserverlib.BadJSONError); ok { + case gomatrixserverlib.BadJSONError: + util.GetLogger(httpReq.Context()).WithError(err).Error("eventutil.BuildEvent failed") return util.JSONResponse{ Code: http.StatusBadRequest, JSON: spec.BadJSON(e.Error()), } - } else if err != nil { + default: util.GetLogger(httpReq.Context()).WithError(err).Error("eventutil.BuildEvent failed") return spec.InternalServerError() } diff --git a/internal/eventutil/events.go b/internal/eventutil/events.go index dff459684..79882d8d8 100644 --- a/internal/eventutil/events.go +++ b/internal/eventutil/events.go @@ -31,7 +31,17 @@ import ( // ErrRoomNoExists is returned when trying to lookup the state of a room that // doesn't exist -var ErrRoomNoExists = errors.New("room does not exist") +var errRoomNoExists = fmt.Errorf("room does not exist") + +type ErrRoomNoExists struct{} + +func (e ErrRoomNoExists) Error() string { + return errRoomNoExists.Error() +} + +func (e ErrRoomNoExists) Unwrap() error { + return errRoomNoExists +} // QueryAndBuildEvent builds a Matrix event using the event builder and roomserver query // API client provided. If also fills roomserver query API response (if provided) @@ -116,7 +126,7 @@ func addPrevEventsToEvent( queryRes *api.QueryLatestEventsAndStateResponse, ) error { if !queryRes.RoomExists { - return ErrRoomNoExists + return ErrRoomNoExists{} } verImpl, err := gomatrixserverlib.GetRoomVersion(queryRes.RoomVersion) diff --git a/roomserver/internal/perform/perform_admin.go b/roomserver/internal/perform/perform_admin.go index a539efd1d..fadc8bcfc 100644 --- a/roomserver/internal/perform/perform_admin.go +++ b/roomserver/internal/perform/perform_admin.go @@ -52,7 +52,7 @@ func (r *Admin) PerformAdminEvacuateRoom( return nil, err } if roomInfo == nil || roomInfo.IsStub() { - return nil, eventutil.ErrRoomNoExists + return nil, eventutil.ErrRoomNoExists{} } memberNIDs, err := r.DB.GetMembershipEventNIDsForRoom(ctx, roomInfo.RoomNID, true, true) @@ -240,7 +240,7 @@ func (r *Admin) PerformAdminDownloadState( } if roomInfo == nil || roomInfo.IsStub() { - return eventutil.ErrRoomNoExists + return eventutil.ErrRoomNoExists{} } fwdExtremities, _, depth, err := r.DB.LatestEventIDs(ctx, roomInfo.RoomNID) diff --git a/roomserver/internal/perform/perform_join.go b/roomserver/internal/perform/perform_join.go index a836eb1ae..bde844cb9 100644 --- a/roomserver/internal/perform/perform_join.go +++ b/roomserver/internal/perform/perform_join.go @@ -286,7 +286,7 @@ func (r *Joiner) performJoinRoomByID( } event, err := eventutil.QueryAndBuildEvent(ctx, &proto, r.Cfg.Matrix, identity, time.Now(), r.RSAPI, &buildRes) - switch err { + switch err.(type) { case nil: // The room join is local. Send the new join event into the // roomserver. First of all check that the user isn't already @@ -328,7 +328,7 @@ func (r *Joiner) performJoinRoomByID( // Otherwise we'll try a federated join as normal, since it's quite // possible that the room still exists on other servers. if len(req.ServerNames) == 0 { - return "", "", eventutil.ErrRoomNoExists + return "", "", eventutil.ErrRoomNoExists{} } } diff --git a/roomserver/internal/perform/perform_upgrade.go b/roomserver/internal/perform/perform_upgrade.go index e88cb1dcc..abe63145a 100644 --- a/roomserver/internal/perform/perform_upgrade.go +++ b/roomserver/internal/perform/perform_upgrade.go @@ -274,7 +274,7 @@ func publishNewRoomAndUnpublishOldRoom( func (r *Upgrader) validateRoomExists(ctx context.Context, roomID string) error { if _, err := r.URSAPI.QueryRoomVersionForRoom(ctx, roomID); err != nil { - return eventutil.ErrRoomNoExists + return eventutil.ErrRoomNoExists{} } return nil } @@ -556,15 +556,18 @@ func (r *Upgrader) makeHeaderedEvent(ctx context.Context, evTime time.Time, user } var queryRes api.QueryLatestEventsAndStateResponse headeredEvent, err := eventutil.QueryAndBuildEvent(ctx, &proto, r.Cfg.Matrix, identity, evTime, r.URSAPI, &queryRes) - if err == eventutil.ErrRoomNoExists { - return nil, err - } else if e, ok := err.(gomatrixserverlib.BadJSONError); ok { + switch e := err.(type) { + case nil: + case eventutil.ErrRoomNoExists: return nil, e - } else if e, ok := err.(gomatrixserverlib.EventValidationError); ok { + case gomatrixserverlib.BadJSONError: return nil, e - } else if err != nil { + case gomatrixserverlib.EventValidationError: + return nil, e + default: return nil, fmt.Errorf("failed to build new %q event: %w", proto.Type, err) } + // check to see if this user can perform this operation stateEvents := make([]gomatrixserverlib.PDU, len(queryRes.StateEvents)) for i := range queryRes.StateEvents {