diff --git a/roomserver/input/events.go b/roomserver/input/events.go index 2bb0d0a05..e9b497167 100644 --- a/roomserver/input/events.go +++ b/roomserver/input/events.go @@ -18,6 +18,7 @@ package input import ( "context" + "errors" "fmt" "github.com/matrix-org/dendrite/common" @@ -78,6 +79,10 @@ type RoomEventDatabase interface { GetRoomVersionForRoom( ctx context.Context, roomID string, ) (gomatrixserverlib.RoomVersion, error) + // Get the room NID for a room ID. + RoomNID(ctx context.Context, roomID string) (types.RoomNID, error) + // Get the latest event IDs & state for a given room NID. + LatestEventIDs(ctx context.Context, roomNID types.RoomNID) ([]gomatrixserverlib.EventReference, types.StateSnapshotNID, int64, error) } // OutputRoomEventWriter has the APIs needed to write an event to the output logs. @@ -247,8 +252,22 @@ func processInviteEvent( event := input.Event.Unwrap() - if err = event.SetUnsignedField("invite_room_state", input.InviteRoomState); err != nil { - return err + if len(input.InviteRoomState) > 0 { + // If we were supplied with some invite room state already (which is + // most likely to be if the event came in over federation) then use + // that. + if err = event.SetUnsignedField("invite_room_state", input.InviteRoomState); err != nil { + return err + } + } else { + // There's no invite room state, so let's have a go at building it + // up from local data. 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, db, input); ierr == nil { + if err = event.SetUnsignedField("invite_room_state", irs); err != nil { + return err + } + } } outputUpdates, err := updateToInviteMembership(updater, &event, nil, input.Event.RoomVersion) @@ -263,3 +282,48 @@ func processInviteEvent( succeeded = true return nil } + +func buildInviteStrippedState( + ctx context.Context, + db RoomEventDatabase, + input api.InputInviteEvent, +) ([]gomatrixserverlib.InviteV2StrippedState, error) { + roomNID, err := db.RoomNID(ctx, input.Event.RoomID()) + if err != nil || roomNID == 0 { + return nil, errors.New("room unknown") + } + stateWanted := []gomatrixserverlib.StateKeyTuple{} + for _, t := range []string{ + gomatrixserverlib.MRoomName, gomatrixserverlib.MRoomCanonicalAlias, + gomatrixserverlib.MRoomAliases, gomatrixserverlib.MRoomJoinRules, + } { + stateWanted = append(stateWanted, gomatrixserverlib.StateKeyTuple{ + EventType: t, + StateKey: "", + }) + } + _, currentStateSnapshotNID, _, err := db.LatestEventIDs(ctx, roomNID) + if err != nil { + return nil, err + } + roomState := state.NewStateResolution(db) + stateEntries, err := roomState.LoadStateAtSnapshotForStringTuples( + ctx, currentStateSnapshotNID, stateWanted, + ) + if err != nil { + return nil, err + } + stateNIDs := []types.EventNID{} + for _, stateNID := range stateEntries { + stateNIDs = append(stateNIDs, stateNID.EventNID) + } + stateEvents, err := db.Events(ctx, stateNIDs) + if err != nil { + return nil, err + } + inviteState := []gomatrixserverlib.InviteV2StrippedState{} + for _, event := range stateEvents { + inviteState = append(inviteState, gomatrixserverlib.NewInviteV2StrippedState(&event.Event)) + } + return inviteState, nil +}