PerformError be gone; Remove error from room upgrades

This commit is contained in:
Till Faelligen 2023-04-25 10:15:38 +02:00
parent e94ab3358e
commit f400acbf44
No known key found for this signature in database
GPG key ID: ACCDC9606D472758
4 changed files with 80 additions and 225 deletions

View file

@ -15,17 +15,20 @@
package routing package routing
import ( import (
"errors"
"net/http" "net/http"
appserviceAPI "github.com/matrix-org/dendrite/appservice/api" appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
"github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/httputil"
"github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/clientapi/jsonerror"
"github.com/matrix-org/dendrite/internal/eventutil"
roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/roomserver/version" "github.com/matrix-org/dendrite/roomserver/version"
"github.com/matrix-org/dendrite/setup/config" "github.com/matrix-org/dendrite/setup/config"
userapi "github.com/matrix-org/dendrite/userapi/api" userapi "github.com/matrix-org/dendrite/userapi/api"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
"github.com/sirupsen/logrus"
) )
type upgradeRoomRequest struct { type upgradeRoomRequest struct {
@ -57,38 +60,29 @@ func UpgradeRoom(
} }
} }
upgradeReq := roomserverAPI.PerformRoomUpgradeRequest{ newRoomID, err := rsAPI.PerformRoomUpgrade(req.Context(), roomID, device.UserID, gomatrixserverlib.RoomVersion(r.NewVersion))
UserID: device.UserID, switch e := err.(type) {
RoomID: roomID, case nil:
RoomVersion: gomatrixserverlib.RoomVersion(r.NewVersion), case roomserverAPI.ErrNotAllowed:
} return util.JSONResponse{
upgradeResp := roomserverAPI.PerformRoomUpgradeResponse{} Code: http.StatusForbidden,
JSON: jsonerror.Forbidden(e.Error()),
if err := rsAPI.PerformRoomUpgrade(req.Context(), &upgradeReq, &upgradeResp); err != nil { }
return jsonerror.InternalAPIError(req.Context(), err) default:
} if errors.Is(err, eventutil.ErrRoomNoExists) {
if upgradeResp.Error != nil {
if upgradeResp.Error.Code == roomserverAPI.PerformErrorNoRoom {
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusNotFound, Code: http.StatusNotFound,
JSON: jsonerror.NotFound("Room does not exist"), 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()
} }
logrus.WithError(err).Errorf("Error: %#v", err)
return jsonerror.InternalServerError()
} }
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusOK, Code: http.StatusOK,
JSON: upgradeRoomResponse{ JSON: upgradeRoomResponse{
ReplacementRoom: upgradeResp.NewRoomID, ReplacementRoom: newRoomID,
}, },
} }
} }

View file

@ -169,7 +169,7 @@ type ClientRoomserverAPI interface {
GetAliasesForRoomID(ctx context.Context, req *GetAliasesForRoomIDRequest, res *GetAliasesForRoomIDResponse) error GetAliasesForRoomID(ctx context.Context, req *GetAliasesForRoomIDRequest, res *GetAliasesForRoomIDResponse) error
// PerformRoomUpgrade upgrades a room to a newer version // PerformRoomUpgrade upgrades a room to a newer version
PerformRoomUpgrade(ctx context.Context, req *PerformRoomUpgradeRequest, resp *PerformRoomUpgradeResponse) 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) PerformAdminEvacuateRoom(ctx context.Context, roomID string) (affected []string, err error)
PerformAdminEvacuateUser(ctx context.Context, userID string) (affected []string, err error) PerformAdminEvacuateUser(ctx context.Context, userID string) (affected []string, err error)
PerformAdminPurgeRoom(ctx context.Context, roomID string) error PerformAdminPurgeRoom(ctx context.Context, roomID string) error

View file

@ -1,52 +1,10 @@
package api package api
import ( import (
"fmt"
"net/http"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/gomatrixserverlib/fclient" "github.com/matrix-org/gomatrixserverlib/fclient"
"github.com/matrix-org/gomatrixserverlib/spec" "github.com/matrix-org/gomatrixserverlib/spec"
"github.com/matrix-org/util" "github.com/matrix-org/util"
"github.com/matrix-org/dendrite/clientapi/jsonerror"
)
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 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),
}
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
// PerformErrorNoRoom means that the room being joined doesn't exist.
PerformErrorNoRoom PerformErrorCode = 3
) )
type PerformJoinRequest struct { type PerformJoinRequest struct {
@ -150,14 +108,3 @@ type PerformForgetRequest struct {
} }
type PerformForgetResponse 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
}

View file

@ -44,46 +44,29 @@ type fledglingEvent struct {
// PerformRoomUpgrade upgrades a room from one version to another // PerformRoomUpgrade upgrades a room from one version to another
func (r *Upgrader) PerformRoomUpgrade( func (r *Upgrader) PerformRoomUpgrade(
ctx context.Context, ctx context.Context,
req *api.PerformRoomUpgradeRequest, roomID, userID string, roomVersion gomatrixserverlib.RoomVersion,
res *api.PerformRoomUpgradeResponse, ) (newRoomID string, err error) {
) error { return r.performRoomUpgrade(ctx, roomID, userID, roomVersion)
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
} }
func (r *Upgrader) performRoomUpgrade( func (r *Upgrader) performRoomUpgrade(
ctx context.Context, ctx context.Context,
req *api.PerformRoomUpgradeRequest, roomID, userID string, roomVersion gomatrixserverlib.RoomVersion,
) (string, *api.PerformError) { ) (string, error) {
roomID := req.RoomID
userID := req.UserID
_, userDomain, err := r.Cfg.Matrix.SplitLocalID('@', userID) _, userDomain, err := r.Cfg.Matrix.SplitLocalID('@', userID)
if err != nil { if err != nil {
return "", &api.PerformError{ return "", api.ErrNotAllowed{Err: fmt.Errorf("error validating the user ID")}
Code: api.PerformErrorNotAllowed,
Msg: "Error validating the user ID",
}
} }
evTime := time.Now() evTime := time.Now()
// Return an immediate error if the room does not exist // Return an immediate error if the room does not exist
if err := r.validateRoomExists(ctx, roomID); err != nil { if err := r.validateRoomExists(ctx, roomID); err != nil {
return "", &api.PerformError{ return "", err
Code: api.PerformErrorNoRoom,
Msg: "Error validating that the room exists",
}
} }
// 1. Check if the user is authorized to actually perform the upgrade (can send m.room.tombstone) // 1. Check if the user is authorized to actually perform the upgrade (can send m.room.tombstone)
if !r.userIsAuthorized(ctx, userID, roomID) { if !r.userIsAuthorized(ctx, userID, roomID) {
return "", &api.PerformError{ return "", api.ErrNotAllowed{Err: fmt.Errorf("You don't have permission to upgrade the room, power level too low.")}
Code: api.PerformErrorNotAllowed,
Msg: "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 // TODO (#267): Check room ID doesn't clash with an existing one, and we
@ -96,9 +79,7 @@ func (r *Upgrader) performRoomUpgrade(
} }
oldRoomRes := &api.QueryLatestEventsAndStateResponse{} oldRoomRes := &api.QueryLatestEventsAndStateResponse{}
if err := r.URSAPI.QueryLatestEventsAndState(ctx, oldRoomReq, oldRoomRes); err != nil { if err := r.URSAPI.QueryLatestEventsAndState(ctx, oldRoomReq, oldRoomRes); err != nil {
return "", &api.PerformError{ return "", fmt.Errorf("Failed to get latest state: %s", err)
Msg: fmt.Sprintf("Failed to get latest state: %s", err),
}
} }
// Make the tombstone event // Make the tombstone event
@ -109,13 +90,13 @@ func (r *Upgrader) performRoomUpgrade(
// Generate the initial events we need to send into the new room. This includes copied state events and bans // 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 // 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 { if pErr != nil {
return "", pErr return "", pErr
} }
// Send the setup events to the new room // 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 return "", pErr
} }
@ -147,22 +128,15 @@ func (r *Upgrader) performRoomUpgrade(
return newRoomID, nil 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{ oldPowerLevelsEvent := api.GetStateEvent(ctx, r.URSAPI, roomID, gomatrixserverlib.StateKeyTuple{
EventType: spec.MRoomPowerLevels, EventType: spec.MRoomPowerLevels,
StateKey: "", StateKey: "",
}) })
powerLevelContent, err := oldPowerLevelsEvent.PowerLevels() return 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
} }
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) restrictedPowerLevelContent, pErr := r.getRoomPowerLevels(ctx, roomID)
if pErr != nil { if pErr != nil {
return pErr return pErr
@ -184,54 +158,46 @@ func (r *Upgrader) restrictOldRoomPowerLevels(ctx context.Context, evTime time.T
StateKey: "", StateKey: "",
Content: restrictedPowerLevelContent, Content: restrictedPowerLevelContent,
}) })
if resErr != nil {
if resErr.Code == api.PerformErrorNotAllowed { switch resErr.(type) {
util.GetLogger(ctx).WithField(logrus.ErrorKey, resErr).Warn("UpgradeRoom: Could not restrict power levels in old room") case api.ErrNotAllowed:
} else { util.GetLogger(ctx).WithField(logrus.ErrorKey, resErr).Warn("UpgradeRoom: Could not restrict power levels in old room")
return resErr case nil:
} return r.sendHeaderedEvent(ctx, userDomain, restrictedPowerLevelsHeadered, api.DoNotSendToOtherServers)
} else { default:
if resErr = r.sendHeaderedEvent(ctx, userDomain, restrictedPowerLevelsHeadered, api.DoNotSendToOtherServers); resErr != nil { return resErr
return resErr
}
} }
return nil return nil
} }
func moveLocalAliases(ctx context.Context, func moveLocalAliases(ctx context.Context,
roomID, newRoomID, userID string, roomID, newRoomID, userID string,
URSAPI api.RoomserverInternalAPI) *api.PerformError { URSAPI api.RoomserverInternalAPI,
var err error ) (err error) {
aliasReq := api.GetAliasesForRoomIDRequest{RoomID: roomID} aliasReq := api.GetAliasesForRoomIDRequest{RoomID: roomID}
aliasRes := api.GetAliasesForRoomIDResponse{} aliasRes := api.GetAliasesForRoomIDResponse{}
if err = URSAPI.GetAliasesForRoomID(ctx, &aliasReq, &aliasRes); err != nil { if err = URSAPI.GetAliasesForRoomID(ctx, &aliasReq, &aliasRes); err != nil {
return &api.PerformError{ return fmt.Errorf("Failed to get old room aliases: %w", err)
Msg: fmt.Sprintf("Failed to get old room aliases: %s", err),
}
} }
for _, alias := range aliasRes.Aliases { for _, alias := range aliasRes.Aliases {
removeAliasReq := api.RemoveRoomAliasRequest{UserID: userID, Alias: alias} removeAliasReq := api.RemoveRoomAliasRequest{UserID: userID, Alias: alias}
removeAliasRes := api.RemoveRoomAliasResponse{} removeAliasRes := api.RemoveRoomAliasResponse{}
if err = URSAPI.RemoveRoomAlias(ctx, &removeAliasReq, &removeAliasRes); err != nil { if err = URSAPI.RemoveRoomAlias(ctx, &removeAliasReq, &removeAliasRes); err != nil {
return &api.PerformError{ return fmt.Errorf("Failed to remove old room alias: %w", err)
Msg: fmt.Sprintf("Failed to remove old room alias: %s", err),
}
} }
setAliasReq := api.SetRoomAliasRequest{UserID: userID, Alias: alias, RoomID: newRoomID} setAliasReq := api.SetRoomAliasRequest{UserID: userID, Alias: alias, RoomID: newRoomID}
setAliasRes := api.SetRoomAliasResponse{} setAliasRes := api.SetRoomAliasResponse{}
if err = URSAPI.SetRoomAlias(ctx, &setAliasReq, &setAliasRes); err != nil { if err = URSAPI.SetRoomAlias(ctx, &setAliasReq, &setAliasRes); err != nil {
return &api.PerformError{ return fmt.Errorf("Failed to set new room alias: %w", err)
Msg: fmt.Sprintf("Failed to set new room alias: %s", err),
}
} }
} }
return nil 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 { for _, event := range oldRoom.StateEvents {
if event.Type() != spec.MRoomCanonicalAlias || !event.StateKeyEquals("") { if event.Type() != spec.MRoomCanonicalAlias || !event.StateKeyEquals("") {
continue continue
@ -241,9 +207,7 @@ func (r *Upgrader) clearOldCanonicalAliasEvent(ctx context.Context, oldRoom *api
AltAliases []string `json:"alt_aliases"` AltAliases []string `json:"alt_aliases"`
} }
if err := json.Unmarshal(event.Content(), &aliasContent); err != nil { if err := json.Unmarshal(event.Content(), &aliasContent); err != nil {
return &api.PerformError{ return fmt.Errorf("failed to unmarshal canonical aliases: %w", err)
Msg: fmt.Sprintf("Failed to unmarshal canonical aliases: %s", err),
}
} }
if aliasContent.Alias == "" && len(aliasContent.AltAliases) == 0 { if aliasContent.Alias == "" && len(aliasContent.AltAliases) == 0 {
// There are no canonical aliases to clear, therefore do nothing. // There are no canonical aliases to clear, therefore do nothing.
@ -255,30 +219,25 @@ func (r *Upgrader) clearOldCanonicalAliasEvent(ctx context.Context, oldRoom *api
Type: spec.MRoomCanonicalAlias, Type: spec.MRoomCanonicalAlias,
Content: map[string]interface{}{}, Content: map[string]interface{}{},
}) })
if resErr != nil { switch resErr.(type) {
if resErr.Code == api.PerformErrorNotAllowed { case api.ErrNotAllowed:
util.GetLogger(ctx).WithField(logrus.ErrorKey, resErr).Warn("UpgradeRoom: Could not set empty canonical alias event in old room") util.GetLogger(ctx).WithField(logrus.ErrorKey, resErr).Warn("UpgradeRoom: Could not set empty canonical alias event in old room")
} else { case nil:
return resErr return r.sendHeaderedEvent(ctx, userDomain, emptyCanonicalAliasEvent, api.DoNotSendToOtherServers)
} default:
} else { return resErr
if resErr = r.sendHeaderedEvent(ctx, userDomain, emptyCanonicalAliasEvent, api.DoNotSendToOtherServers); resErr != nil {
return resErr
}
} }
return nil 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 // check if the old room was published
var pubQueryRes api.QueryPublishedRoomsResponse var pubQueryRes api.QueryPublishedRoomsResponse
err := r.URSAPI.QueryPublishedRooms(ctx, &api.QueryPublishedRoomsRequest{ err := r.URSAPI.QueryPublishedRooms(ctx, &api.QueryPublishedRoomsRequest{
RoomID: roomID, RoomID: roomID,
}, &pubQueryRes) }, &pubQueryRes)
if err != nil { if err != nil {
return &api.PerformError{ return err
Msg: "QueryPublishedRooms failed",
}
} }
// if the old room is published (was public), publish the new room // if the old room is published (was public), publish the new room
@ -316,10 +275,7 @@ func (r *Upgrader) validateRoomExists(ctx context.Context, roomID string) error
verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID} verReq := api.QueryRoomVersionForRoomRequest{RoomID: roomID}
verRes := api.QueryRoomVersionForRoomResponse{} verRes := api.QueryRoomVersionForRoomResponse{}
if err := r.URSAPI.QueryRoomVersionForRoom(ctx, &verReq, &verRes); err != nil { if err := r.URSAPI.QueryRoomVersionForRoom(ctx, &verReq, &verRes); err != nil {
return &api.PerformError{ return eventutil.ErrRoomNoExists
Code: api.PerformErrorNoRoom,
Msg: "Room does not exist",
}
} }
return nil return nil
} }
@ -343,7 +299,7 @@ func (r *Upgrader) userIsAuthorized(ctx context.Context, userID, roomID string,
} }
// nolint:gocyclo // nolint:gocyclo
func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.QueryLatestEventsAndStateResponse, userID, roomID, newVersion string, tombstoneEvent *gomatrixserverlib.HeaderedEvent) ([]fledglingEvent, *api.PerformError) { func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.QueryLatestEventsAndStateResponse, userID, roomID string, newVersion gomatrixserverlib.RoomVersion, tombstoneEvent *gomatrixserverlib.HeaderedEvent) ([]fledglingEvent, error) {
state := make(map[gomatrixserverlib.StateKeyTuple]*gomatrixserverlib.HeaderedEvent, len(oldRoom.StateEvents)) state := make(map[gomatrixserverlib.StateKeyTuple]*gomatrixserverlib.HeaderedEvent, len(oldRoom.StateEvents))
for _, event := range oldRoom.StateEvents { for _, event := range oldRoom.StateEvents {
if event.StateKey() == nil { if event.StateKey() == nil {
@ -382,9 +338,7 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query
// old room state. Check that they are there. // old room state. Check that they are there.
for tuple := range override { for tuple := range override {
if _, ok := state[tuple]; !ok { if _, ok := state[tuple]; !ok {
return nil, &api.PerformError{ return nil, fmt.Errorf("essential event of type %q state key %q is missing", tuple.EventType, tuple.StateKey)
Msg: fmt.Sprintf("Essential event of type %q state key %q is missing", tuple.EventType, tuple.StateKey),
}
} }
} }
@ -431,9 +385,7 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query
powerLevelContent, err := oldPowerLevelsEvent.PowerLevels() powerLevelContent, err := oldPowerLevelsEvent.PowerLevels()
if err != nil { if err != nil {
util.GetLogger(ctx).WithError(err).Error() util.GetLogger(ctx).WithError(err).Error()
return nil, &api.PerformError{ return nil, fmt.Errorf("Power level event content was invalid")
Msg: "Power level event content was invalid",
}
} }
tempPowerLevelsEvent, powerLevelsOverridden := createTemporaryPowerLevels(powerLevelContent, userID) tempPowerLevelsEvent, powerLevelsOverridden := createTemporaryPowerLevels(powerLevelContent, userID)
@ -497,7 +449,7 @@ func (r *Upgrader) generateInitialEvents(ctx context.Context, oldRoom *api.Query
return eventsToMake, nil 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 err error
var builtEvents []*gomatrixserverlib.HeaderedEvent var builtEvents []*gomatrixserverlib.HeaderedEvent
authEvents := gomatrixserverlib.NewAuthEvents(nil) authEvents := gomatrixserverlib.NewAuthEvents(nil)
@ -513,34 +465,27 @@ func (r *Upgrader) sendInitialEvents(ctx context.Context, evTime time.Time, user
} }
err = builder.SetContent(e.Content) err = builder.SetContent(e.Content)
if err != nil { if err != nil {
return &api.PerformError{ return fmt.Errorf("failed to set content of new %q event: %w", builder.Type, err)
Msg: fmt.Sprintf("Failed to set content of new %q event: %s", builder.Type, err),
}
} }
if i > 0 { if i > 0 {
builder.PrevEvents = []gomatrixserverlib.EventReference{builtEvents[i-1].EventReference()} builder.PrevEvents = []gomatrixserverlib.EventReference{builtEvents[i-1].EventReference()}
} }
var event *gomatrixserverlib.Event 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 { if err != nil {
return &api.PerformError{ return fmt.Errorf("failed to build new %q event: %w", builder.Type, err)
Msg: fmt.Sprintf("Failed to build new %q event: %s", builder.Type, err),
}
} }
if err = gomatrixserverlib.Allowed(event, &authEvents); err != nil { if err = gomatrixserverlib.Allowed(event, &authEvents); err != nil {
return &api.PerformError{ return fmt.Errorf("Failed to auth new %q event: %w", builder.Type, err)
Msg: fmt.Sprintf("Failed to auth new %q event: %s", builder.Type, err),
}
} }
// Add the event to the list of auth events // Add the event to the list of auth events
builtEvents = append(builtEvents, event.Headered(gomatrixserverlib.RoomVersion(newVersion))) builtEvents = append(builtEvents, event.Headered(newVersion))
err = authEvents.AddEvent(event) err = authEvents.AddEvent(event)
if err != nil { if err != nil {
return &api.PerformError{ return fmt.Errorf("failed to add new %q event to auth set: %w", builder.Type, err)
Msg: fmt.Sprintf("Failed to add new %q event to auth set: %s", builder.Type, err),
}
} }
} }
@ -554,9 +499,7 @@ func (r *Upgrader) sendInitialEvents(ctx context.Context, evTime time.Time, user
}) })
} }
if err = api.SendInputRoomEvents(ctx, r.URSAPI, userDomain, inputs, false); err != nil { if err = api.SendInputRoomEvents(ctx, r.URSAPI, userDomain, inputs, false); err != nil {
return &api.PerformError{ return fmt.Errorf("failed to send new room %q to roomserver: %w", newRoomID, err)
Msg: fmt.Sprintf("Failed to send new room %q to roomserver: %s", newRoomID, err),
}
} }
return nil return nil
} }
@ -565,7 +508,7 @@ func (r *Upgrader) makeTombstoneEvent(
ctx context.Context, ctx context.Context,
evTime time.Time, evTime time.Time,
userID, roomID, newRoomID string, userID, roomID, newRoomID string,
) (*gomatrixserverlib.HeaderedEvent, *api.PerformError) { ) (*gomatrixserverlib.HeaderedEvent, error) {
content := map[string]interface{}{ content := map[string]interface{}{
"body": "This room has been replaced", "body": "This room has been replaced",
"replacement_room": newRoomID, "replacement_room": newRoomID,
@ -577,7 +520,7 @@ func (r *Upgrader) makeTombstoneEvent(
return r.makeHeaderedEvent(ctx, evTime, userID, roomID, event) return r.makeHeaderedEvent(ctx, evTime, userID, roomID, event)
} }
func (r *Upgrader) makeHeaderedEvent(ctx context.Context, evTime time.Time, userID, roomID string, event fledglingEvent) (*gomatrixserverlib.HeaderedEvent, *api.PerformError) { func (r *Upgrader) makeHeaderedEvent(ctx context.Context, evTime time.Time, userID, roomID string, event fledglingEvent) (*gomatrixserverlib.HeaderedEvent, error) {
builder := gomatrixserverlib.EventBuilder{ builder := gomatrixserverlib.EventBuilder{
Sender: userID, Sender: userID,
RoomID: roomID, RoomID: roomID,
@ -586,47 +529,27 @@ func (r *Upgrader) makeHeaderedEvent(ctx context.Context, evTime time.Time, user
} }
err := builder.SetContent(event.Content) err := builder.SetContent(event.Content)
if err != nil { if err != nil {
return nil, &api.PerformError{ return nil, fmt.Errorf("failed to set new %q event content: %w", builder.Type, err)
Msg: fmt.Sprintf("Failed to set new %q event content: %s", builder.Type, err),
}
} }
// Get the sender domain. // Get the sender domain.
_, senderDomain, serr := r.Cfg.Matrix.SplitLocalID('@', builder.Sender) _, senderDomain, serr := r.Cfg.Matrix.SplitLocalID('@', builder.Sender)
if serr != nil { if serr != nil {
return nil, &api.PerformError{ return nil, fmt.Errorf("Failed to split user ID %q: %w", builder.Sender, err)
Msg: fmt.Sprintf("Failed to split user ID %q: %s", builder.Sender, err),
}
} }
identity, err := r.Cfg.Matrix.SigningIdentityFor(senderDomain) identity, err := r.Cfg.Matrix.SigningIdentityFor(senderDomain)
if err != nil { if err != nil {
return nil, &api.PerformError{ return nil, fmt.Errorf("failed to get signing identity for %q: %w", senderDomain, err)
Msg: fmt.Sprintf("Failed to get signing identity for %q: %s", senderDomain, err),
}
} }
var queryRes api.QueryLatestEventsAndStateResponse var queryRes api.QueryLatestEventsAndStateResponse
headeredEvent, err := eventutil.QueryAndBuildEvent(ctx, &builder, r.Cfg.Matrix, identity, evTime, r.URSAPI, &queryRes) headeredEvent, err := eventutil.QueryAndBuildEvent(ctx, &builder, r.Cfg.Matrix, identity, evTime, r.URSAPI, &queryRes)
if err == eventutil.ErrRoomNoExists { if err == eventutil.ErrRoomNoExists {
return nil, &api.PerformError{ return nil, err
Code: api.PerformErrorNoRoom,
Msg: "Room does not exist",
}
} else if e, ok := err.(gomatrixserverlib.BadJSONError); ok { } else if e, ok := err.(gomatrixserverlib.BadJSONError); ok {
return nil, &api.PerformError{ return nil, e
Msg: e.Error(),
}
} else if e, ok := err.(gomatrixserverlib.EventValidationError); ok { } else if e, ok := err.(gomatrixserverlib.EventValidationError); ok {
if e.Code == gomatrixserverlib.EventValidationTooLarge { return nil, e
return nil, &api.PerformError{
Msg: e.Error(),
}
}
return nil, &api.PerformError{
Msg: e.Error(),
}
} else if err != nil { } else if err != nil {
return nil, &api.PerformError{ return nil, fmt.Errorf("failed to build new %q event: %w", builder.Type, err)
Msg: fmt.Sprintf("Failed to build new %q event: %s", builder.Type, err),
}
} }
// check to see if this user can perform this operation // check to see if this user can perform this operation
stateEvents := make([]*gomatrixserverlib.Event, len(queryRes.StateEvents)) stateEvents := make([]*gomatrixserverlib.Event, len(queryRes.StateEvents))
@ -635,10 +558,7 @@ func (r *Upgrader) makeHeaderedEvent(ctx context.Context, evTime time.Time, user
} }
provider := gomatrixserverlib.NewAuthEvents(stateEvents) provider := gomatrixserverlib.NewAuthEvents(stateEvents)
if err = gomatrixserverlib.Allowed(headeredEvent.Event, &provider); err != nil { if err = gomatrixserverlib.Allowed(headeredEvent.Event, &provider); err != nil {
return nil, &api.PerformError{ 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?
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 headeredEvent, nil return headeredEvent, nil
@ -686,7 +606,7 @@ func (r *Upgrader) sendHeaderedEvent(
serverName spec.ServerName, serverName spec.ServerName,
headeredEvent *gomatrixserverlib.HeaderedEvent, headeredEvent *gomatrixserverlib.HeaderedEvent,
sendAsServer string, sendAsServer string,
) *api.PerformError { ) error {
var inputs []api.InputRoomEvent var inputs []api.InputRoomEvent
inputs = append(inputs, api.InputRoomEvent{ inputs = append(inputs, api.InputRoomEvent{
Kind: api.KindNew, Kind: api.KindNew,
@ -694,11 +614,5 @@ func (r *Upgrader) sendHeaderedEvent(
Origin: serverName, Origin: serverName,
SendAsServer: sendAsServer, SendAsServer: sendAsServer,
}) })
if err := api.SendInputRoomEvents(ctx, r.URSAPI, serverName, inputs, false); err != nil { return api.SendInputRoomEvents(ctx, r.URSAPI, serverName, inputs, false)
return &api.PerformError{
Msg: fmt.Sprintf("Failed to send new %q event to roomserver: %s", headeredEvent.Type(), err),
}
}
return nil
} }