Fix synchronous invites

This commit is contained in:
Neil Alexander 2020-08-14 15:12:38 +01:00
parent 96814d436a
commit db57d7e00b
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944
6 changed files with 63 additions and 68 deletions

View file

@ -371,10 +371,7 @@ func createRoom(
} }
// If this is a direct message then we should invite the participants. // If this is a direct message then we should invite the participants.
fmt.Println("INVITEES:")
for _, invitee := range r.Invite { for _, invitee := range r.Invite {
fmt.Println("*", invitee)
// Build the invite event. // Build the invite event.
inviteEvent, err := buildMembershipEvent( inviteEvent, err := buildMembershipEvent(
req.Context(), invitee, "", accountDB, device, gomatrixserverlib.Invite, req.Context(), invitee, "", accountDB, device, gomatrixserverlib.Invite,
@ -389,6 +386,10 @@ func createRoom(
var strippedState []gomatrixserverlib.InviteV2StrippedState var strippedState []gomatrixserverlib.InviteV2StrippedState
for _, event := range candidates { for _, event := range candidates {
switch event.Type() { switch event.Type() {
case gomatrixserverlib.MRoomName:
fallthrough
case gomatrixserverlib.MRoomCanonicalAlias:
fallthrough
case "m.room.encryption": // TODO: move this to gmsl case "m.room.encryption": // TODO: move this to gmsl
fallthrough fallthrough
case gomatrixserverlib.MRoomMember: case gomatrixserverlib.MRoomMember:

View file

@ -26,7 +26,6 @@ import (
"github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/clientapi/jsonerror"
"github.com/matrix-org/dendrite/clientapi/threepid" "github.com/matrix-org/dendrite/clientapi/threepid"
currentstateAPI "github.com/matrix-org/dendrite/currentstateserver/api" currentstateAPI "github.com/matrix-org/dendrite/currentstateserver/api"
federationSenderAPI "github.com/matrix-org/dendrite/federationsender/api"
"github.com/matrix-org/dendrite/internal/config" "github.com/matrix-org/dendrite/internal/config"
"github.com/matrix-org/dendrite/internal/eventutil" "github.com/matrix-org/dendrite/internal/eventutil"
"github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/api"
@ -173,7 +172,6 @@ func SendInvite(
req *http.Request, accountDB accounts.Database, device *userapi.Device, req *http.Request, accountDB accounts.Database, device *userapi.Device,
roomID string, cfg *config.ClientAPI, roomID string, cfg *config.ClientAPI,
rsAPI roomserverAPI.RoomserverInternalAPI, asAPI appserviceAPI.AppServiceQueryAPI, rsAPI roomserverAPI.RoomserverInternalAPI, asAPI appserviceAPI.AppServiceQueryAPI,
fsAPI federationSenderAPI.FederationSenderInternalAPI,
) util.JSONResponse { ) util.JSONResponse {
body, evTime, _, reqErr := extractRequestData(req, roomID, rsAPI) body, evTime, _, reqErr := extractRequestData(req, roomID, rsAPI)
if reqErr != nil { if reqErr != nil {

View file

@ -142,7 +142,7 @@ func Setup(
if err != nil { if err != nil {
return util.ErrorResponse(err) return util.ErrorResponse(err)
} }
return SendInvite(req, accountDB, device, vars["roomID"], cfg, rsAPI, asAPI, federationSender) return SendInvite(req, accountDB, device, vars["roomID"], cfg, rsAPI, asAPI)
}), }),
).Methods(http.MethodPost, http.MethodOptions) ).Methods(http.MethodPost, http.MethodOptions)
r0mux.Handle("/rooms/{roomID}/kick", r0mux.Handle("/rooms/{roomID}/kick",

View file

@ -144,7 +144,7 @@ func processInvite(
// Add the invite event to the roomserver. // Add the invite event to the roomserver.
if err := api.SendInvite( if err := api.SendInvite(
ctx, rsAPI, signedEvent.Headered(roomVer), strippedState, event.Origin(), nil, ctx, rsAPI, signedEvent.Headered(roomVer), strippedState, api.DoNotSendToOtherServers, nil,
); err != nil { ); err != nil {
util.GetLogger(ctx).WithError(err).Error("producer.SendInvite failed") util.GetLogger(ctx).WithError(err).Error("producer.SendInvite failed")
return jsonerror.InternalServerError() return jsonerror.InternalServerError()

View file

@ -16,6 +16,7 @@ package api
import ( import (
"context" "context"
"fmt"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
@ -100,6 +101,8 @@ func SendInvite(
inviteRoomState []gomatrixserverlib.InviteV2StrippedState, inviteRoomState []gomatrixserverlib.InviteV2StrippedState,
sendAsServer gomatrixserverlib.ServerName, txnID *TransactionID, sendAsServer gomatrixserverlib.ServerName, txnID *TransactionID,
) error { ) error {
// Start by sending the invite request into the roomserver. This will
// trigger the federation request amongst other things if needed.
request := &PerformInviteRequest{ request := &PerformInviteRequest{
Event: inviteEvent, Event: inviteEvent,
InviteRoomState: inviteRoomState, InviteRoomState: inviteRoomState,
@ -108,7 +111,28 @@ func SendInvite(
TransactionID: txnID, TransactionID: txnID,
} }
response := &PerformInviteResponse{} response := &PerformInviteResponse{}
return rsAPI.PerformInvite(ctx, request, response) if err := rsAPI.PerformInvite(ctx, request, response); err != nil {
return fmt.Errorf("rsAPI.PerformInvite: %w", err)
}
// Now send the invite event into the roomserver. If the room is known
// locally then this will succeed, notifying existing users in the room
// about the new invite. If the room isn't known locally then this will
// fail - and that's also OK.
inputReq := &InputRoomEventsRequest{
InputRoomEvents: []InputRoomEvent{
{
Kind: KindNew,
Event: inviteEvent,
AuthEventIDs: inviteEvent.AuthEventIDs(),
SendAsServer: DoNotSendToOtherServers,
},
},
}
inputRes := &InputRoomEventsResponse{}
_ = rsAPI.InputRoomEvents(ctx, inputReq, inputRes)
return nil
} }
// GetEvent returns the event or nil, even on errors. // GetEvent returns the event or nil, even on errors.

View file

@ -36,26 +36,26 @@ func (r *RoomserverInternalAPI) PerformInvite(
}).Info("processing invite event") }).Info("processing invite event")
_, domain, _ := gomatrixserverlib.SplitID('@', targetUserID) _, domain, _ := gomatrixserverlib.SplitID('@', targetUserID)
isTargetLocalUser := domain == r.Cfg.Matrix.ServerName isTargetLocal := domain == r.Cfg.Matrix.ServerName
isOriginLocalUser := event.Origin() == r.Cfg.Matrix.ServerName isOriginLocal := event.Origin() == r.Cfg.Matrix.ServerName
// If the invite originated from us and the target isn't local then we inviteState := req.InviteRoomState
// should try and send the invite over federation first. It might be if len(inviteState) == 0 {
// that the remote user doesn't exist, in which case we can give up if is, err := buildInviteStrippedState(ctx, r.DB, req); err == nil {
// processing here. inviteState = is
if isOriginLocalUser && !isTargetLocalUser {
fsReq := &federationSenderAPI.PerformInviteRequest{
RoomVersion: req.RoomVersion,
Event: req.Event,
} }
fsRes := &federationSenderAPI.PerformInviteResponse{}
if err := r.fsAPI.PerformInvite(ctx, fsReq, fsRes); err != nil {
return fmt.Errorf("r.fsAPI.PerformInvite: %w", err)
} }
event = fsRes.SignedEvent if len(inviteState) == 0 {
if err := event.SetUnsignedField("invite_room_state", struct{}{}); err != nil {
return err
}
} else {
if err := event.SetUnsignedField("invite_room_state", inviteState); err != nil {
return err
}
} }
updater, err := r.DB.MembershipUpdater(ctx, roomID, targetUserID, isTargetLocalUser, req.RoomVersion) updater, err := r.DB.MembershipUpdater(ctx, roomID, targetUserID, isTargetLocal, req.RoomVersion)
if err != nil { if err != nil {
return err return err
} }
@ -101,9 +101,9 @@ func (r *RoomserverInternalAPI) PerformInvite(
} }
} }
if isOriginLocal {
// check that the user is allowed to do this. We can only do this check if it is // check that the user is allowed to do this. We can only do this check if it is
// a local invite as we have the auth events, else we have to take it on trust. // a local invite as we have the auth events, else we have to take it on trust.
if isOriginLocalUser {
_, err = checkAuthEvents(ctx, r.DB, req.Event, req.Event.AuthEventIDs()) _, err = checkAuthEvents(ctx, r.DB, req.Event, req.Event.AuthEventIDs())
if err != nil { if err != nil {
log.WithError(err).WithField("event_id", event.EventID()).WithField("auth_event_ids", event.AuthEventIDs()).Error( log.WithError(err).WithField("event_id", event.EventID()).WithField("auth_event_ids", event.AuthEventIDs()).Error(
@ -117,50 +117,22 @@ func (r *RoomserverInternalAPI) PerformInvite(
} }
return err return err
} }
}
if len(req.InviteRoomState) > 0 { // If the invite originated from us and the target isn't local then we
// If we were supplied with some invite room state already (which is // should try and send the invite over federation first. It might be
// most likely to be if the event came in over federation) then use // that the remote user doesn't exist, in which case we can give up
// that. // processing here.
if err = event.SetUnsignedField("invite_room_state", req.InviteRoomState); err != nil { if req.SendAsServer != api.DoNotSendToOtherServers && !isTargetLocal {
return err fsReq := &federationSenderAPI.PerformInviteRequest{
RoomVersion: req.RoomVersion,
Event: req.Event,
InviteRoomState: inviteState,
} }
} else { fsRes := &federationSenderAPI.PerformInviteResponse{}
// There's no invite room state, so let's have a go at building it if err = r.fsAPI.PerformInvite(ctx, fsReq, fsRes); err != nil {
// up from local data (which is most likely to be if the event came return fmt.Errorf("r.fsAPI.PerformInvite: %w", err)
// from the CS API). If we know about the room then we can insert
// the invite room state, if we don't then we just fail quietly.
if irs, ierr := buildInviteStrippedState(ctx, r.DB, req); ierr == nil {
if err = event.SetUnsignedField("invite_room_state", irs); err != nil {
return err
} }
} else { event = fsRes.SignedEvent
log.WithError(ierr).Warn("failed to build invite stripped state")
// still set the field else synapse deployments don't process the invite
if err = event.SetUnsignedField("invite_room_state", struct{}{}); err != nil {
return err
}
}
}
// If we're the sender of the event then we should send the invite
// event into the room so that the room state is updated and other
// room participants will see the invite.
if isOriginLocalUser {
inputReq := &api.InputRoomEventsRequest{
InputRoomEvents: []api.InputRoomEvent{
{
Kind: api.KindNew,
Event: event,
AuthEventIDs: event.AuthEventIDs(),
SendAsServer: api.DoNotSendToOtherServers,
},
},
}
inputRes := &api.InputRoomEventsResponse{}
if err = r.InputRoomEvents(ctx, inputReq, inputRes); err != nil {
return fmt.Errorf("r.InputRoomEvents: %w", err)
} }
} }
@ -193,7 +165,7 @@ func buildInviteStrippedState(
for _, t := range []string{ for _, t := range []string{
gomatrixserverlib.MRoomName, gomatrixserverlib.MRoomCanonicalAlias, gomatrixserverlib.MRoomName, gomatrixserverlib.MRoomCanonicalAlias,
gomatrixserverlib.MRoomAliases, gomatrixserverlib.MRoomJoinRules, gomatrixserverlib.MRoomAliases, gomatrixserverlib.MRoomJoinRules,
"m.room.avatar", "m.room.avatar", "m.room.encryption",
} { } {
stateWanted = append(stateWanted, gomatrixserverlib.StateKeyTuple{ stateWanted = append(stateWanted, gomatrixserverlib.StateKeyTuple{
EventType: t, EventType: t,