PerformInvite: bugfix and rejig control flow (#2137)
* PerformInvite: bugfix and rejig control flow Local clients would not be notified of invites to rooms Dendrite had already joined in all cases due to not returning an `api.OutputNewInviteEvent` for local invites. We now do this. This was an easy mistake to make due to the control flow of the function which doesn't handle the happy case at the end of the function and instead forks the function depending on if the invite was via federation or not. This has now been changed to handle the federated invite as if it were an error (in that we check it, do it and bail out) rather than outstay our welcome. This ends up with the local invite being the happy case, which now both sends an `InputRoomEvent` to the roomserver _and_ a `api.OutputNewInviteEvent` is returned. * Don't send invite pokes in PerformInvite * Move event ID into logger
This commit is contained in:
parent
a09d71d231
commit
2dee706f9e
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/matrix-org/dendrite/roomserver/types"
|
"github.com/matrix-org/dendrite/roomserver/types"
|
||||||
"github.com/matrix-org/dendrite/setup/config"
|
"github.com/matrix-org/dendrite/setup/config"
|
||||||
"github.com/matrix-org/gomatrixserverlib"
|
"github.com/matrix-org/gomatrixserverlib"
|
||||||
|
"github.com/matrix-org/util"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -54,18 +55,23 @@ func (r *Inviter) PerformInvite(
|
||||||
return nil, fmt.Errorf("failed to load RoomInfo: %w", err)
|
return nil, fmt.Errorf("failed to load RoomInfo: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.WithFields(log.Fields{
|
|
||||||
"event_id": event.EventID(),
|
|
||||||
"room_id": roomID,
|
|
||||||
"room_version": req.RoomVersion,
|
|
||||||
"target_user_id": targetUserID,
|
|
||||||
"room_info_exists": info != nil,
|
|
||||||
}).Debug("processing invite event")
|
|
||||||
|
|
||||||
_, domain, _ := gomatrixserverlib.SplitID('@', targetUserID)
|
_, domain, _ := gomatrixserverlib.SplitID('@', targetUserID)
|
||||||
isTargetLocal := domain == r.Cfg.Matrix.ServerName
|
isTargetLocal := domain == r.Cfg.Matrix.ServerName
|
||||||
isOriginLocal := event.Origin() == r.Cfg.Matrix.ServerName
|
isOriginLocal := event.Origin() == r.Cfg.Matrix.ServerName
|
||||||
|
|
||||||
|
logger := util.GetLogger(ctx).WithFields(map[string]interface{}{
|
||||||
|
"inviter": event.Sender(),
|
||||||
|
"invitee": *event.StateKey(),
|
||||||
|
"room_id": roomID,
|
||||||
|
"event_id": event.EventID(),
|
||||||
|
})
|
||||||
|
logger.WithFields(log.Fields{
|
||||||
|
"room_version": req.RoomVersion,
|
||||||
|
"room_info_exists": info != nil,
|
||||||
|
"target_local": isTargetLocal,
|
||||||
|
"origin_local": isOriginLocal,
|
||||||
|
}).Debug("processing invite event")
|
||||||
|
|
||||||
inviteState := req.InviteRoomState
|
inviteState := req.InviteRoomState
|
||||||
if len(inviteState) == 0 && info != nil {
|
if len(inviteState) == 0 && info != nil {
|
||||||
var is []gomatrixserverlib.InviteV2StrippedState
|
var is []gomatrixserverlib.InviteV2StrippedState
|
||||||
|
@ -122,23 +128,49 @@ func (r *Inviter) PerformInvite(
|
||||||
Code: api.PerformErrorNotAllowed,
|
Code: api.PerformErrorNotAllowed,
|
||||||
Msg: "User is already joined to room",
|
Msg: "User is already joined to room",
|
||||||
}
|
}
|
||||||
|
logger.Debugf("user already joined")
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if isOriginLocal {
|
if !isOriginLocal {
|
||||||
|
// The invite originated over federation. Process the membership
|
||||||
|
// update, which will notify the sync API etc about the incoming
|
||||||
|
// invite. We do NOT send an InputRoomEvent for the invite as it
|
||||||
|
// will never pass auth checks due to lacking room state, but we
|
||||||
|
// still need to tell the client about the invite so we can accept
|
||||||
|
// it, hence we return an output event to send to the sync api.
|
||||||
|
updater, err := r.DB.MembershipUpdater(ctx, roomID, targetUserID, isTargetLocal, req.RoomVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("r.DB.MembershipUpdater: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
unwrapped := event.Unwrap()
|
||||||
|
outputUpdates, err := helpers.UpdateToInviteMembership(updater, unwrapped, nil, req.Event.RoomVersion)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("updateToInviteMembership: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = updater.Commit(); err != nil {
|
||||||
|
return nil, fmt.Errorf("updater.Commit: %w", err)
|
||||||
|
}
|
||||||
|
logger.Debugf("updated membership to invite and sending invite OutputEvent")
|
||||||
|
return outputUpdates, nil
|
||||||
|
}
|
||||||
|
|
||||||
// The invite originated locally. Therefore we have a responsibility to
|
// The invite originated locally. Therefore we have a responsibility to
|
||||||
// try and see if the user is allowed to make this invite. We can't do
|
// try and see if the user is allowed to make this invite. We can't do
|
||||||
// this for invites coming in over federation - we have to take those on
|
// this for invites coming in over federation - we have to take those on
|
||||||
// trust.
|
// trust.
|
||||||
_, err = helpers.CheckAuthEvents(ctx, r.DB, event, event.AuthEventIDs())
|
_, err = helpers.CheckAuthEvents(ctx, r.DB, event, event.AuthEventIDs())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.WithError(err).WithField("event_id", event.EventID()).WithField("auth_event_ids", event.AuthEventIDs()).Error(
|
logger.WithError(err).WithField("event_id", event.EventID()).WithField("auth_event_ids", event.AuthEventIDs()).Error(
|
||||||
"processInviteEvent.checkAuthEvents failed for event",
|
"processInviteEvent.checkAuthEvents failed for event",
|
||||||
)
|
)
|
||||||
res.Error = &api.PerformError{
|
res.Error = &api.PerformError{
|
||||||
Msg: err.Error(),
|
Msg: err.Error(),
|
||||||
Code: api.PerformErrorNotAllowed,
|
Code: api.PerformErrorNotAllowed,
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the invite originated from us and the target isn't local then we
|
// If the invite originated from us and the target isn't local then we
|
||||||
|
@ -157,16 +189,18 @@ func (r *Inviter) PerformInvite(
|
||||||
Msg: err.Error(),
|
Msg: err.Error(),
|
||||||
Code: api.PerformErrorNotAllowed,
|
Code: api.PerformErrorNotAllowed,
|
||||||
}
|
}
|
||||||
log.WithError(err).WithField("event_id", event.EventID()).Error("r.FSAPI.PerformInvite failed")
|
logger.WithError(err).WithField("event_id", event.EventID()).Error("r.FSAPI.PerformInvite failed")
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
event = fsRes.Event
|
event = fsRes.Event
|
||||||
|
logger.Debugf("Federated PerformInvite success with event ID %s", event.EventID())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the invite event to the roomserver input stream. This will
|
// Send the invite event to the roomserver input stream. This will
|
||||||
// notify existing users in the room about the invite, update the
|
// notify existing users in the room about the invite, update the
|
||||||
// membership table and ensure that the event is ready and available
|
// membership table and ensure that the event is ready and available
|
||||||
// to use as an auth event when accepting the invite.
|
// to use as an auth event when accepting the invite.
|
||||||
|
// It will NOT notify the invitee of this invite.
|
||||||
inputReq := &api.InputRoomEventsRequest{
|
inputReq := &api.InputRoomEventsRequest{
|
||||||
InputRoomEvents: []api.InputRoomEvent{
|
InputRoomEvents: []api.InputRoomEvent{
|
||||||
{
|
{
|
||||||
|
@ -184,31 +218,12 @@ func (r *Inviter) PerformInvite(
|
||||||
Msg: fmt.Sprintf("r.InputRoomEvents: %s", err.Error()),
|
Msg: fmt.Sprintf("r.InputRoomEvents: %s", err.Error()),
|
||||||
Code: api.PerformErrorNotAllowed,
|
Code: api.PerformErrorNotAllowed,
|
||||||
}
|
}
|
||||||
log.WithError(err).WithField("event_id", event.EventID()).Error("r.InputRoomEvents failed")
|
logger.WithError(err).WithField("event_id", event.EventID()).Error("r.InputRoomEvents failed")
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// The invite originated over federation. Process the membership
|
|
||||||
// update, which will notify the sync API etc about the incoming
|
|
||||||
// invite.
|
|
||||||
updater, err := r.DB.MembershipUpdater(ctx, roomID, targetUserID, isTargetLocal, req.RoomVersion)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("r.DB.MembershipUpdater: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
unwrapped := event.Unwrap()
|
|
||||||
outputUpdates, err := helpers.UpdateToInviteMembership(updater, unwrapped, nil, req.Event.RoomVersion)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("updateToInviteMembership: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = updater.Commit(); err != nil {
|
|
||||||
return nil, fmt.Errorf("updater.Commit: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return outputUpdates, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Don't notify the sync api of this event in the same way as a federated invite so the invitee
|
||||||
|
// gets the invite, as the roomserver will do this when it processes the m.room.member invite.
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue