mirror of
https://github.com/hoernschen/dendrite.git
synced 2025-07-29 12:42:46 +00:00
Remove PerformError
(#3066)
This removes `PerformError`, which was needed when we still had polylith. This removes quite a bunch of ```go if err != nil { return err } if err := res.Error; err != nil { return err.JSONResponse() } ``` Hopefully can be read commit by commit. [skip ci]
This commit is contained in:
parent
1432743d1a
commit
6b47cf0f6a
22 changed files with 469 additions and 903 deletions
|
@ -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)
|
||||
roomIDs, err := r.DB.GetRoomsByMembership(ctx, userID, spec.Join)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
inviteRoomIDs, err := r.DB.GetRoomsByMembership(ctx, req.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
|
||||
}
|
||||
|
||||
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", req.RoomID).Warn("Room purged from roomserver")
|
||||
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
|
||||
}
|
||||
|
||||
return r.Inputer.OutputProducer.ProduceRoomEvents(req.RoomID, []api.OutputEvent{
|
||||
logrus.WithField("room_id", roomID).Warn("Room purged from roomserver")
|
||||
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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{
|
||||
{
|
||||
Type: api.OutputTypeRetirePeek,
|
||||
RetirePeek: &api.OutputRetirePeek{
|
||||
RoomID: req.RoomID,
|
||||
UserID: req.UserID,
|
||||
DeviceID: req.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
|
||||
return r.Inputer.OutputProducer.ProduceRoomEvents(roomID, []api.OutputEvent{
|
||||
{
|
||||
Type: api.OutputTypeRetirePeek,
|
||||
RetirePeek: &api.OutputRetirePeek{
|
||||
RoomID: roomID,
|
||||
UserID: userID,
|
||||
DeviceID: deviceID,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue