aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--clientapi/routing/admin.go103
-rw-r--r--clientapi/routing/createroom.go42
-rw-r--r--clientapi/routing/directory.go22
-rw-r--r--clientapi/routing/joinroom.go64
-rw-r--r--clientapi/routing/membership.go24
-rw-r--r--clientapi/routing/peekroom.go56
-rw-r--r--clientapi/routing/routing.go6
-rw-r--r--clientapi/routing/upgrade_room.go36
-rw-r--r--federationapi/routing/invite.go28
-rw-r--r--roomserver/api/api.go45
-rw-r--r--roomserver/api/perform.go154
-rw-r--r--roomserver/internal/api.go4
-rw-r--r--roomserver/internal/perform/perform_admin.go251
-rw-r--r--roomserver/internal/perform/perform_invite.go36
-rw-r--r--roomserver/internal/perform/perform_join.go76
-rw-r--r--roomserver/internal/perform/perform_peek.go55
-rw-r--r--roomserver/internal/perform/perform_publish.go10
-rw-r--r--roomserver/internal/perform/perform_unpeek.go74
-rw-r--r--roomserver/internal/perform/perform_upgrade.go226
-rw-r--r--roomserver/roomserver_test.go27
-rw-r--r--roomserver/storage/interface.go2
-rw-r--r--userapi/internal/user_api.go23
22 files changed, 465 insertions, 899 deletions
diff --git a/clientapi/routing/admin.go b/clientapi/routing/admin.go
index 809d486d..a5fc4ec4 100644
--- a/clientapi/routing/admin.go
+++ b/clientapi/routing/admin.go
@@ -3,12 +3,14 @@ package routing
import (
"context"
"encoding/json"
+ "errors"
"fmt"
"net/http"
"time"
"github.com/gorilla/mux"
"github.com/matrix-org/dendrite/internal"
+ "github.com/matrix-org/dendrite/internal/eventutil"
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/gomatrixserverlib/spec"
"github.com/matrix-org/util"
@@ -28,88 +30,60 @@ func AdminEvacuateRoom(req *http.Request, rsAPI roomserverAPI.ClientRoomserverAP
if err != nil {
return util.ErrorResponse(err)
}
- res := &roomserverAPI.PerformAdminEvacuateRoomResponse{}
- if err := rsAPI.PerformAdminEvacuateRoom(
- req.Context(),
- &roomserverAPI.PerformAdminEvacuateRoomRequest{
- RoomID: vars["roomID"],
- },
- res,
- ); err != nil {
+
+ affected, err := rsAPI.PerformAdminEvacuateRoom(req.Context(), vars["roomID"])
+ switch err {
+ case nil:
+ case eventutil.ErrRoomNoExists:
+ return util.JSONResponse{
+ Code: http.StatusNotFound,
+ JSON: jsonerror.NotFound(err.Error()),
+ }
+ default:
+ logrus.WithError(err).WithField("roomID", vars["roomID"]).Error("Failed to evacuate room")
return util.ErrorResponse(err)
}
- if err := res.Error; err != nil {
- return err.JSONResponse()
- }
return util.JSONResponse{
Code: 200,
JSON: map[string]interface{}{
- "affected": res.Affected,
+ "affected": affected,
},
}
}
-func AdminEvacuateUser(req *http.Request, cfg *config.ClientAPI, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse {
+func AdminEvacuateUser(req *http.Request, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse {
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
if err != nil {
return util.ErrorResponse(err)
}
- userID := vars["userID"]
- _, domain, err := gomatrixserverlib.SplitID('@', userID)
+ affected, err := rsAPI.PerformAdminEvacuateUser(req.Context(), vars["userID"])
if err != nil {
+ logrus.WithError(err).WithField("userID", vars["userID"]).Error("Failed to evacuate user")
return util.MessageResponse(http.StatusBadRequest, err.Error())
}
- if !cfg.Matrix.IsLocalServerName(domain) {
- return util.JSONResponse{
- Code: http.StatusBadRequest,
- JSON: jsonerror.MissingArgument("User ID must belong to this server."),
- }
- }
- res := &roomserverAPI.PerformAdminEvacuateUserResponse{}
- if err := rsAPI.PerformAdminEvacuateUser(
- req.Context(),
- &roomserverAPI.PerformAdminEvacuateUserRequest{
- UserID: userID,
- },
- res,
- ); err != nil {
- return jsonerror.InternalAPIError(req.Context(), err)
- }
- if err := res.Error; err != nil {
- return err.JSONResponse()
- }
+
return util.JSONResponse{
Code: 200,
JSON: map[string]interface{}{
- "affected": res.Affected,
+ "affected": affected,
},
}
}
-func AdminPurgeRoom(req *http.Request, cfg *config.ClientAPI, device *api.Device, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse {
+func AdminPurgeRoom(req *http.Request, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse {
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
if err != nil {
return util.ErrorResponse(err)
}
- roomID := vars["roomID"]
- res := &roomserverAPI.PerformAdminPurgeRoomResponse{}
- if err := rsAPI.PerformAdminPurgeRoom(
- context.Background(),
- &roomserverAPI.PerformAdminPurgeRoomRequest{
- RoomID: roomID,
- },
- res,
- ); err != nil {
+ if err = rsAPI.PerformAdminPurgeRoom(context.Background(), vars["roomID"]); err != nil {
return util.ErrorResponse(err)
}
- if err := res.Error; err != nil {
- return err.JSONResponse()
- }
+
return util.JSONResponse{
Code: 200,
- JSON: res,
+ JSON: struct{}{},
}
}
@@ -238,7 +212,7 @@ func AdminMarkAsStale(req *http.Request, cfg *config.ClientAPI, keyAPI api.Clien
}
}
-func AdminDownloadState(req *http.Request, cfg *config.ClientAPI, device *api.Device, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse {
+func AdminDownloadState(req *http.Request, device *api.Device, rsAPI roomserverAPI.ClientRoomserverAPI) util.JSONResponse {
vars, err := httputil.URLDecodeMapValues(mux.Vars(req))
if err != nil {
return util.ErrorResponse(err)
@@ -257,23 +231,22 @@ func AdminDownloadState(req *http.Request, cfg *config.ClientAPI, device *api.De
JSON: jsonerror.MissingArgument("Expecting remote server name."),
}
}
- res := &roomserverAPI.PerformAdminDownloadStateResponse{}
- if err := rsAPI.PerformAdminDownloadState(
- req.Context(),
- &roomserverAPI.PerformAdminDownloadStateRequest{
- UserID: device.UserID,
- RoomID: roomID,
- ServerName: spec.ServerName(serverName),
- },
- res,
- ); err != nil {
- return jsonerror.InternalAPIError(req.Context(), err)
- }
- if err := res.Error; err != nil {
- return err.JSONResponse()
+ if err = rsAPI.PerformAdminDownloadState(req.Context(), roomID, device.UserID, spec.ServerName(serverName)); err != nil {
+ if errors.Is(err, eventutil.ErrRoomNoExists) {
+ return util.JSONResponse{
+ Code: 200,
+ JSON: jsonerror.NotFound(eventutil.ErrRoomNoExists.Error()),
+ }
+ }
+ logrus.WithError(err).WithFields(logrus.Fields{
+ "userID": device.UserID,
+ "serverName": serverName,
+ "roomID": roomID,
+ }).Error("failed to download state")
+ return util.ErrorResponse(err)
}
return util.JSONResponse{
Code: 200,
- JSON: map[string]interface{}{},
+ JSON: struct{}{},
}
}
diff --git a/clientapi/routing/createroom.go b/clientapi/routing/createroom.go
index 3962dccc..518daece 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"
"github.com/matrix-org/dendrite/roomserver/types"
@@ -544,9 +545,10 @@ func createRoom(
}
// Process the invites.
+ var inviteEvent *types.HeaderedEvent
for _, invitee := range r.Invite {
// Build the invite event.
- inviteEvent, err := buildMembershipEvent(
+ inviteEvent, err = buildMembershipEvent(
ctx, invitee, "", profileAPI, device, spec.Invite,
roomID, r.IsDirect, cfg, evTime, rsAPI, asAPI,
)
@@ -559,38 +561,44 @@ func createRoom(
fclient.NewInviteV2StrippedState(inviteEvent.Event),
)
// Send the invite event to the roomserver.
- var inviteRes roomserverAPI.PerformInviteResponse
event := inviteEvent
- if err := rsAPI.PerformInvite(ctx, &roomserverAPI.PerformInviteRequest{
+ err = rsAPI.PerformInvite(ctx, &roomserverAPI.PerformInviteRequest{
Event: event,
InviteRoomState: inviteStrippedState,
RoomVersion: event.Version(),
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()
- }
}
}
- if r.Visibility == "public" {
+ if r.Visibility == spec.Public {
// expose this room in the published room list
- var pubRes roomserverAPI.PerformPublishResponse
- if err := rsAPI.PerformPublish(ctx, &roomserverAPI.PerformPublishRequest{
+ if err = rsAPI.PerformPublish(ctx, &roomserverAPI.PerformPublishRequest{
RoomID: roomID,
- Visibility: "public",
- }, &pubRes); err != nil {
- return jsonerror.InternalAPIError(ctx, err)
- }
- if pubRes.Error != nil {
- // treat as non-fatal since the room is already made by this point
- util.GetLogger(ctx).WithError(pubRes.Error).Error("failed to visibility:public")
+ Visibility: spec.Public,
+ }); err != nil {
+ util.GetLogger(ctx).WithError(err).Error("failed to publish room")
+ return jsonerror.InternalServerError()
}
}
diff --git a/clientapi/routing/directory.go b/clientapi/routing/directory.go
index 9dd2d7cd..a8bf019b 100644
--- a/clientapi/routing/directory.go
+++ b/clientapi/routing/directory.go
@@ -304,16 +304,12 @@ func SetVisibility(
return *reqErr
}
- var publishRes roomserverAPI.PerformPublishResponse
- if err := rsAPI.PerformPublish(req.Context(), &roomserverAPI.PerformPublishRequest{
+ if err = rsAPI.PerformPublish(req.Context(), &roomserverAPI.PerformPublishRequest{
RoomID: roomID,
Visibility: v.Visibility,
- }, &publishRes); err != nil {
- return jsonerror.InternalAPIError(req.Context(), err)
- }
- if publishRes.Error != nil {
- util.GetLogger(req.Context()).WithError(publishRes.Error).Error("PerformPublish failed")
- return publishRes.Error.JSONResponse()
+ }); err != nil {
+ util.GetLogger(req.Context()).WithError(err).Error("failed to publish room")
+ return jsonerror.InternalServerError()
}
return util.JSONResponse{
@@ -342,18 +338,14 @@ func SetVisibilityAS(
return *reqErr
}
}
- var publishRes roomserverAPI.PerformPublishResponse
if err := rsAPI.PerformPublish(req.Context(), &roomserverAPI.PerformPublishRequest{
RoomID: roomID,
Visibility: v.Visibility,
NetworkID: networkID,
AppserviceID: dev.AppserviceID,
- }, &publishRes); err != nil {
- return jsonerror.InternalAPIError(req.Context(), err)
- }
- if publishRes.Error != nil {
- util.GetLogger(req.Context()).WithError(publishRes.Error).Error("PerformPublish failed")
- return publishRes.Error.JSONResponse()
+ }); err != nil {
+ util.GetLogger(req.Context()).WithError(err).Error("failed to publish room")
+ return jsonerror.InternalServerError()
}
return util.JSONResponse{
diff --git a/clientapi/routing/joinroom.go b/clientapi/routing/joinroom.go
index d736a958..54a9aaa4 100644
--- a/clientapi/routing/joinroom.go
+++ b/clientapi/routing/joinroom.go
@@ -15,14 +15,18 @@
package routing
import (
+ "encoding/json"
+ "errors"
"net/http"
"time"
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
"github.com/matrix-org/dendrite/clientapi/httputil"
"github.com/matrix-org/dendrite/clientapi/jsonerror"
+ "github.com/matrix-org/dendrite/internal/eventutil"
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/userapi/api"
+ "github.com/matrix-org/gomatrix"
"github.com/matrix-org/gomatrixserverlib/spec"
"github.com/matrix-org/util"
)
@@ -41,7 +45,6 @@ func JoinRoomByIDOrAlias(
IsGuest: device.AccountType == api.AccountTypeGuest,
Content: map[string]interface{}{},
}
- joinRes := roomserverAPI.PerformJoinResponse{}
// Check to see if any ?server_name= query parameters were
// given in the request.
@@ -81,37 +84,66 @@ func JoinRoomByIDOrAlias(
done := make(chan util.JSONResponse, 1)
go func() {
defer close(done)
- if err := rsAPI.PerformJoin(req.Context(), &joinReq, &joinRes); err != nil {
- done <- jsonerror.InternalAPIError(req.Context(), err)
- } else if joinRes.Error != nil {
- if joinRes.Error.Code == roomserverAPI.PerformErrorNotAllowed && device.AccountType == api.AccountTypeGuest {
- done <- util.JSONResponse{
- Code: http.StatusForbidden,
- JSON: jsonerror.GuestAccessForbidden(joinRes.Error.Msg),
- }
- } else {
- done <- joinRes.Error.JSONResponse()
- }
- } else {
- done <- util.JSONResponse{
+ roomID, _, err := rsAPI.PerformJoin(req.Context(), &joinReq)
+ var response util.JSONResponse
+
+ switch e := err.(type) {
+ case nil: // success case
+ response = util.JSONResponse{
Code: http.StatusOK,
// TODO: Put the response struct somewhere internal.
JSON: struct {
RoomID string `json:"room_id"`
- }{joinRes.RoomID},
+ }{roomID},
+ }
+ case roomserverAPI.ErrInvalidID:
+ response = util.JSONResponse{
+ Code: http.StatusBadRequest,
+ JSON: jsonerror.Unknown(e.Error()),
+ }
+ case roomserverAPI.ErrNotAllowed:
+ jsonErr := jsonerror.Forbidden(e.Error())
+ if device.AccountType == api.AccountTypeGuest {
+ jsonErr = jsonerror.GuestAccessForbidden(e.Error())
+ }
+ response = util.JSONResponse{
+ Code: http.StatusForbidden,
+ JSON: jsonErr,
+ }
+ case *gomatrix.HTTPError: // this ensures we proxy responses over federation to the client
+ response = util.JSONResponse{
+ Code: e.Code,
+ JSON: json.RawMessage(e.Message),
+ }
+ default:
+ response = util.JSONResponse{
+ Code: http.StatusInternalServerError,
+ JSON: jsonerror.InternalServerError(),
+ }
+ if errors.Is(err, eventutil.ErrRoomNoExists) {
+ response = util.JSONResponse{
+ Code: http.StatusNotFound,
+ JSON: jsonerror.NotFound(e.Error()),
+ }
}
}
+ done <- response
}()
// Wait either for the join to finish, or for us to hit a reasonable
// timeout, at which point we'll just return a 200 to placate clients.
+ timer := time.NewTimer(time.Second * 20)
select {
- case <-time.After(time.Second * 20):
+ case <-timer.C:
return util.JSONResponse{
Code: http.StatusAccepted,
JSON: jsonerror.Unknown("The room join will continue in the background."),
}
case result := <-done:
+ // Stop and drain the timer
+ if !timer.Stop() {
+ <-timer.C
+ }
return result
}
}
diff --git a/clientapi/routing/membership.go b/clientapi/routing/membership.go
index 827b5f29..a4aa963a 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"
@@ -265,22 +266,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.Version(),
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/clientapi/routing/peekroom.go b/clientapi/routing/peekroom.go
index 9a8f4378..3937b9ad 100644
--- a/clientapi/routing/peekroom.go
+++ b/clientapi/routing/peekroom.go
@@ -15,13 +15,16 @@
package routing
import (
+ "encoding/json"
"net/http"
"github.com/matrix-org/dendrite/clientapi/jsonerror"
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/userapi/api"
+ "github.com/matrix-org/gomatrix"
"github.com/matrix-org/gomatrixserverlib/spec"
"github.com/matrix-org/util"
+ "github.com/sirupsen/logrus"
)
func PeekRoomByIDOrAlias(
@@ -41,8 +44,6 @@ func PeekRoomByIDOrAlias(
UserID: device.UserID,
DeviceID: device.ID,
}
- peekRes := roomserverAPI.PerformPeekResponse{}
-
// Check to see if any ?server_name= query parameters were
// given in the request.
if serverNames, ok := req.URL.Query()["server_name"]; ok {
@@ -55,11 +56,27 @@ func PeekRoomByIDOrAlias(
}
// Ask the roomserver to perform the peek.
- if err := rsAPI.PerformPeek(req.Context(), &peekReq, &peekRes); err != nil {
- return util.ErrorResponse(err)
- }
- if peekRes.Error != nil {
- return peekRes.Error.JSONResponse()
+ roomID, err := rsAPI.PerformPeek(req.Context(), &peekReq)
+ 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 *gomatrix.HTTPError:
+ return util.JSONResponse{
+ Code: e.Code,
+ JSON: json.RawMessage(e.Message),
+ }
+ case nil:
+ default:
+ logrus.WithError(err).WithField("roomID", roomIDOrAlias).Errorf("Failed to peek room")
+ return jsonerror.InternalServerError()
}
// if this user is already joined to the room, we let them peek anyway
@@ -75,7 +92,7 @@ func PeekRoomByIDOrAlias(
// TODO: Put the response struct somewhere internal.
JSON: struct {
RoomID string `json:"room_id"`
- }{peekRes.RoomID},
+ }{roomID},
}
}
@@ -85,18 +102,17 @@ func UnpeekRoomByID(
rsAPI roomserverAPI.ClientRoomserverAPI,
roomID string,
) util.JSONResponse {
- unpeekReq := roomserverAPI.PerformUnpeekRequest{
- RoomID: roomID,
- UserID: device.UserID,
- DeviceID: device.ID,
- }
- unpeekRes := roomserverAPI.PerformUnpeekResponse{}
-
- if err := rsAPI.PerformUnpeek(req.Context(), &unpeekReq, &unpeekRes); err != nil {
- return jsonerror.InternalAPIError(req.Context(), err)
- }
- if unpeekRes.Error != nil {
- return unpeekRes.Error.JSONResponse()
+ err := rsAPI.PerformUnpeek(req.Context(), roomID, device.UserID, device.ID)
+ switch e := err.(type) {
+ case roomserverAPI.ErrInvalidID:
+ return util.JSONResponse{
+ Code: http.StatusBadRequest,
+ JSON: jsonerror.Unknown(e.Error()),
+ }
+ case nil:
+ default:
+ logrus.WithError(err).WithField("roomID", roomID).Errorf("Failed to un-peek room")
+ return jsonerror.InternalServerError()
}
return util.JSONResponse{
diff --git a/clientapi/routing/routing.go b/clientapi/routing/routing.go
index aa9b41fc..70299e14 100644
--- a/clientapi/routing/routing.go
+++ b/clientapi/routing/routing.go
@@ -162,13 +162,13 @@ func Setup(
dendriteAdminRouter.Handle("/admin/evacuateUser/{userID}",
httputil.MakeAdminAPI("admin_evacuate_user", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
- return AdminEvacuateUser(req, cfg, rsAPI)
+ return AdminEvacuateUser(req, rsAPI)
}),
).Methods(http.MethodPost, http.MethodOptions)
dendriteAdminRouter.Handle("/admin/purgeRoom/{roomID}",
httputil.MakeAdminAPI("admin_purge_room", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
- return AdminPurgeRoom(req, cfg, device, rsAPI)
+ return AdminPurgeRoom(req, rsAPI)
}),
).Methods(http.MethodPost, http.MethodOptions)
@@ -180,7 +180,7 @@ func Setup(
dendriteAdminRouter.Handle("/admin/downloadState/{serverName}/{roomID}",
httputil.MakeAdminAPI("admin_download_state", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {
- return AdminDownloadState(req, cfg, device, rsAPI)
+ return AdminDownloadState(req, device, rsAPI)
}),
).Methods(http.MethodGet, http.MethodOptions)
diff --git a/clientapi/routing/upgrade_room.go b/clientapi/routing/upgrade_room.go
index 34c7eb00..f0936db1f 100644
--- a/clientapi/routing/upgrade_room.go
+++ b/clientapi/routing/upgrade_room.go
@@ -15,11 +15,13 @@
package routing
import (
+ "errors"
"net/http"
appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
"github.com/matrix-org/dendrite/clientapi/httputil"
"github.com/matrix-org/dendrite/clientapi/jsonerror"
+ "github.com/matrix-org/dendrite/internal/eventutil"
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/roomserver/version"
"github.com/matrix-org/dendrite/setup/config"
@@ -57,38 +59,28 @@ func UpgradeRoom(
}
}
- upgradeReq := roomserverAPI.PerformRoomUpgradeRequest{
- UserID: device.UserID,
- RoomID: roomID,
- RoomVersion: gomatrixserverlib.RoomVersion(r.NewVersion),
- }
- upgradeResp := roomserverAPI.PerformRoomUpgradeResponse{}
-
- if err := rsAPI.PerformRoomUpgrade(req.Context(), &upgradeReq, &upgradeResp); err != nil {
- return jsonerror.InternalAPIError(req.Context(), err)
- }
-
- if upgradeResp.Error != nil {
- if upgradeResp.Error.Code == roomserverAPI.PerformErrorNoRoom {
+ newRoomID, err := rsAPI.PerformRoomUpgrade(req.Context(), roomID, device.UserID, gomatrixserverlib.RoomVersion(r.NewVersion))
+ switch e := err.(type) {
+ case nil:
+ case roomserverAPI.ErrNotAllowed:
+ return util.JSONResponse{
+ Code: http.StatusForbidden,
+ JSON: jsonerror.Forbidden(e.Error()),
+ }
+ default:
+ if errors.Is(err, eventutil.ErrRoomNoExists) {
return util.JSONResponse{
Code: http.StatusNotFound,
JSON: jsonerror.NotFound("Room does not exist"),
}
- } else if upgradeResp.Error.Code == roomserverAPI.PerformErrorNotAllowed {
- return util.JSONResponse{
- Code: http.StatusForbidden,
- JSON: jsonerror.Forbidden(upgradeResp.Error.Msg),
- }
- } else {
- return jsonerror.InternalServerError()
}
-
+ return jsonerror.InternalServerError()
}
return util.JSONResponse{
Code: http.StatusOK,
JSON: upgradeRoomResponse{
- ReplacementRoom: upgradeResp.NewRoomID,
+ ReplacementRoom: newRoomID,
},
}
}
diff --git a/federationapi/routing/invite.go b/federationapi/routing/invite.go
index a4ebeaed..6fa37f4a 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/roomserver/types"
@@ -205,17 +206,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 ae67a3d7..2aaecbbf 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
@@ -150,17 +169,17 @@ type ClientRoomserverAPI interface {
GetAliasesForRoomID(ctx context.Context, req *GetAliasesForRoomIDRequest, res *GetAliasesForRoomIDResponse) error
// PerformRoomUpgrade upgrades a room to a newer version
- PerformRoomUpgrade(ctx context.Context, req *PerformRoomUpgradeRequest, resp *PerformRoomUpgradeResponse) error
- PerformAdminEvacuateRoom(ctx context.Context, req *PerformAdminEvacuateRoomRequest, res *PerformAdminEvacuateRoomResponse) error
- PerformAdminEvacuateUser(ctx context.Context, req *PerformAdminEvacuateUserRequest, res *PerformAdminEvacuateUserResponse) error
- PerformAdminPurgeRoom(ctx context.Context, req *PerformAdminPurgeRoomRequest, res *PerformAdminPurgeRoomResponse) error
- PerformAdminDownloadState(ctx context.Context, req *PerformAdminDownloadStateRequest, res *PerformAdminDownloadStateResponse) 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
- PerformJoin(ctx context.Context, req *PerformJoinRequest, res *PerformJoinResponse) error
+ PerformRoomUpgrade(ctx context.Context, roomID, userID string, roomVersion gomatrixserverlib.RoomVersion) (newRoomID string, err error)
+ PerformAdminEvacuateRoom(ctx context.Context, roomID string) (affected []string, err error)
+ PerformAdminEvacuateUser(ctx context.Context, userID string) (affected []string, err error)
+ PerformAdminPurgeRoom(ctx context.Context, roomID string) error
+ PerformAdminDownloadState(ctx context.Context, roomID, userID string, serverName spec.ServerName) error
+ PerformPeek(ctx context.Context, req *PerformPeekRequest) (roomID string, err error)
+ PerformUnpeek(ctx context.Context, roomID, userID, deviceID string) error
+ PerformInvite(ctx context.Context, req *PerformInviteRequest) error
+ PerformJoin(ctx context.Context, req *PerformJoinRequest) (roomID string, joinedVia spec.ServerName, err error)
PerformLeave(ctx context.Context, req *PerformLeaveRequest, res *PerformLeaveResponse) error
- PerformPublish(ctx context.Context, req *PerformPublishRequest, res *PerformPublishResponse) error
+ PerformPublish(ctx context.Context, req *PerformPublishRequest) error
// PerformForget forgets a rooms history for a specific user
PerformForget(ctx context.Context, req *PerformForgetRequest, resp *PerformForgetResponse) error
SetRoomAlias(ctx context.Context, req *SetRoomAliasRequest, res *SetRoomAliasResponse) error
@@ -172,8 +191,8 @@ type UserRoomserverAPI interface {
KeyserverRoomserverAPI
QueryCurrentState(ctx context.Context, req *QueryCurrentStateRequest, res *QueryCurrentStateResponse) error
QueryMembershipsForRoom(ctx context.Context, req *QueryMembershipsForRoomRequest, res *QueryMembershipsForRoomResponse) error
- PerformAdminEvacuateUser(ctx context.Context, req *PerformAdminEvacuateUserRequest, res *PerformAdminEvacuateUserResponse) error
- PerformJoin(ctx context.Context, req *PerformJoinRequest, res *PerformJoinResponse) error
+ PerformAdminEvacuateUser(ctx context.Context, userID string) (affected []string, err error)
+ PerformJoin(ctx context.Context, req *PerformJoinRequest) (roomID string, joinedVia spec.ServerName, err error)
}
type FederationRoomserverAPI interface {
@@ -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 218a39a0..c6e5f5a1 100644
--- a/roomserver/api/perform.go
+++ b/roomserver/api/perform.go
@@ -1,81 +1,11 @@
package api
import (
- "encoding/json"
- "fmt"
- "net/http"
-
+ "github.com/matrix-org/dendrite/roomserver/types"
"github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/gomatrixserverlib/fclient"
"github.com/matrix-org/gomatrixserverlib/spec"
"github.com/matrix-org/util"
-
- "github.com/matrix-org/dendrite/clientapi/jsonerror"
- "github.com/matrix-org/dendrite/roomserver/types"
-)
-
-type PerformErrorCode int
-
-type PerformError struct {
- Msg string
- RemoteCode int // remote HTTP status code, for PerformErrRemote
- Code PerformErrorCode
-}
-
-func (p *PerformError) Error() string {
- return fmt.Sprintf("%d : %s", p.Code, p.Msg)
-}
-
-// JSONResponse maps error codes to suitable HTTP error codes, defaulting to 500.
-func (p *PerformError) JSONResponse() util.JSONResponse {
- switch p.Code {
- case PerformErrorBadRequest:
- return util.JSONResponse{
- Code: http.StatusBadRequest,
- JSON: jsonerror.Unknown(p.Msg),
- }
- case PerformErrorNoRoom:
- return util.JSONResponse{
- Code: http.StatusNotFound,
- JSON: jsonerror.NotFound(p.Msg),
- }
- case PerformErrorNotAllowed:
- return util.JSONResponse{
- Code: http.StatusForbidden,
- JSON: jsonerror.Forbidden(p.Msg),
- }
- case PerformErrorNoOperation:
- return util.JSONResponse{
- Code: http.StatusForbidden,
- JSON: jsonerror.Forbidden(p.Msg),
- }
- case PerformErrRemote:
- // if the code is 0 then something bad happened and it isn't
- // a remote HTTP error being encapsulated, e.g network error to remote.
- if p.RemoteCode == 0 {
- return util.ErrorResponse(fmt.Errorf("%s", p.Msg))
- }
- return util.JSONResponse{
- Code: p.RemoteCode,
- // TODO: Should we assert this is in fact JSON? E.g gjson parse?
- JSON: json.RawMessage(p.Msg),
- }
- default:
- return util.ErrorResponse(p)
- }
-}
-
-const (
- // PerformErrorNotAllowed means the user is not allowed to invite/join/etc this room (e.g join_rule:invite or banned)
- PerformErrorNotAllowed PerformErrorCode = 1
- // PerformErrorBadRequest means the request was wrong in some way (invalid user ID, wrong server, etc)
- PerformErrorBadRequest PerformErrorCode = 2
- // PerformErrorNoRoom means that the room being joined doesn't exist.
- PerformErrorNoRoom PerformErrorCode = 3
- // PerformErrorNoOperation means that the request resulted in nothing happening e.g invite->invite or leave->leave.
- PerformErrorNoOperation PerformErrorCode = 4
- // PerformErrRemote means that the request failed and the PerformError.Msg is the raw remote JSON error response
- PerformErrRemote PerformErrorCode = 5
)
type PerformJoinRequest struct {
@@ -87,14 +17,6 @@ type PerformJoinRequest struct {
Unsigned map[string]interface{} `json:"unsigned"`
}
-type PerformJoinResponse struct {
- // The room ID, populated on success.
- RoomID string `json:"room_id"`
- JoinedVia spec.ServerName
- // If non-nil, the join request failed. Contains more information why it failed.
- Error *PerformError
-}
-
type PerformLeaveRequest struct {
RoomID string `json:"room_id"`
UserID string `json:"user_id"`
@@ -113,10 +35,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"`
@@ -124,24 +42,6 @@ type PerformPeekRequest struct {
ServerNames []spec.ServerName `json:"server_names"`
}
-type PerformPeekResponse struct {
- // The room ID, populated on success.
- RoomID string `json:"room_id"`
- // If non-nil, the join request failed. Contains more information why it failed.
- Error *PerformError
-}
-
-type PerformUnpeekRequest struct {
- RoomID string `json:"room_id"`
- UserID string `json:"user_id"`
- DeviceID string `json:"device_id"`
-}
-
-type PerformUnpeekResponse struct {
- // If non-nil, the join request failed. Contains more information why it failed.
- Error *PerformError
-}
-
// PerformBackfillRequest is a request to PerformBackfill.
type PerformBackfillRequest struct {
// The room to backfill
@@ -180,11 +80,6 @@ type PerformPublishRequest struct {
NetworkID string
}
-type PerformPublishResponse struct {
- // If non-nil, the publish request failed. Contains more information why it failed.
- Error *PerformError
-}
-
type PerformInboundPeekRequest struct {
UserID string `json:"user_id"`
RoomID string `json:"room_id"`
@@ -214,50 +109,3 @@ type PerformForgetRequest struct {
}
type PerformForgetResponse struct{}
-
-type PerformRoomUpgradeRequest struct {
- RoomID string `json:"room_id"`
- UserID string `json:"user_id"`
- RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"`
-}
-
-type PerformRoomUpgradeResponse struct {
- NewRoomID string
- Error *PerformError
-}
-
-type PerformAdminEvacuateRoomRequest struct {
- RoomID string `json:"room_id"`
-}
-
-type PerformAdminEvacuateRoomResponse struct {
- Affected []string `json:"affected"`
- Error *PerformError
-}
-
-type PerformAdminEvacuateUserRequest struct {
- UserID string `json:"user_id"`
-}
-
-type PerformAdminEvacuateUserResponse struct {
- Affected []string `json:"affected"`
- Error *PerformError
-}
-
-type PerformAdminPurgeRoomRequest struct {
- RoomID string `json:"room_id"`
-}
-
-type PerformAdminPurgeRoomResponse struct {
- Error *PerformError `json:"error,omitempty"`
-}
-
-type PerformAdminDownloadStateRequest struct {
- RoomID string `json:"room_id"`
- UserID string `json:"user_id"`
- ServerName spec.ServerName `json:"server_name"`
-}
-
-type PerformAdminDownloadStateResponse struct {
- Error *PerformError `json:"error,omitempty"`
-}
diff --git a/roomserver/internal/api.go b/roomserver/internal/api.go
index 975e7796..81904c8b 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_admin.go b/roomserver/internal/perform/perform_admin.go
index e08f3d61..050e5a62 100644
--- a/roomserver/internal/perform/perform_admin.go
+++ b/roomserver/internal/perform/perform_admin.go
@@ -29,6 +29,7 @@ import (
"github.com/matrix-org/dendrite/roomserver/types"
"github.com/matrix-org/dendrite/setup/config"
"github.com/matrix-org/gomatrixserverlib"
+ "github.com/matrix-org/gomatrixserverlib/fclient"
"github.com/matrix-org/gomatrixserverlib/spec"
"github.com/sirupsen/logrus"
)
@@ -41,61 +42,44 @@ type Admin struct {
Leaver *Leaver
}
-// PerformEvacuateRoom will remove all local users from the given room.
+// PerformAdminEvacuateRoom will remove all local users from the given room.
func (r *Admin) PerformAdminEvacuateRoom(
ctx context.Context,
- req *api.PerformAdminEvacuateRoomRequest,
- res *api.PerformAdminEvacuateRoomResponse,
-) error {
- roomInfo, err := r.DB.RoomInfo(ctx, req.RoomID)
+ roomID string,
+) (affected []string, err error) {
+ roomInfo, err := r.DB.RoomInfo(ctx, roomID)
if err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("r.DB.RoomInfo: %s", err),
- }
- return nil
+ return nil, err
}
if roomInfo == nil || roomInfo.IsStub() {
- res.Error = &api.PerformError{
- Code: api.PerformErrorNoRoom,
- Msg: fmt.Sprintf("Room %s not found", req.RoomID),
- }
- return nil
+ return nil, eventutil.ErrRoomNoExists
}
memberNIDs, err := r.DB.GetMembershipEventNIDsForRoom(ctx, roomInfo.RoomNID, true, true)
if err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("r.DB.GetMembershipEventNIDsForRoom: %s", err),
- }
- return nil
+ return nil, err
}
memberEvents, err := r.DB.Events(ctx, roomInfo, memberNIDs)
if err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("r.DB.Events: %s", err),
- }
- return nil
+ return nil, err
}
inputEvents := make([]api.InputRoomEvent, 0, len(memberEvents))
- res.Affected = make([]string, 0, len(memberEvents))
+ affected = make([]string, 0, len(memberEvents))
latestReq := &api.QueryLatestEventsAndStateRequest{
- RoomID: req.RoomID,
+ RoomID: roomID,
}
latestRes := &api.QueryLatestEventsAndStateResponse{}
if err = r.Queryer.QueryLatestEventsAndState(ctx, latestReq, latestRes); err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("r.Queryer.QueryLatestEventsAndState: %s", err),
- }
- return nil
+ return nil, err
}
prevEvents := latestRes.LatestEvents
+ var senderDomain spec.ServerName
+ var eventsNeeded gomatrixserverlib.StateNeeded
+ var identity *fclient.SigningIdentity
+ var event *types.HeaderedEvent
for _, memberEvent := range memberEvents {
if memberEvent.StateKey() == nil {
continue
@@ -103,57 +87,41 @@ func (r *Admin) PerformAdminEvacuateRoom(
var memberContent gomatrixserverlib.MemberContent
if err = json.Unmarshal(memberEvent.Content(), &memberContent); err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("json.Unmarshal: %s", err),
- }
- return nil
+ return nil, err
}
memberContent.Membership = spec.Leave
stateKey := *memberEvent.StateKey()
fledglingEvent := &gomatrixserverlib.EventBuilder{
- RoomID: req.RoomID,
+ RoomID: roomID,
Type: spec.MRoomMember,
StateKey: &stateKey,
Sender: stateKey,
PrevEvents: prevEvents,
}
- _, senderDomain, err := gomatrixserverlib.SplitID('@', fledglingEvent.Sender)
+ _, senderDomain, err = gomatrixserverlib.SplitID('@', fledglingEvent.Sender)
if err != nil {
continue
}
if fledglingEvent.Content, err = json.Marshal(memberContent); err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("json.Marshal: %s", err),
- }
- return nil
+ return nil, err
}
- eventsNeeded, err := gomatrixserverlib.StateNeededForEventBuilder(fledglingEvent)
+ eventsNeeded, err = gomatrixserverlib.StateNeededForEventBuilder(fledglingEvent)
if err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("gomatrixserverlib.StateNeededForEventBuilder: %s", err),
- }
- return nil
+ return nil, err
}
- identity, err := r.Cfg.Matrix.SigningIdentityFor(senderDomain)
+ identity, err = r.Cfg.Matrix.SigningIdentityFor(senderDomain)
if err != nil {
continue
}
- event, err := eventutil.BuildEvent(ctx, fledglingEvent, r.Cfg.Matrix, identity, time.Now(), &eventsNeeded, latestRes)
+ event, err = eventutil.BuildEvent(ctx, fledglingEvent, r.Cfg.Matrix, identity, time.Now(), &eventsNeeded, latestRes)
if err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("eventutil.BuildEvent: %s", err),
- }
- return nil
+ return nil, err
}
inputEvents = append(inputEvents, api.InputRoomEvent{
@@ -162,7 +130,7 @@ func (r *Admin) PerformAdminEvacuateRoom(
Origin: senderDomain,
SendAsServer: string(senderDomain),
})
- res.Affected = append(res.Affected, stateKey)
+ affected = append(affected, stateKey)
prevEvents = []gomatrixserverlib.EventReference{
event.EventReference(),
}
@@ -173,108 +141,85 @@ func (r *Admin) PerformAdminEvacuateRoom(
Asynchronous: true,
}
inputRes := &api.InputRoomEventsResponse{}
- return r.Inputer.InputRoomEvents(ctx, inputReq, inputRes)
+ err = r.Inputer.InputRoomEvents(ctx, inputReq, inputRes)
+ return affected, err
}
+// PerformAdminEvacuateUser will remove the given user from all rooms.
func (r *Admin) PerformAdminEvacuateUser(
ctx context.Context,
- req *api.PerformAdminEvacuateUserRequest,
- res *api.PerformAdminEvacuateUserResponse,
-) error {
- _, domain, err := gomatrixserverlib.SplitID('@', req.UserID)
+ userID string,
+) (affected []string, err error) {
+ _, domain, err := gomatrixserverlib.SplitID('@', userID)
if err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("Malformed user ID: %s", err),
- }
- return nil
+ return nil, err
}
if !r.Cfg.Matrix.IsLocalServerName(domain) {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: "Can only evacuate local users using this endpoint",
- }
- return nil
+ return nil, fmt.Errorf("can only evacuate local users using this endpoint")
}
- roomIDs, err := r.DB.GetRoomsByMembership(ctx, req.UserID, spec.Join)
- if err != nil && err != sql.ErrNoRows {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("r.DB.GetRoomsByMembership: %s", err),
- }
- return nil
+ roomIDs, err := r.DB.GetRoomsByMembership(ctx, userID, spec.Join)
+ if err != nil {
+ return nil, err
}
- inviteRoomIDs, err := r.DB.GetRoomsByMembership(ctx, req.UserID, spec.Invite)
+ inviteRoomIDs, err := r.DB.GetRoomsByMembership(ctx, userID, spec.Invite)
if err != nil && err != sql.ErrNoRows {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("r.DB.GetRoomsByMembership: %s", err),
- }
- return nil
+ return nil, err
}
- for _, roomID := range append(roomIDs, inviteRoomIDs...) {
+ allRooms := append(roomIDs, inviteRoomIDs...)
+ affected = make([]string, 0, len(allRooms))
+ for _, roomID := range allRooms {
leaveReq := &api.PerformLeaveRequest{
RoomID: roomID,
- UserID: req.UserID,
+ UserID: userID,
}
leaveRes := &api.PerformLeaveResponse{}
outputEvents, err := r.Leaver.PerformLeave(ctx, leaveReq, leaveRes)
if err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("r.Leaver.PerformLeave: %s", err),
- }
- return nil
+ return nil, err
}
- res.Affected = append(res.Affected, roomID)
+ affected = append(affected, roomID)
if len(outputEvents) == 0 {
continue
}
if err := r.Inputer.OutputProducer.ProduceRoomEvents(roomID, outputEvents); err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("r.Inputer.WriteOutputEvents: %s", err),
- }
- return nil
+ return nil, err
}
}
- return nil
+ return affected, nil
}
+// PerformAdminPurgeRoom removes all traces for the given room from the database.
func (r *Admin) PerformAdminPurgeRoom(
ctx context.Context,
- req *api.PerformAdminPurgeRoomRequest,
- res *api.PerformAdminPurgeRoomResponse,
+ roomID string,
) error {
// Validate we actually got a room ID and nothing else
- if _, _, err := gomatrixserverlib.SplitID('!', req.RoomID); err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("Malformed room ID: %s", err),
- }
- return nil
+ if _, _, err := gomatrixserverlib.SplitID('!', roomID); err != nil {
+ return err
}
- logrus.WithField("room_id", req.RoomID).Warn("Purging room from roomserver")
- if err := r.DB.PurgeRoom(ctx, req.RoomID); err != nil {
- logrus.WithField("room_id", req.RoomID).WithError(err).Warn("Failed to purge room from roomserver")
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: err.Error(),
- }
- return nil
+ // Evacuate the room before purging it from the database
+ if _, err := r.PerformAdminEvacuateRoom(ctx, roomID); err != nil {
+ logrus.WithField("room_id", roomID).WithError(err).Warn("Failed to evacuate room before purging")
+ return err
+ }
+
+ logrus.WithField("room_id", roomID).Warn("Purging room from roomserver")
+ if err := r.DB.PurgeRoom(ctx, roomID); err != nil {
+ logrus.WithField("room_id", roomID).WithError(err).Warn("Failed to purge room from roomserver")
+ return err
}
- logrus.WithField("room_id", req.RoomID).Warn("Room purged from roomserver")
+ logrus.WithField("room_id", roomID).Warn("Room purged from roomserver")
- return r.Inputer.OutputProducer.ProduceRoomEvents(req.RoomID, []api.OutputEvent{
+ return r.Inputer.OutputProducer.ProduceRoomEvents(roomID, []api.OutputEvent{
{
Type: api.OutputTypePurgeRoom,
PurgeRoom: &api.OutputPurgeRoom{
- RoomID: req.RoomID,
+ RoomID: roomID,
},
},
})
@@ -282,42 +227,25 @@ func (r *Admin) PerformAdminPurgeRoom(
func (r *Admin) PerformAdminDownloadState(
ctx context.Context,
- req *api.PerformAdminDownloadStateRequest,
- res *api.PerformAdminDownloadStateResponse,
+ roomID, userID string, serverName spec.ServerName,
) error {
- _, senderDomain, err := r.Cfg.Matrix.SplitLocalID('@', req.UserID)
+ _, senderDomain, err := r.Cfg.Matrix.SplitLocalID('@', userID)
if err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("r.Cfg.Matrix.SplitLocalID: %s", err),
- }
- return nil
+ return err
}
- roomInfo, err := r.DB.RoomInfo(ctx, req.RoomID)
+ roomInfo, err := r.DB.RoomInfo(ctx, roomID)
if err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("r.DB.RoomInfo: %s", err),
- }
- return nil
+ return err
}
if roomInfo == nil || roomInfo.IsStub() {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("room %q not found", req.RoomID),
- }
- return nil
+ return eventutil.ErrRoomNoExists
}
fwdExtremities, _, depth, err := r.DB.LatestEventIDs(ctx, roomInfo.RoomNID)
if err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("r.DB.LatestEventIDs: %s", err),
- }
- return nil
+ return err
}
authEventMap := map[string]*gomatrixserverlib.Event{}
@@ -325,13 +253,9 @@ func (r *Admin) PerformAdminDownloadState(
for _, fwdExtremity := range fwdExtremities {
var state gomatrixserverlib.StateResponse
- state, err = r.Inputer.FSAPI.LookupState(ctx, r.Inputer.ServerName, req.ServerName, req.RoomID, fwdExtremity.EventID, roomInfo.RoomVersion)
+ state, err = r.Inputer.FSAPI.LookupState(ctx, r.Inputer.ServerName, serverName, roomID, fwdExtremity.EventID, roomInfo.RoomVersion)
if err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("r.Inputer.FSAPI.LookupState (%q): %s", fwdExtremity.EventID, err),
- }
- return nil
+ return fmt.Errorf("r.Inputer.FSAPI.LookupState (%q): %s", fwdExtremity.EventID, err)
}
for _, authEvent := range state.GetAuthEvents().UntrustedEvents(roomInfo.RoomVersion) {
if err = gomatrixserverlib.VerifyEventSignatures(ctx, authEvent, r.Inputer.KeyRing); err != nil {
@@ -361,18 +285,14 @@ func (r *Admin) PerformAdminDownloadState(
builder := &gomatrixserverlib.EventBuilder{
Type: "org.matrix.dendrite.state_download",
- Sender: req.UserID,
- RoomID: req.RoomID,
+ Sender: userID,
+ RoomID: roomID,
Content: spec.RawJSON("{}"),
}
eventsNeeded, err := gomatrixserverlib.StateNeededForEventBuilder(builder)
if err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("gomatrixserverlib.StateNeededForEventBuilder: %s", err),
- }
- return nil
+ return fmt.Errorf("gomatrixserverlib.StateNeededForEventBuilder: %w", err)
}
queryRes := &api.QueryLatestEventsAndStateResponse{
@@ -390,11 +310,7 @@ func (r *Admin) PerformAdminDownloadState(
ev, err := eventutil.BuildEvent(ctx, builder, r.Cfg.Matrix, identity, time.Now(), &eventsNeeded, queryRes)
if err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("eventutil.BuildEvent: %s", err),
- }
- return nil
+ return fmt.Errorf("eventutil.BuildEvent: %w", err)
}
inputReq := &api.InputRoomEventsRequest{
@@ -418,19 +334,12 @@ func (r *Admin) PerformAdminDownloadState(
SendAsServer: string(r.Cfg.Matrix.ServerName),
})
- if err := r.Inputer.InputRoomEvents(ctx, inputReq, inputRes); err != nil {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("r.Inputer.InputRoomEvents: %s", err),
- }
- return nil
+ if err = r.Inputer.InputRoomEvents(ctx, inputReq, inputRes); err != nil {
+ return fmt.Errorf("r.Inputer.InputRoomEvents: %w", err)
}
if inputRes.ErrMsg != "" {
- res.Error = &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: inputRes.ErrMsg,
- }
+ return inputRes.Err()
}
return nil
diff --git a/roomserver/internal/perform/perform_invite.go b/roomserver/internal/perform/perform_invite.go
index 8370efc4..dd798289 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
diff --git a/roomserver/internal/perform/perform_join.go b/roomserver/internal/perform/perform_join.go
index e752b249..06cc0d67 100644
--- a/roomserver/internal/perform/perform_join.go
+++ b/roomserver/internal/perform/perform_join.go
@@ -54,32 +54,22 @@ type Joiner struct {
func (r *Joiner) PerformJoin(
ctx context.Context,
req *rsAPI.PerformJoinRequest,
- res *rsAPI.PerformJoinResponse,
-) error {
+) (roomID string, joinedVia spec.ServerName, err error) {
logger := logrus.WithContext(ctx).WithFields(logrus.Fields{
"room_id": req.RoomIDOrAlias,
"user_id": req.UserID,
"servers": req.ServerNames,
})
logger.Info("User requested to room join")
- roomID, joinedVia, err := r.performJoin(context.Background(), req)
+ roomID, joinedVia, err = r.performJoin(context.Background(), req)
if err != nil {
logger.WithError(err).Error("Failed to join room")
sentry.CaptureException(err)
- perr, ok := err.(*rsAPI.PerformError)
- if ok {
- res.Error = perr
- } else {
- res.Error = &rsAPI.PerformError{
- Msg: err.Error(),
- }
- }
- return nil
+ return "", "", err
}
logger.Info("User joined room successfully")
- res.RoomID = roomID
- res.JoinedVia = joinedVia
- return nil
+
+ return roomID, joinedVia, nil
}
func (r *Joiner) performJoin(
@@ -88,16 +78,10 @@ func (r *Joiner) performJoin(
) (string, spec.ServerName, error) {
_, domain, err := gomatrixserverlib.SplitID('@', req.UserID)
if err != nil {
- return "", "", &rsAPI.PerformError{
- Code: rsAPI.PerformErrorBadRequest,
- Msg: fmt.Sprintf("Supplied user ID %q in incorrect format", req.UserID),
- }
+ return "", "", rsAPI.ErrInvalidID{Err: fmt.Errorf("supplied user ID %q in incorrect format", req.UserID)}
}
if !r.Cfg.Matrix.IsLocalServerName(domain) {
- return "", "", &rsAPI.PerformError{
- Code: rsAPI.PerformErrorBadRequest,
- Msg: fmt.Sprintf("User %q does not belong to this homeserver", req.UserID),
- }
+ return "", "", rsAPI.ErrInvalidID{Err: fmt.Errorf("user %q does not belong to this homeserver", req.UserID)}
}
if strings.HasPrefix(req.RoomIDOrAlias, "!") {
return r.performJoinRoomByID(ctx, req)
@@ -105,10 +89,7 @@ func (r *Joiner) performJoin(
if strings.HasPrefix(req.RoomIDOrAlias, "#") {
return r.performJoinRoomByAlias(ctx, req)
}
- return "", "", &rsAPI.PerformError{
- Code: rsAPI.PerformErrorBadRequest,
- Msg: fmt.Sprintf("Room ID or alias %q is invalid", req.RoomIDOrAlias),
- }
+ return "", "", rsAPI.ErrInvalidID{Err: fmt.Errorf("room ID or alias %q is invalid", req.RoomIDOrAlias)}
}
func (r *Joiner) performJoinRoomByAlias(
@@ -183,10 +164,7 @@ func (r *Joiner) performJoinRoomByID(
// Get the domain part of the room ID.
_, domain, err := gomatrixserverlib.SplitID('!', req.RoomIDOrAlias)
if err != nil {
- return "", "", &rsAPI.PerformError{
- Code: rsAPI.PerformErrorBadRequest,
- Msg: fmt.Sprintf("Room ID %q is invalid: %s", req.RoomIDOrAlias, err),
- }
+ return "", "", rsAPI.ErrInvalidID{Err: fmt.Errorf("room ID %q is invalid: %w", req.RoomIDOrAlias, err)}
}
// If the server name in the room ID isn't ours then it's a
@@ -200,10 +178,7 @@ func (r *Joiner) performJoinRoomByID(
userID := req.UserID
_, userDomain, err := r.Cfg.Matrix.SplitLocalID('@', userID)
if err != nil {
- return "", "", &rsAPI.PerformError{
- Code: rsAPI.PerformErrorBadRequest,
- Msg: fmt.Sprintf("User ID %q is invalid: %s", userID, err),
- }
+ return "", "", rsAPI.ErrInvalidID{Err: fmt.Errorf("user ID %q is invalid: %w", userID, err)}
}
eb := gomatrixserverlib.EventBuilder{
Type: spec.MRoomMember,
@@ -287,10 +262,7 @@ func (r *Joiner) performJoinRoomByID(
// Servers MUST only allow guest users to join rooms if the m.room.guest_access state event
// is present on the room and has the guest_access value can_join.
if guestAccess != "can_join" {
- return "", "", &rsAPI.PerformError{
- Code: rsAPI.PerformErrorNotAllowed,
- Msg: "Guest access is forbidden",
- }
+ return "", "", rsAPI.ErrNotAllowed{Err: fmt.Errorf("guest access is forbidden")}
}
}
@@ -342,16 +314,10 @@ func (r *Joiner) performJoinRoomByID(
}
inputRes := rsAPI.InputRoomEventsResponse{}
if err = r.Inputer.InputRoomEvents(ctx, &inputReq, &inputRes); err != nil {
- return "", "", &rsAPI.PerformError{
- Code: rsAPI.PerformErrorNoOperation,
- Msg: fmt.Sprintf("InputRoomEvents failed: %s", err),
- }
+ return "", "", rsAPI.ErrNotAllowed{Err: err}
}
if err = inputRes.Err(); err != nil {
- return "", "", &rsAPI.PerformError{
- Code: rsAPI.PerformErrorNotAllowed,
- Msg: fmt.Sprintf("InputRoomEvents auth failed: %s", err),
- }
+ return "", "", rsAPI.ErrNotAllowed{Err: err}
}
}
@@ -364,10 +330,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 "", "", &rsAPI.PerformError{
- Code: rsAPI.PerformErrorNoRoom,
- Msg: fmt.Sprintf("room ID %q does not exist", req.RoomIDOrAlias),
- }
+ return "", "", eventutil.ErrRoomNoExists
}
}
@@ -402,11 +365,7 @@ func (r *Joiner) performFederatedJoinRoomByID(
fedRes := fsAPI.PerformJoinResponse{}
r.FSAPI.PerformJoin(ctx, &fedReq, &fedRes)
if fedRes.LastError != nil {
- return "", &rsAPI.PerformError{
- Code: rsAPI.PerformErrRemote,
- Msg: fedRes.LastError.Message,
- RemoteCode: fedRes.LastError.Code,
- }
+ return "", fedRes.LastError
}
return fedRes.JoinedVia, nil
}
@@ -430,10 +389,7 @@ func (r *Joiner) populateAuthorisedViaUserForRestrictedJoin(
return "", nil
}
if !res.Allowed {
- return "", &rsAPI.PerformError{
- Code: rsAPI.PerformErrorNotAllowed,
- Msg: fmt.Sprintf("The join to room %s was not allowed.", joinReq.RoomIDOrAlias),
- }
+ return "", rsAPI.ErrNotAllowed{Err: fmt.Errorf("the join to room %s was not allowed", joinReq.RoomIDOrAlias)}
}
return res.AuthorisedVia, nil
}
diff --git a/roomserver/internal/perform/perform_peek.go b/roomserver/internal/perform/perform_peek.go
index 2f39050d..661fe20a 100644
--- a/roomserver/internal/perform/perform_peek.go
+++ b/roomserver/internal/perform/perform_peek.go
@@ -44,21 +44,8 @@ type Peeker struct {
func (r *Peeker) PerformPeek(
ctx context.Context,
req *api.PerformPeekRequest,
- res *api.PerformPeekResponse,
-) error {
- roomID, err := r.performPeek(ctx, req)
- if err != nil {
- perr, ok := err.(*api.PerformError)
- if ok {
- res.Error = perr
- } else {
- res.Error = &api.PerformError{
- Msg: err.Error(),
- }
- }
- }
- res.RoomID = roomID
- return nil
+) (roomID string, err error) {
+ return r.performPeek(ctx, req)
}
func (r *Peeker) performPeek(
@@ -68,16 +55,10 @@ func (r *Peeker) performPeek(
// FIXME: there's way too much duplication with performJoin
_, domain, err := gomatrixserverlib.SplitID('@', req.UserID)
if err != nil {
- return "", &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("Supplied user ID %q in incorrect format", req.UserID),
- }
+ return "", api.ErrInvalidID{Err: fmt.Errorf("supplied user ID %q in incorrect format", req.UserID)}
}
if !r.Cfg.Matrix.IsLocalServerName(domain) {
- return "", &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("User %q does not belong to this homeserver", req.UserID),
- }
+ return "", api.ErrInvalidID{Err: fmt.Errorf("user %q does not belong to this homeserver", req.UserID)}
}
if strings.HasPrefix(req.RoomIDOrAlias, "!") {
return r.performPeekRoomByID(ctx, req)
@@ -85,10 +66,7 @@ func (r *Peeker) performPeek(
if strings.HasPrefix(req.RoomIDOrAlias, "#") {
return r.performPeekRoomByAlias(ctx, req)
}
- return "", &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("Room ID or alias %q is invalid", req.RoomIDOrAlias),
- }
+ return "", api.ErrInvalidID{Err: fmt.Errorf("room ID or alias %q is invalid", req.RoomIDOrAlias)}
}
func (r *Peeker) performPeekRoomByAlias(
@@ -98,7 +76,7 @@ func (r *Peeker) performPeekRoomByAlias(
// Get the domain part of the room alias.
_, domain, err := gomatrixserverlib.SplitID('#', req.RoomIDOrAlias)
if err != nil {
- return "", fmt.Errorf("alias %q is not in the correct format", req.RoomIDOrAlias)
+ return "", api.ErrInvalidID{Err: fmt.Errorf("alias %q is not in the correct format", req.RoomIDOrAlias)}
}
req.ServerNames = append(req.ServerNames, domain)
@@ -147,10 +125,7 @@ func (r *Peeker) performPeekRoomByID(
// Get the domain part of the room ID.
_, domain, err := gomatrixserverlib.SplitID('!', roomID)
if err != nil {
- return "", &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("Room ID %q is invalid: %s", roomID, err),
- }
+ return "", api.ErrInvalidID{Err: fmt.Errorf("room ID %q is invalid: %w", roomID, err)}
}
// handle federated peeks
@@ -169,11 +144,7 @@ func (r *Peeker) performPeekRoomByID(
fedRes := fsAPI.PerformOutboundPeekResponse{}
_ = r.FSAPI.PerformOutboundPeek(ctx, &fedReq, &fedRes)
if fedRes.LastError != nil {
- return "", &api.PerformError{
- Code: api.PerformErrRemote,
- Msg: fedRes.LastError.Message,
- RemoteCode: fedRes.LastError.Code,
- }
+ return "", fedRes.LastError
}
}
@@ -194,17 +165,11 @@ func (r *Peeker) performPeekRoomByID(
}
if !worldReadable {
- return "", &api.PerformError{
- Code: api.PerformErrorNotAllowed,
- Msg: "Room is not world-readable",
- }
+ return "", api.ErrNotAllowed{Err: fmt.Errorf("room is not world-readable")}
}
if ev, _ := r.DB.GetStateEvent(ctx, roomID, "m.room.encryption", ""); ev != nil {
- return "", &api.PerformError{
- Code: api.PerformErrorNotAllowed,
- Msg: "Cannot peek into an encrypted room",
- }
+ return "", api.ErrNotAllowed{Err: fmt.Errorf("Cannot peek into an encrypted room")}
}
// TODO: handle federated peeks
diff --git a/roomserver/internal/perform/perform_publish.go b/roomserver/internal/perform/perform_publish.go
index fbbfc321..297a4a18 100644
--- a/roomserver/internal/perform/perform_publish.go
+++ b/roomserver/internal/perform/perform_publish.go
@@ -25,16 +25,10 @@ type Publisher struct {
DB storage.Database
}
+// PerformPublish publishes or unpublishes a room from the room directory. Returns a database error, if any.
func (r *Publisher) PerformPublish(
ctx context.Context,
req *api.PerformPublishRequest,
- res *api.PerformPublishResponse,
) error {
- err := r.DB.PublishRoom(ctx, req.RoomID, req.AppserviceID, req.NetworkID, req.Visibility == "public")
- if err != nil {
- res.Error = &api.PerformError{
- Msg: err.Error(),
- }
- }
- return nil
+ return r.DB.PublishRoom(ctx, req.RoomID, req.AppserviceID, req.NetworkID, req.Visibility == "public")
}
diff --git a/roomserver/internal/perform/perform_unpeek.go b/roomserver/internal/perform/perform_unpeek.go
index 28486fa1..1ea8079d 100644
--- a/roomserver/internal/perform/perform_unpeek.go
+++ b/roomserver/internal/perform/perform_unpeek.go
@@ -34,84 +34,48 @@ type Unpeeker struct {
Inputer *input.Inputer
}
-// PerformPeek handles peeking into matrix rooms, including over federation by talking to the federationapi.
+// PerformUnpeek handles un-peeking matrix rooms, including over federation by talking to the federationapi.
func (r *Unpeeker) PerformUnpeek(
ctx context.Context,
- req *api.PerformUnpeekRequest,
- res *api.PerformUnpeekResponse,
-) error {
- if err := r.performUnpeek(ctx, req); err != nil {
- perr, ok := err.(*api.PerformError)
- if ok {
- res.Error = perr
- } else {
- res.Error = &api.PerformError{
- Msg: err.Error(),
- }
- }
- }
- return nil
-}
-
-func (r *Unpeeker) performUnpeek(
- ctx context.Context,
- req *api.PerformUnpeekRequest,
+ roomID, userID, deviceID string,
) error {
// FIXME: there's way too much duplication with performJoin
- _, domain, err := gomatrixserverlib.SplitID('@', req.UserID)
+ _, domain, err := gomatrixserverlib.SplitID('@', userID)
if err != nil {
- return &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("Supplied user ID %q in incorrect format", req.UserID),
- }
+ return api.ErrInvalidID{Err: fmt.Errorf("supplied user ID %q in incorrect format", userID)}
}
if !r.Cfg.Matrix.IsLocalServerName(domain) {
- return &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("User %q does not belong to this homeserver", req.UserID),
- }
+ return api.ErrInvalidID{Err: fmt.Errorf("user %q does not belong to this homeserver", userID)}
}
- if strings.HasPrefix(req.RoomID, "!") {
- return r.performUnpeekRoomByID(ctx, req)
- }
- return &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("Room ID %q is invalid", req.RoomID),
+ if strings.HasPrefix(roomID, "!") {
+ return r.performUnpeekRoomByID(ctx, roomID, userID, deviceID)
}
+ return api.ErrInvalidID{Err: fmt.Errorf("room ID %q is invalid", roomID)}
}
func (r *Unpeeker) performUnpeekRoomByID(
_ context.Context,
- req *api.PerformUnpeekRequest,
+ roomID, userID, deviceID string,
) (err error) {
// Get the domain part of the room ID.
- _, _, err = gomatrixserverlib.SplitID('!', req.RoomID)
+ _, _, err = gomatrixserverlib.SplitID('!', roomID)
if err != nil {
- return &api.PerformError{
- Code: api.PerformErrorBadRequest,
- Msg: fmt.Sprintf("Room ID %q is invalid: %s", req.RoomID, err),
- }
+ return api.ErrInvalidID{Err: fmt.Errorf("room ID %q is invalid: %w", roomID, err)}
}
// TODO: handle federated peeks
-
- err = r.Inputer.OutputProducer.ProduceRoomEvents(req.RoomID, []api.OutputEvent{
+ // By this point, if req.RoomIDOrAlias contained an alias, then
+ // it will have been overwritten with a room ID by performPeekRoomByAlias.
+ // We should now include this in the response so that the CS API can
+ // return the right room ID.
+ return r.Inputer.OutputProducer.ProduceRoomEvents(roomID, []api.OutputEvent{
{
Type: api.OutputTypeRetirePeek,
RetirePeek: &api.OutputRetirePeek{
- RoomID: req.RoomID,
- UserID: req.UserID,
- DeviceID: req.DeviceID,
+ RoomID: roomID,
+ UserID: userID,
+ DeviceID: deviceID,
},
},
})
- if err != nil {
- return
- }
-
- // By this point, if req.RoomIDOrAlias contained an alias, then
- // it will have been overwritten with a room ID by performPeekRoomByAlias.
- // We should now include this in the response so that the CS API can
- // return the right room ID.
- return nil
}
diff --git a/roomserver/internal/perform/perform_upgrade.go b/roomserver/internal/perform/perform_upgrade.go
index bfe70354..3a3c1148 100644
--- a/roomserver/internal/perform/perform_upgrade.go
+++ b/roomserver/internal/perform/perform_upgrade.go
@@ -45,46 +45,29 @@ type fledglingEvent struct {
// PerformRoomUpgrade upgrades a room from one version to another
func (r *Upgrader) PerformRoomUpgrade(
ctx context.Context,
- req *api.PerformRoomUpgradeRequest,
- res *api.PerformRoomUpgradeResponse,
-) error {
- res.NewRoomID, res.Error = r.performRoomUpgrade(ctx, req)
- if res.Error != nil {
- res.NewRoomID = ""
- logrus.WithContext(ctx).WithError(res.Error).Error("Room upgrade failed")
- }
- return nil
+ roomID, userID string, roomVersion gomatrixserverlib.RoomVersion,
+) (newRoomID string, err error) {
+ return r.performRoomUpgrade(ctx, roomID, userID, roomVersion)
}
func (r *Upgrader) performRoomUpgrade(
ctx context.Context,
- req *api.PerformRoomUpgradeRequest,
-) (string, *api.PerformError) {
- roomID := req.RoomID
- userID := req.UserID
+ roomID, userID string, roomVersion gomatrixserverlib.RoomVersion,
+) (string, error) {
_, userDomain, err := r.Cfg.Matrix.SplitLocalID('@', userID)
if err != nil {
- return "", &api.PerformError{
- Code: api.PerformErrorNotAllowed,
- Msg: "Error validating the user ID",
- }
+ return "", api.ErrNotAllowed{Err: fmt.Errorf("error validating the user ID")}
}
evTime := time.Now()
// Return an immediate error if the room does not exist
if err := r.validateRoomExists(ctx, roomID); err != nil {
- return "", &api.PerformError{
- Code: api.PerformErrorNoRoom,
- Msg: "Error validating that the room exists",
- }
+ return "", err
}
// 1. Check if the user is authorized to actually perform the upgrade (can send m.room.tombstone)
if !r.userIsAuthorized(ctx, userID, roomID) {
- return "", &api.PerformError{
- Code: api.PerformErrorNotAllowed,
- Msg: "You don't have permission to upgrade the room, power level too low.",
- }
+ return "", api.ErrNotAllowed{Err: fmt.Errorf("You don't have permission to upgrade the room, power level too low.")}
}
// TODO (#267): Check room ID doesn't clash with an existing one, and we
@@ -97,9 +80,7 @@ func (r *Upgrader) performRoomUpgrade(
}
oldRoomRes := &api.QueryLatestEventsAndStateResponse{}
if err := r.URSAPI.QueryLatestEventsAndState(ctx, oldRoomReq, oldRoomRes); err != nil {
- return "", &api.PerformError{
- Msg: fmt.Sprintf("Failed to get latest state: %s", err),
- }
+ return "", fmt.Errorf("Failed to get latest state: %s", err)
}
// Make the tombstone event
@@ -110,13 +91,13 @@ func (r *Upgrader) performRoomUpgrade(
// Generate the initial events we need to send into the new room. This includes copied state events and bans
// as well as the power level events needed to set up the room
- eventsToMake, pErr := r.generateInitialEvents(ctx, oldRoomRes, userID, roomID, string(req.RoomVersion), tombstoneEvent)
+ eventsToMake, pErr := r.generateInitialEvents(ctx, oldRoomRes, userID, roomID, roomVersion, tombstoneEvent)
if pErr != nil {
return "", pErr
}
// Send the setup events to the new room
- if pErr = r.sendInitialEvents(ctx, evTime, userID, userDomain, newRoomID, string(req.RoomVersion), eventsToMake); pErr != nil {
+ if pErr = r.sendInitialEvents(ctx, evTime, userID, userDomain, newRoomID, roomVersion, eventsToMake); pErr != nil {
return "", pErr
}
@@ -148,22 +129,15 @@ func (r *Upgrader) performRoomUpgrade(
return newRoomID, nil
}
-func (r *Upgrader) getRoomPowerLevels(ctx context.Context, roomID string) (*gomatrixserverlib.PowerLevelContent, *api.PerformError) {
+func (r *Upgrader) getRoomPowerLevels(ctx context.Context, roomID string) (*gomatrixserverlib.PowerLevelContent, error) {
oldPowerLevelsEvent := api.GetStateEvent(ctx, r.URSAPI, roomID, gomatrixserverlib.StateKeyTuple{
EventType: spec.MRoomPowerLevels,
StateKey: "",
})
- powerLevelContent, err := oldPowerLevelsEvent.PowerLevels()
- if err != nil {
- util.GetLogger(ctx).WithError(err).Error()
- return nil, &api.PerformError{
- Msg: "Power level event was invalid or malformed",
- }
- }
- return powerLevelContent, nil
+ return oldPowerLevelsEvent.PowerLevels()
}
-func (r *Upgrader) restrictOldRoomPowerLevels(ctx context.Context, evTime time.Time, userID string, userDomain spec.ServerName, roomID string) *api.PerformError {
+func (r *Upgrader) restrictOldRoomPowerLevels(ctx context.Context, evTime time.Time, userID string, userDomain spec.ServerName, roomID string) error {
restrictedPowerLevelContent, pErr := r.getRoomPowerLevels(ctx, roomID)
if pErr != nil {
return pErr
@@ -185,54 +159,46 @@ func (r *Upgrader) restrictOldRoomPowerLevels(ctx context.Context, evTime time.T
StateKey: "",
Content: restrictedPowerLevelContent,
})
- if resErr != nil {
- if resErr.Code == api.PerformErrorNotAllowed {
- util.GetLogger(ctx).WithField(logrus.ErrorKey, resErr).Warn("UpgradeRoom: Could not restrict power levels in old room")
- } else {
- return resErr
- }
- } else {
- if resErr = r.sendHeaderedEvent(ctx, userDomain, restrictedPowerLevelsHeadered, api.DoNotSendToOtherServers); resErr != nil {
- return resErr
- }
+
+ switch resErr.(type) {
+ case api.ErrNotAllowed:
+ util.GetLogger(ctx).WithField(logrus.ErrorKey, resErr).Warn("UpgradeRoom: Could not restrict power levels in old room")
+ case nil:
+ return r.sendHeaderedEvent(ctx, userDomain, restrictedPowerLevelsHeadered, api.DoNotSendToOtherServers)
+ default:
+ return resErr
}
return nil
}
func moveLocalAliases(ctx context.Context,
roomID, newRoomID, userID string,
- URSAPI api.RoomserverInternalAPI) *api.PerformError {
- var err error
+ URSAPI api.RoomserverInternalAPI,
+) (err error) {
aliasReq := api.GetAliasesForRoomIDRequest{RoomID: roomID}
aliasRes := api.GetAliasesForRoomIDResponse{}
if err = URSAPI.GetAliasesForRoomID(ctx, &aliasReq, &aliasRes); err != nil {
- return &api.PerformError{
- Msg: fmt.Sprintf("Failed to get old room aliases: %s", err),
- }
+ return fmt.Errorf("Failed to get old room aliases: %w", err)
}
for _, alias := range aliasRes.Aliases {
removeAliasReq := api.RemoveRoomAliasRequest{UserID: userID, Alias: alias}
removeAliasRes := api.RemoveRoomAliasResponse{}
if err = URSAPI.RemoveRoomAlias(ctx, &removeAliasReq, &removeAliasRes); err != nil {
- return &api.PerformError{
- Msg: fmt.Sprintf("Failed to remove old room alias: %s", err),
- }
+ return fmt.Errorf("Failed to remove old room alias: %w", err)
}
setAliasReq := api.SetRoomAliasRequest{UserID: userID, Alias: alias, RoomID: newRoomID}
setAliasRes := api.SetRoomAliasResponse{}
if err = URSAPI.SetRoomAlias(ctx, &setAliasReq, &setAliasRes); err != nil {
- return &api.PerformError{
- Msg: fmt.Sprintf("Failed to set new room alias: %s", err),
- }
+ return fmt.Errorf("Failed to set new room alias: %w", err)
}
}
return nil
}
-func (r *Upgrader) clearOldCanonicalAliasEvent(ctx context.Context, oldRoom *api.QueryLatestEventsAndStateResponse, evTime time.Time, userID string, userDomain spec.ServerName, roomID string) *api.PerformError {
+func (r *Upgrader) clearOldCanonicalAliasEvent(ctx context.Context, oldRoom *api.QueryLatestEventsAndStateResponse, evTime time.Time, userID string, userDomain spec.ServerName, roomID string) error {
for _, event := range oldRoom.StateEvents {
if event.Type() != spec.MRoomCanonicalAlias || !event.StateKeyEquals("") {
continue
@@ -242,9 +208,7 @@ func (r *Upgrader) clearOldCanonicalAliasEvent(ctx context.Context, oldRoom *api
AltAliases []string `json:"alt_aliases"`
}
if err := json.Unmarshal(event.Content(), &aliasContent); err != nil {
- return &api.PerformError{
- Msg: fmt.Sprintf("Failed to unmarshal canonical aliases: %s", err),
- }
+ return fmt.Errorf("failed to unmarshal canonical aliases: %w", err)
}
if aliasContent.Alias == "" && len(aliasContent.AltAliases) == 0 {
// There are no canonical aliases to clear, therefore do nothing.
@@ -256,30 +220,25 @@ func (r *Upgrader) clearOldCanonicalAliasEvent(ctx context.Context, oldRoom *api
Type: spec.MRoomCanonicalAlias,
Content: map[string]interface{}{},
})
- if resErr != nil {
- if resErr.Code == api.PerformErrorNotAllowed {
- util.GetLogger(ctx).WithField(logrus.ErrorKey, resErr).Warn("UpgradeRoom: Could not set empty canonical alias event in old room")
- } else {
- return resErr
- }
- } else {
- if resErr = r.sendHeaderedEvent(ctx, userDomain, emptyCanonicalAliasEvent, api.DoNotSendToOtherServers); resErr != nil {
- return resErr
- }
+ switch resErr.(type) {
+ case api.ErrNotAllowed:
+ util.GetLogger(ctx).WithField(logrus.ErrorKey, resErr).Warn("UpgradeRoom: Could not set empty canonical alias event in old room")
+ case nil:
+ return r.sendHeaderedEvent(ctx, userDomain, emptyCanonicalAliasEvent, api.DoNotSendToOtherServers)
+ default:
+ return resErr
}
return nil
}
-func (r *Upgrader) publishIfOldRoomWasPublic(ctx context.Context, roomID, newRoomID string) *api.PerformError {
+func (r *Upgrader) publishIfOldRoomWasPublic(ctx context.Context, roomID, newRoomID string) error {
// check if the old room was published
var pubQueryRes api.QueryPublishedRoomsResponse
err := r.URSAPI.QueryPublishedRooms(ctx, &api.QueryPublishedRoomsRequest{
RoomID: roomID,
}, &pubQueryRes)
if err != nil {
- return &api.PerformError{
- Msg: "QueryPublishedRooms failed",
- }
+ return err
}
// if the old room is published (was public), publish the new room
@@ -295,36 +254,27 @@ func publishNewRoomAndUnpublishOldRoom(
oldRoomID, newRoomID string,
) {
// expose this room in the published room list
- var pubNewRoomRes api.PerformPublishResponse
if err := URSAPI.PerformPublish(ctx, &api.PerformPublishRequest{
RoomID: newRoomID,
- Visibility: "public",
- }, &pubNewRoomRes); err != nil {
- util.GetLogger(ctx).WithError(err).Error("failed to reach internal API")
- } else if pubNewRoomRes.Error != nil {
+ Visibility: spec.Public,
+ }); err != nil {
// treat as non-fatal since the room is already made by this point
- util.GetLogger(ctx).WithError(pubNewRoomRes.Error).Error("failed to visibility:public")
+ util.GetLogger(ctx).WithError(err).Error("failed to publish room")
}
- var unpubOldRoomRes api.PerformPublishResponse
// remove the old room from the published room list
if err := URSAPI.PerformPublish(ctx, &api.PerformPublishRequest{
RoomID: oldRoomID,
Visibility: "private",
- }, &unpubOldRoomRes); err != nil {
- util.GetLogger(ctx).WithError(err).Error("failed to reach internal API")
- } else if unpubOldRoomRes.Error != nil {
+ }); err != nil {
// treat as non-fatal since the room is already made by this point
- util.GetLogger(ctx).WithError(unpubOldRoomRes.Error).Error("failed to visibility:private")
+ util.GetLogger(ctx).WithError(err).Error("failed to un-publish room")
}
}
func (r *Upgrader) validateRoomExists(ctx context.Context, roomID string) error {
if _, err := r.URSAPI.QueryRoomVersionForRoom(ctx, roomID); err != nil {
- return &api.PerformError{
- Code: api.PerformErrorNoRoom,
- Msg: "Room does not exist",
- }
+ return eventutil.ErrRoomNoExists
}
return nil
}
@@ -348,7 +298,7 @@ func (r *Upgrader) userIsAuthorized(ctx context.Context, userID, roomID string,
}
// nolint:gocyclo
-func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.QueryLatestEventsAndStateResponse, userID, roomID, newVersion string, tombstoneEvent *types.HeaderedEvent) ([]fledglingEvent, *api.PerformError) {
+func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.QueryLatestEventsAndStateResponse, userID, roomID string, newVersion gomatrixserverlib.RoomVersion, tombstoneEvent *types.HeaderedEvent) ([]fledglingEvent, error) {
state := make(map[gomatrixserverlib.StateKeyTuple]*types.HeaderedEvent, len(oldRoom.StateEvents))
for _, event := range oldRoom.StateEvents {
if event.StateKey() == nil {
@@ -391,9 +341,7 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query
// old room state. Check that they are there.
for tuple := range override {
if _, ok := state[tuple]; !ok {
- return nil, &api.PerformError{
- Msg: fmt.Sprintf("Essential event of type %q state key %q is missing", tuple.EventType, tuple.StateKey),
- }
+ return nil, fmt.Errorf("essential event of type %q state key %q is missing", tuple.EventType, tuple.StateKey)
}
}
@@ -440,9 +388,7 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query
powerLevelContent, err := oldPowerLevelsEvent.PowerLevels()
if err != nil {
util.GetLogger(ctx).WithError(err).Error()
- return nil, &api.PerformError{
- Msg: "Power level event content was invalid",
- }
+ return nil, fmt.Errorf("Power level event content was invalid")
}
tempPowerLevelsEvent, powerLevelsOverridden := createTemporaryPowerLevels(powerLevelContent, userID)
@@ -506,7 +452,7 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query
return eventsToMake, nil
}
-func (r *Upgrader) sendInitialEvents(ctx context.Context, evTime time.Time, userID string, userDomain spec.ServerName, newRoomID, newVersion string, eventsToMake []fledglingEvent) *api.PerformError {
+func (r *Upgrader) sendInitialEvents(ctx context.Context, evTime time.Time, userID string, userDomain spec.ServerName, newRoomID string, newVersion gomatrixserverlib.RoomVersion, eventsToMake []fledglingEvent) error {
var err error
var builtEvents []*types.HeaderedEvent
authEvents := gomatrixserverlib.NewAuthEvents(nil)
@@ -522,34 +468,27 @@ func (r *Upgrader) sendInitialEvents(ctx context.Context, evTime time.Time, user
}
err = builder.SetContent(e.Content)
if err != nil {
- return &api.PerformError{
- Msg: fmt.Sprintf("Failed to set content of new %q event: %s", builder.Type, err),
- }
+ return fmt.Errorf("failed to set content of new %q event: %w", builder.Type, err)
}
if i > 0 {
builder.PrevEvents = []gomatrixserverlib.EventReference{builtEvents[i-1].EventReference()}
}
var event *gomatrixserverlib.Event
- event, err = builder.AddAuthEventsAndBuild(userDomain, &authEvents, evTime, gomatrixserverlib.RoomVersion(newVersion), r.Cfg.Matrix.KeyID, r.Cfg.Matrix.PrivateKey)
+ event, err = builder.AddAuthEventsAndBuild(userDomain, &authEvents, evTime, newVersion, r.Cfg.Matrix.KeyID, r.Cfg.Matrix.PrivateKey)
if err != nil {
- return &api.PerformError{
- Msg: fmt.Sprintf("Failed to build new %q event: %s", builder.Type, err),
- }
+ return fmt.Errorf("failed to build new %q event: %w", builder.Type, err)
+
}
if err = gomatrixserverlib.Allowed(event, &authEvents); err != nil {
- return &api.PerformError{
- Msg: fmt.Sprintf("Failed to auth new %q event: %s", builder.Type, err),
- }
+ return fmt.Errorf("Failed to auth new %q event: %w", builder.Type, err)
}
// Add the event to the list of auth events
builtEvents = append(builtEvents, &types.HeaderedEvent{Event: event})
err = authEvents.AddEvent(event)
if err != nil {
- return &api.PerformError{
- Msg: fmt.Sprintf("Failed to add new %q event to auth set: %s", builder.Type, err),
- }
+ return fmt.Errorf("failed to add new %q event to auth set: %w", builder.Type, err)
}
}
@@ -563,9 +502,7 @@ func (r *Upgrader) sendInitialEvents(ctx context.Context, evTime time.Time, user
})
}
if err = api.SendInputRoomEvents(ctx, r.URSAPI, userDomain, inputs, false); err != nil {
- return &api.PerformError{
- Msg: fmt.Sprintf("Failed to send new room %q to roomserver: %s", newRoomID, err),
- }
+ return fmt.Errorf("failed to send new room %q to roomserver: %w", newRoomID, err)
}
return nil
}
@@ -574,7 +511,7 @@ func (r *Upgrader) makeTombstoneEvent(
ctx context.Context,
evTime time.Time,
userID, roomID, newRoomID string,
-) (*types.HeaderedEvent, *api.PerformError) {
+) (*types.HeaderedEvent, error) {
content := map[string]interface{}{
"body": "This room has been replaced",
"replacement_room": newRoomID,
@@ -586,7 +523,7 @@ func (r *Upgrader) makeTombstoneEvent(
return r.makeHeaderedEvent(ctx, evTime, userID, roomID, event)
}
-func (r *Upgrader) makeHeaderedEvent(ctx context.Context, evTime time.Time, userID, roomID string, event fledglingEvent) (*types.HeaderedEvent, *api.PerformError) {
+func (r *Upgrader) makeHeaderedEvent(ctx context.Context, evTime time.Time, userID, roomID string, event fledglingEvent) (*types.HeaderedEvent, error) {
builder := gomatrixserverlib.EventBuilder{
Sender: userID,
RoomID: roomID,
@@ -595,47 +532,27 @@ func (r *Upgrader) makeHeaderedEvent(ctx context.Context, evTime time.Time, user
}
err := builder.SetContent(event.Content)
if err != nil {
- return nil, &api.PerformError{
- Msg: fmt.Sprintf("Failed to set new %q event content: %s", builder.Type, err),
- }
+ return nil, fmt.Errorf("failed to set new %q event content: %w", builder.Type, err)
}
// Get the sender domain.
_, senderDomain, serr := r.Cfg.Matrix.SplitLocalID('@', builder.Sender)
if serr != nil {
- return nil, &api.PerformError{
- Msg: fmt.Sprintf("Failed to split user ID %q: %s", builder.Sender, err),
- }
+ return nil, fmt.Errorf("Failed to split user ID %q: %w", builder.Sender, err)
}
identity, err := r.Cfg.Matrix.SigningIdentityFor(senderDomain)
if err != nil {
- return nil, &api.PerformError{
- Msg: fmt.Sprintf("Failed to get signing identity for %q: %s", senderDomain, err),
- }
+ return nil, fmt.Errorf("failed to get signing identity for %q: %w", senderDomain, err)
}
var queryRes api.QueryLatestEventsAndStateResponse
headeredEvent, err := eventutil.QueryAndBuildEvent(ctx, &builder, r.Cfg.Matrix, identity, evTime, r.URSAPI, &queryRes)
if err == eventutil.ErrRoomNoExists {
- return nil, &api.PerformError{
- Code: api.PerformErrorNoRoom,
- Msg: "Room does not exist",
- }
+ return nil, err
} else if e, ok := err.(gomatrixserverlib.BadJSONError); ok {
- return nil, &api.PerformError{
- Msg: e.Error(),
- }
+ return nil, e
} else if e, ok := err.(gomatrixserverlib.EventValidationError); ok {
- if e.Code == gomatrixserverlib.EventValidationTooLarge {
- return nil, &api.PerformError{
- Msg: e.Error(),
- }
- }
- return nil, &api.PerformError{
- Msg: e.Error(),
- }
+ return nil, e
} else if err != nil {
- return nil, &api.PerformError{
- Msg: fmt.Sprintf("Failed to build new %q event: %s", builder.Type, err),
- }
+ return nil, fmt.Errorf("failed to build new %q event: %w", builder.Type, err)
}
// check to see if this user can perform this operation
stateEvents := make([]*gomatrixserverlib.Event, len(queryRes.StateEvents))
@@ -644,10 +561,7 @@ func (r *Upgrader) makeHeaderedEvent(ctx context.Context, evTime time.Time, user
}
provider := gomatrixserverlib.NewAuthEvents(gomatrixserverlib.ToPDUs(stateEvents))
if err = gomatrixserverlib.Allowed(headeredEvent.Event, &provider); err != nil {
- return nil, &api.PerformError{
- Code: api.PerformErrorNotAllowed,
- Msg: fmt.Sprintf("Failed to auth new %q event: %s", builder.Type, err), // TODO: Is this error string comprehensible to the client?
- }
+ return nil, api.ErrNotAllowed{Err: fmt.Errorf("failed to auth new %q event: %w", builder.Type, err)} // TODO: Is this error string comprehensible to the client?
}
return headeredEvent, nil
@@ -695,7 +609,7 @@ func (r *Upgrader) sendHeaderedEvent(
serverName spec.ServerName,
headeredEvent *types.HeaderedEvent,
sendAsServer string,
-) *api.PerformError {
+) error {
var inputs []api.InputRoomEvent
inputs = append(inputs, api.InputRoomEvent{
Kind: api.KindNew,
@@ -703,11 +617,5 @@ func (r *Upgrader) sendHeaderedEvent(
Origin: serverName,
SendAsServer: sendAsServer,
})
- if err := api.SendInputRoomEvents(ctx, r.URSAPI, serverName, inputs, false); err != nil {
- return &api.PerformError{
- Msg: fmt.Sprintf("Failed to send new %q event to roomserver: %s", headeredEvent.Type(), err),
- }
- }
-
- return nil
+ return api.SendInputRoomEvents(ctx, r.URSAPI, serverName, inputs, false)
}
diff --git a/roomserver/roomserver_test.go b/roomserver/roomserver_test.go
index 856321bc..9877dd91 100644
--- a/roomserver/roomserver_test.go
+++ b/roomserver/roomserver_test.go
@@ -254,13 +254,9 @@ func TestPurgeRoom(t *testing.T) {
}
// some dummy entries to validate after purging
- publishResp := &api.PerformPublishResponse{}
- if err = rsAPI.PerformPublish(ctx, &api.PerformPublishRequest{RoomID: room.ID, Visibility: "public"}, publishResp); err != nil {
+ if err = rsAPI.PerformPublish(ctx, &api.PerformPublishRequest{RoomID: room.ID, Visibility: spec.Public}); err != nil {
t.Fatal(err)
}
- if publishResp.Error != nil {
- t.Fatal(publishResp.Error)
- }
isPublished, err := db.GetPublishedRoom(ctx, room.ID)
if err != nil {
@@ -328,8 +324,7 @@ func TestPurgeRoom(t *testing.T) {
}
// purge the room from the database
- purgeResp := &api.PerformAdminPurgeRoomResponse{}
- if err = rsAPI.PerformAdminPurgeRoom(ctx, &api.PerformAdminPurgeRoomRequest{RoomID: room.ID}, purgeResp); err != nil {
+ if err = rsAPI.PerformAdminPurgeRoom(ctx, room.ID); err != nil {
t.Fatal(err)
}
@@ -926,7 +921,7 @@ func TestUpgrade(t *testing.T) {
if err := rsAPI.PerformPublish(ctx, &api.PerformPublishRequest{
RoomID: r.ID,
Visibility: spec.Public,
- }, &api.PerformPublishResponse{}); err != nil {
+ }); err != nil {
t.Fatal(err)
}
@@ -1070,25 +1065,19 @@ func TestUpgrade(t *testing.T) {
}
roomID := tc.roomFunc(rsAPI)
- upgradeReq := api.PerformRoomUpgradeRequest{
- RoomID: roomID,
- UserID: tc.upgradeUser,
- RoomVersion: version.DefaultRoomVersion(), // always upgrade to the latest version
- }
- upgradeRes := api.PerformRoomUpgradeResponse{}
-
- if err := rsAPI.PerformRoomUpgrade(processCtx.Context(), &upgradeReq, &upgradeRes); err != nil {
+ newRoomID, err := rsAPI.PerformRoomUpgrade(processCtx.Context(), roomID, tc.upgradeUser, version.DefaultRoomVersion())
+ if err != nil && tc.wantNewRoom {
t.Fatal(err)
}
- if tc.wantNewRoom && upgradeRes.NewRoomID == "" {
+ if tc.wantNewRoom && newRoomID == "" {
t.Fatalf("expected a new room, but the upgrade failed")
}
- if !tc.wantNewRoom && upgradeRes.NewRoomID != "" {
+ if !tc.wantNewRoom && newRoomID != "" {
t.Fatalf("expected no new room, but the upgrade succeeded")
}
if tc.validateFunc != nil {
- tc.validateFunc(t, roomID, upgradeRes.NewRoomID, rsAPI)
+ tc.validateFunc(t, roomID, newRoomID, rsAPI)
}
})
}
diff --git a/roomserver/storage/interface.go b/roomserver/storage/interface.go
index 1cf05d59..a2364e2e 100644
--- a/roomserver/storage/interface.go
+++ b/roomserver/storage/interface.go
@@ -139,7 +139,7 @@ type Database interface {
// not found.
// Returns an error if the retrieval went wrong.
EventsFromIDs(ctx context.Context, roomInfo *types.RoomInfo, eventIDs []string) ([]types.Event, error)
- // Publish or unpublish a room from the room directory.
+ // PerformPublish publishes or unpublishes a room from the room directory. Returns a database error, if any.
PublishRoom(ctx context.Context, roomID, appserviceID, networkID string, publish bool) error
// Returns a list of room IDs for rooms which are published.
GetPublishedRooms(ctx context.Context, networkID string, includeAllNetworks bool) ([]string, error)
diff --git a/userapi/internal/user_api.go b/userapi/internal/user_api.go
index 1b6a4ebf..cdd08344 100644
--- a/userapi/internal/user_api.go
+++ b/userapi/internal/user_api.go
@@ -172,8 +172,8 @@ func addUserToRoom(
UserID: userID,
Content: addGroupContent,
}
- joinRes := rsapi.PerformJoinResponse{}
- return rsAPI.PerformJoin(ctx, &joinReq, &joinRes)
+ _, _, err := rsAPI.PerformJoin(ctx, &joinReq)
+ return err
}
func (a *UserInternalAPI) PerformAccountCreation(ctx context.Context, req *api.PerformAccountCreationRequest, res *api.PerformAccountCreationResponse) error {
@@ -624,33 +624,28 @@ func (a *UserInternalAPI) PerformAccountDeactivation(ctx context.Context, req *a
return fmt.Errorf("server name %q not locally configured", serverName)
}
- evacuateReq := &rsapi.PerformAdminEvacuateUserRequest{
- UserID: fmt.Sprintf("@%s:%s", req.Localpart, serverName),
- }
- evacuateRes := &rsapi.PerformAdminEvacuateUserResponse{}
- if err := a.RSAPI.PerformAdminEvacuateUser(ctx, evacuateReq, evacuateRes); err != nil {
- return err
- }
- if err := evacuateRes.Error; err != nil {
- logrus.WithError(err).Errorf("Failed to evacuate user after account deactivation")
+ userID := fmt.Sprintf("@%s:%s", req.Localpart, serverName)
+ _, err := a.RSAPI.PerformAdminEvacuateUser(ctx, userID)
+ if err != nil {
+ logrus.WithError(err).WithField("userID", userID).Errorf("Failed to evacuate user after account deactivation")
}
deviceReq := &api.PerformDeviceDeletionRequest{
UserID: fmt.Sprintf("@%s:%s", req.Localpart, serverName),
}
deviceRes := &api.PerformDeviceDeletionResponse{}
- if err := a.PerformDeviceDeletion(ctx, deviceReq, deviceRes); err != nil {
+ if err = a.PerformDeviceDeletion(ctx, deviceReq, deviceRes); err != nil {
return err
}
pusherReq := &api.PerformPusherDeletionRequest{
Localpart: req.Localpart,
}
- if err := a.PerformPusherDeletion(ctx, pusherReq, &struct{}{}); err != nil {
+ if err = a.PerformPusherDeletion(ctx, pusherReq, &struct{}{}); err != nil {
return err
}
- err := a.DB.DeactivateAccount(ctx, req.Localpart, serverName)
+ err = a.DB.DeactivateAccount(ctx, req.Localpart, serverName)
res.AccountDeactivated = err == nil
return err
}