diff --git a/roomserver/api/wrapper.go b/roomserver/api/wrapper.go index cc048ddd4..24949fc63 100644 --- a/roomserver/api/wrapper.go +++ b/roomserver/api/wrapper.go @@ -122,15 +122,7 @@ func SendEventWithRewrite( // We will handle an event as if it's an outlier if one of the // following conditions is true: storeAsOutlier := false - if authOrStateEvent.Type() == event.Type() && *authOrStateEvent.StateKey() == *event.StateKey() { - // The event is a state event but the input event is going to - // replace it, therefore it can't be added to the state or we'll - // get duplicate state keys in the state block. We'll send it - // as an outlier because we don't know if something will be - // referring to it as an auth event, but need it to be stored - // just in case. - storeAsOutlier = true - } else if _, ok := isCurrentState[authOrStateEvent.EventID()]; !ok { + if _, ok := isCurrentState[authOrStateEvent.EventID()]; !ok { // The event is an auth event and isn't a part of the state set. // We'll send it as an outlier because we need it to be stored // in case something is referring to it as an auth event. diff --git a/roomserver/internal/helpers/auth.go b/roomserver/internal/helpers/auth.go index 5cf93d48e..ef51ca173 100644 --- a/roomserver/internal/helpers/auth.go +++ b/roomserver/internal/helpers/auth.go @@ -32,28 +32,34 @@ func CheckForSoftFail( ctx context.Context, db storage.Database, event gomatrixserverlib.HeaderedEvent, + stateEventIDs []string, ) (bool, error) { - // Work out if the room exists. - roomInfo, err := db.RoomInfo(ctx, event.RoomID()) - if err != nil { - return false, fmt.Errorf("db.RoomNID: %w", err) - } - if roomInfo == nil || roomInfo.IsStub { - return false, nil - } + rewritesState := len(stateEventIDs) > 1 - // If the room exist, gets the current state snapshot. - _, stateSnapshotNID, _, err := db.LatestEventIDs(ctx, roomInfo.RoomNID) - if err != nil { - return true, fmt.Errorf("r.DB.LatestEventIDs: %w", err) - } + var authStateEntries []types.StateEntry + var err error + if rewritesState { + authStateEntries, err = db.StateEntriesForEventIDs(ctx, stateEventIDs) + if err != nil { + return true, fmt.Errorf("StateEntriesForEventIDs failed: %w", err) + } + } else { + // Work out if the room exists. + roomInfo, err := db.RoomInfo(ctx, event.RoomID()) + if err != nil { + return false, fmt.Errorf("db.RoomNID: %w", err) + } + if roomInfo == nil || roomInfo.IsStub { + return false, nil + } - // Then get the state entries for the current state snapshot. - // We'll use this to check if the event is allowed right now. - roomState := state.NewStateResolution(db, *roomInfo) - authStateEntries, err := roomState.LoadStateAtSnapshot(ctx, stateSnapshotNID) - if err != nil { - return true, fmt.Errorf("roomState.LoadStateAtSnapshot: %w", err) + // Then get the state entries for the current state snapshot. + // We'll use this to check if the event is allowed right now. + roomState := state.NewStateResolution(db, *roomInfo) + authStateEntries, err = roomState.LoadStateAtSnapshot(ctx, roomInfo.StateSnapshotNID) + if err != nil { + return true, fmt.Errorf("roomState.LoadStateAtSnapshot: %w", err) + } } // As a special case, it's possible that the room will have no diff --git a/roomserver/internal/input/input_events.go b/roomserver/internal/input/input_events.go index 66248b206..f953a9259 100644 --- a/roomserver/internal/input/input_events.go +++ b/roomserver/internal/input/input_events.go @@ -43,7 +43,6 @@ func (r *Inputer) processRoomEvent( // Parse and validate the event JSON headered := input.Event event := headered.Unwrap() - softfail := false // Check that the event passes authentication checks and work out // the numeric IDs for the auth events. @@ -54,15 +53,18 @@ func (r *Inputer) processRoomEvent( isRejected = true } - // Check that the event passes authentication checks based on the - // current room state. - softfail, err = helpers.CheckForSoftFail(ctx, r.DB, headered) - if err != nil { - logrus.WithFields(logrus.Fields{ - "event_id": event.EventID(), - "type": event.Type(), - "room": event.RoomID(), - }).WithError(err).Info("Error authing soft-failed event") + var softfail bool + if input.Kind == api.KindBackfill || input.Kind == api.KindNew { + // Check that the event passes authentication checks based on the + // current room state. + softfail, err = helpers.CheckForSoftFail(ctx, r.DB, headered, input.StateEventIDs) + if err != nil { + logrus.WithFields(logrus.Fields{ + "event_id": event.EventID(), + "type": event.Type(), + "room": event.RoomID(), + }).WithError(err).Info("Error authing soft-failed event") + } } // If we don't have a transaction ID then get one. @@ -100,6 +102,7 @@ func (r *Inputer) processRoomEvent( "event_id": event.EventID(), "type": event.Type(), "room": event.RoomID(), + "sender": event.Sender(), }).Debug("Stored outlier") return event.EventID(), nil } @@ -128,6 +131,7 @@ func (r *Inputer) processRoomEvent( "type": event.Type(), "room": event.RoomID(), "soft_fail": softfail, + "sender": event.Sender(), }).Debug("Stored rejected event") return event.EventID(), rejectionErr } diff --git a/sytest-blacklist b/sytest-blacklist index 246e68303..2f80fc789 100644 --- a/sytest-blacklist +++ b/sytest-blacklist @@ -52,7 +52,4 @@ Inbound federation accepts a second soft-failed event Outbound federation requests missing prev_events and then asks for /state_ids and resolves the state # We don't implement lazy membership loading yet. -The only membership state included in a gapped incremental sync is for senders in the timeline - -# flakey since implementing rejected events -Inbound federation correctly soft fails events \ No newline at end of file +The only membership state included in a gapped incremental sync is for senders in the timeline \ No newline at end of file diff --git a/sytest-whitelist b/sytest-whitelist index 91516428d..553df1f1a 100644 --- a/sytest-whitelist +++ b/sytest-whitelist @@ -472,4 +472,6 @@ We can't peek into rooms with joined history_visibility Local users can peek by room alias Peeked rooms only turn up in the sync for the device who peeked them Room state at a rejected message event is the same as its predecessor -Room state at a rejected state event is the same as its predecessor \ No newline at end of file +Room state at a rejected state event is the same as its predecessor +Inbound federation correctly soft fails events +Inbound federation accepts a second soft-failed event \ No newline at end of file