diff --git a/federationsender/consumers/roomserver.go b/federationsender/consumers/roomserver.go index a36fb3792..68fa065fb 100644 --- a/federationsender/consumers/roomserver.go +++ b/federationsender/consumers/roomserver.go @@ -187,54 +187,14 @@ func (s *OutputRoomEventConsumer) processInvite(oie api.OutputNewInviteEvent) er return nil } - // When sending a v2 invite, the inviting server should try and include - // a "stripped down" version of the room state. This is pretty much just - // enough information for the remote side to show something useful to the - // user, like the room name, aliases etc. - strippedState := []gomatrixserverlib.InviteV2StrippedState{} - stateWanted := []string{ - gomatrixserverlib.MRoomName, gomatrixserverlib.MRoomCanonicalAlias, - gomatrixserverlib.MRoomAliases, gomatrixserverlib.MRoomJoinRules, - } - - // For each of the state keys that we want to try and send, ask the - // roomserver if we have a state event for that room that matches the - // state key. - for _, wanted := range stateWanted { - queryReq := api.QueryLatestEventsAndStateRequest{ - RoomID: oie.Event.RoomID(), - StateToFetch: []gomatrixserverlib.StateKeyTuple{ - gomatrixserverlib.StateKeyTuple{ - EventType: wanted, - StateKey: "", - }, - }, - } - // If this fails then we just move onto the next event - we don't - // actually know at this point whether the room even has that type - // of state. - queryRes := api.QueryLatestEventsAndStateResponse{} - if err := s.query.QueryLatestEventsAndState(context.TODO(), &queryReq, &queryRes); err != nil { - log.WithFields(log.Fields{ - "room_id": queryReq.RoomID, - "event_type": wanted, - }).WithError(err).Info("couldn't find state to strip") - continue - } - // Append the stripped down copy of the state to our list. - for _, headeredEvent := range queryRes.StateEvents { - event := headeredEvent.Unwrap() - strippedState = append(strippedState, gomatrixserverlib.NewInviteV2StrippedState(&event)) - - log.WithFields(log.Fields{ - "room_id": queryReq.RoomID, - "event_type": event.Type(), - }).Info("adding stripped state") - } + // Try to unmarshal the invite room state to pass to the destination queue. + inviteRoomState := []gomatrixserverlib.InviteV2StrippedState{} + if err := json.Unmarshal(oie.InviteRoomState, &inviteRoomState); err != nil { + return fmt.Errorf("json.Unmarshal: %w", err) } // Build the invite request with the info we've got. - inviteReq, err := gomatrixserverlib.NewInviteV2Request(&oie.Event, strippedState) + inviteReq, err := gomatrixserverlib.NewInviteV2Request(&oie.Event, inviteRoomState) if err != nil { return fmt.Errorf("gomatrixserverlib.NewInviteV2Request: %w", err) } diff --git a/roomserver/api/input.go b/roomserver/api/input.go index 87e3983e3..37c5c44d7 100644 --- a/roomserver/api/input.go +++ b/roomserver/api/input.go @@ -17,6 +17,7 @@ package api import ( "context" + "encoding/json" "errors" "net/http" @@ -86,9 +87,9 @@ type TransactionID struct { // the usual context a matrix room event would have. We usually do not have // access to the events needed to check the event auth rules for the invite. type InputInviteEvent struct { - RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"` - Event gomatrixserverlib.HeaderedEvent `json:"event"` - InviteRoomState []gomatrixserverlib.InviteV2StrippedState `json:"invite_room_state"` + RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"` + Event gomatrixserverlib.HeaderedEvent `json:"event"` + InviteRoomState json.RawMessage `json:"invite_room_state"` } // InputRoomEventsRequest is a request to InputRoomEvents diff --git a/roomserver/api/output.go b/roomserver/api/output.go index 4e7adff79..a04a7a95e 100644 --- a/roomserver/api/output.go +++ b/roomserver/api/output.go @@ -15,6 +15,8 @@ package api import ( + "encoding/json" + "github.com/matrix-org/gomatrixserverlib" ) @@ -118,6 +120,8 @@ type OutputNewRoomEvent struct { type OutputNewInviteEvent struct { // The "m.room.member" invite event. Event gomatrixserverlib.HeaderedEvent `json:"event"` + // The invite stripped event state, if available. + InviteRoomState json.RawMessage } // An OutputRetireInviteEvent is written whenever an existing invite is no longer diff --git a/roomserver/input/events.go b/roomserver/input/events.go index 281d741fe..f870471c0 100644 --- a/roomserver/input/events.go +++ b/roomserver/input/events.go @@ -18,6 +18,7 @@ package input import ( "context" + "encoding/json" "fmt" "github.com/matrix-org/dendrite/common" @@ -248,49 +249,16 @@ func processInviteEvent( } event := input.Event.Unwrap() - inviteStrippedState := []gomatrixserverlib.InviteV2StrippedState{} + inviteStrippedState := input.InviteRoomState - if len(input.InviteRoomState) > 0 { - // If we were supplied with some invite room state then let's use that. - // This will ordinarily happen over federation. - inviteStrippedState = input.InviteRoomState - } else { + // TODO: replace this with a proper origin check + if inviteStrippedState == nil { // Otherwise, we should see if we know anything about the room state // locally. If we have local knowledge of the room, use the locally known // state to build up the invite room state. - if roomNID, err := db.RoomNID(ctx, roomID); err == nil && roomNID != 0 { - 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 err - } - roomState := state.NewStateResolution(db) - stateEntries, err := roomState.LoadStateAtSnapshotForStringTuples( - ctx, currentStateSnapshotNID, stateWanted, - ) - if err != nil { - return err - } - stateNIDs := []types.EventNID{} - for _, stateNID := range stateEntries { - stateNIDs = append(stateNIDs, stateNID.EventNID) - } - stateEvents, err := db.Events(ctx, stateNIDs) - if err != nil { - return err - } - for _, event := range stateEvents { - inviteStrippedState = append(inviteStrippedState, gomatrixserverlib.NewInviteV2StrippedState(&event.Event)) - } + inviteStrippedState, err = buildInviteStrippedState(ctx, db, input) + if err != nil { + return err } } @@ -298,7 +266,7 @@ func processInviteEvent( return err } - outputUpdates, err := updateToInviteMembership(updater, &event, nil, input.Event.RoomVersion) + outputUpdates, err := updateToInviteMembership(updater, event, inviteStrippedState, nil, input.Event.RoomVersion) if err != nil { return err } @@ -310,3 +278,52 @@ func processInviteEvent( succeeded = true return nil } + +func buildInviteStrippedState( + ctx context.Context, + db RoomEventDatabase, + input api.InputInviteEvent, +) (json.RawMessage, error) { + roomNID, err := db.RoomNID(ctx, input.Event.RoomID()) + if err != nil || roomNID == 0 { + return nil, nil + } + 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)) + } + inviteStrippedState, err := json.Marshal(inviteState) + if err != nil { + return nil, err + } + return inviteStrippedState, nil +} diff --git a/roomserver/input/membership.go b/roomserver/input/membership.go index ab5f6ba03..f1e0617c9 100644 --- a/roomserver/input/membership.go +++ b/roomserver/input/membership.go @@ -16,6 +16,7 @@ package input import ( "context" + "encoding/json" "fmt" "github.com/matrix-org/dendrite/roomserver/api" @@ -111,8 +112,8 @@ func updateMembership( } switch newMembership { - case gomatrixserverlib.Invite: - return updateToInviteMembership(mu, add, updates, updater.RoomVersion()) + //case gomatrixserverlib.Invite: + // return updateToInviteMembership(mu, add, updates, updater.RoomVersion()) case gomatrixserverlib.Join: return updateToJoinMembership(mu, add, updates) case gomatrixserverlib.Leave, gomatrixserverlib.Ban: @@ -125,14 +126,17 @@ func updateMembership( } func updateToInviteMembership( - mu types.MembershipUpdater, add *gomatrixserverlib.Event, updates []api.OutputEvent, + mu types.MembershipUpdater, + add gomatrixserverlib.Event, + addState json.RawMessage, + updates []api.OutputEvent, roomVersion gomatrixserverlib.RoomVersion, ) ([]api.OutputEvent, error) { // We may have already sent the invite to the user, either because we are // reprocessing this event, or because the we received this invite from a // remote server via the federation invite API. In those cases we don't need // to send the event. - needsSending, err := mu.SetToInvite(*add) + needsSending, err := mu.SetToInvite(add) if err != nil { return nil, err } @@ -143,7 +147,8 @@ func updateToInviteMembership( // consider a single stream of events when determining whether a user // is invited, rather than having to combine multiple streams themselves. onie := api.OutputNewInviteEvent{ - Event: (*add).Headered(roomVersion), + Event: add.Headered(roomVersion), + InviteRoomState: addState, } updates = append(updates, api.OutputEvent{ Type: api.OutputTypeNewInviteEvent,