Move responsibility of caring about invite room state

This commit is contained in:
Neil Alexander 2020-04-23 16:35:47 +01:00
parent 1de1640cc4
commit 48e3088e90
5 changed files with 80 additions and 93 deletions

View file

@ -187,54 +187,14 @@ func (s *OutputRoomEventConsumer) processInvite(oie api.OutputNewInviteEvent) er
return nil return nil
} }
// When sending a v2 invite, the inviting server should try and include // Try to unmarshal the invite room state to pass to the destination queue.
// a "stripped down" version of the room state. This is pretty much just inviteRoomState := []gomatrixserverlib.InviteV2StrippedState{}
// enough information for the remote side to show something useful to the if err := json.Unmarshal(oie.InviteRoomState, &inviteRoomState); err != nil {
// user, like the room name, aliases etc. return fmt.Errorf("json.Unmarshal: %w", err)
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")
}
} }
// Build the invite request with the info we've got. // 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 { if err != nil {
return fmt.Errorf("gomatrixserverlib.NewInviteV2Request: %w", err) return fmt.Errorf("gomatrixserverlib.NewInviteV2Request: %w", err)
} }

View file

@ -17,6 +17,7 @@ package api
import ( import (
"context" "context"
"encoding/json"
"errors" "errors"
"net/http" "net/http"
@ -88,7 +89,7 @@ type TransactionID struct {
type InputInviteEvent struct { type InputInviteEvent struct {
RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"` RoomVersion gomatrixserverlib.RoomVersion `json:"room_version"`
Event gomatrixserverlib.HeaderedEvent `json:"event"` Event gomatrixserverlib.HeaderedEvent `json:"event"`
InviteRoomState []gomatrixserverlib.InviteV2StrippedState `json:"invite_room_state"` InviteRoomState json.RawMessage `json:"invite_room_state"`
} }
// InputRoomEventsRequest is a request to InputRoomEvents // InputRoomEventsRequest is a request to InputRoomEvents

View file

@ -15,6 +15,8 @@
package api package api
import ( import (
"encoding/json"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
) )
@ -118,6 +120,8 @@ type OutputNewRoomEvent struct {
type OutputNewInviteEvent struct { type OutputNewInviteEvent struct {
// The "m.room.member" invite event. // The "m.room.member" invite event.
Event gomatrixserverlib.HeaderedEvent `json:"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 // An OutputRetireInviteEvent is written whenever an existing invite is no longer

View file

@ -18,6 +18,7 @@ package input
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"github.com/matrix-org/dendrite/common" "github.com/matrix-org/dendrite/common"
@ -248,17 +249,45 @@ func processInviteEvent(
} }
event := input.Event.Unwrap() event := input.Event.Unwrap()
inviteStrippedState := []gomatrixserverlib.InviteV2StrippedState{} inviteStrippedState := input.InviteRoomState
if len(input.InviteRoomState) > 0 { // TODO: replace this with a proper origin check
// If we were supplied with some invite room state then let's use that. if inviteStrippedState == nil {
// This will ordinarily happen over federation.
inviteStrippedState = input.InviteRoomState
} else {
// Otherwise, we should see if we know anything about the room state // 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 // locally. If we have local knowledge of the room, use the locally known
// state to build up the invite room state. // state to build up the invite room state.
if roomNID, err := db.RoomNID(ctx, roomID); err == nil && roomNID != 0 { inviteStrippedState, err = buildInviteStrippedState(ctx, db, input)
if err != nil {
return err
}
}
if err = event.SetUnsignedField("invite_room_state", inviteStrippedState); err != nil {
return err
}
outputUpdates, err := updateToInviteMembership(updater, event, inviteStrippedState, nil, input.Event.RoomVersion)
if err != nil {
return err
}
if err = ow.WriteOutputEvents(roomID, outputUpdates); err != nil {
return err
}
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{} stateWanted := []gomatrixserverlib.StateKeyTuple{}
for _, t := range []string{ for _, t := range []string{
gomatrixserverlib.MRoomName, gomatrixserverlib.MRoomCanonicalAlias, gomatrixserverlib.MRoomName, gomatrixserverlib.MRoomCanonicalAlias,
@ -271,14 +300,14 @@ func processInviteEvent(
} }
_, currentStateSnapshotNID, _, err := db.LatestEventIDs(ctx, roomNID) _, currentStateSnapshotNID, _, err := db.LatestEventIDs(ctx, roomNID)
if err != nil { if err != nil {
return err return nil, err
} }
roomState := state.NewStateResolution(db) roomState := state.NewStateResolution(db)
stateEntries, err := roomState.LoadStateAtSnapshotForStringTuples( stateEntries, err := roomState.LoadStateAtSnapshotForStringTuples(
ctx, currentStateSnapshotNID, stateWanted, ctx, currentStateSnapshotNID, stateWanted,
) )
if err != nil { if err != nil {
return err return nil, err
} }
stateNIDs := []types.EventNID{} stateNIDs := []types.EventNID{}
for _, stateNID := range stateEntries { for _, stateNID := range stateEntries {
@ -286,27 +315,15 @@ func processInviteEvent(
} }
stateEvents, err := db.Events(ctx, stateNIDs) stateEvents, err := db.Events(ctx, stateNIDs)
if err != nil { if err != nil {
return err return nil, err
} }
inviteState := []gomatrixserverlib.InviteV2StrippedState{}
for _, event := range stateEvents { for _, event := range stateEvents {
inviteStrippedState = append(inviteStrippedState, gomatrixserverlib.NewInviteV2StrippedState(&event.Event)) inviteState = append(inviteState, gomatrixserverlib.NewInviteV2StrippedState(&event.Event))
} }
} inviteStrippedState, err := json.Marshal(inviteState)
}
if err = event.SetUnsignedField("invite_room_state", inviteStrippedState); err != nil {
return err
}
outputUpdates, err := updateToInviteMembership(updater, &event, nil, input.Event.RoomVersion)
if err != nil { if err != nil {
return err return nil, err
} }
return inviteStrippedState, nil
if err = ow.WriteOutputEvents(roomID, outputUpdates); err != nil {
return err
}
succeeded = true
return nil
} }

View file

@ -16,6 +16,7 @@ package input
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/api"
@ -111,8 +112,8 @@ func updateMembership(
} }
switch newMembership { switch newMembership {
case gomatrixserverlib.Invite: //case gomatrixserverlib.Invite:
return updateToInviteMembership(mu, add, updates, updater.RoomVersion()) // return updateToInviteMembership(mu, add, updates, updater.RoomVersion())
case gomatrixserverlib.Join: case gomatrixserverlib.Join:
return updateToJoinMembership(mu, add, updates) return updateToJoinMembership(mu, add, updates)
case gomatrixserverlib.Leave, gomatrixserverlib.Ban: case gomatrixserverlib.Leave, gomatrixserverlib.Ban:
@ -125,14 +126,17 @@ func updateMembership(
} }
func updateToInviteMembership( 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, roomVersion gomatrixserverlib.RoomVersion,
) ([]api.OutputEvent, error) { ) ([]api.OutputEvent, error) {
// We may have already sent the invite to the user, either because we are // 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 // 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 // remote server via the federation invite API. In those cases we don't need
// to send the event. // to send the event.
needsSending, err := mu.SetToInvite(*add) needsSending, err := mu.SetToInvite(add)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -143,7 +147,8 @@ func updateToInviteMembership(
// consider a single stream of events when determining whether a user // consider a single stream of events when determining whether a user
// is invited, rather than having to combine multiple streams themselves. // is invited, rather than having to combine multiple streams themselves.
onie := api.OutputNewInviteEvent{ onie := api.OutputNewInviteEvent{
Event: (*add).Headered(roomVersion), Event: add.Headered(roomVersion),
InviteRoomState: addState,
} }
updates = append(updates, api.OutputEvent{ updates = append(updates, api.OutputEvent{
Type: api.OutputTypeNewInviteEvent, Type: api.OutputTypeNewInviteEvent,