From b8d425165d13ce4ec993f8fb4117fbf1b9e79640 Mon Sep 17 00:00:00 2001 From: Till Faelligen <2353100+S7evinK@users.noreply.github.com> Date: Thu, 2 Mar 2023 14:59:11 +0100 Subject: [PATCH] Add PowerLevelResolver to resolve the powerlevels before a redaction event --- roomserver/internal/input/input_events.go | 50 +++++++------------ .../internal/perform/perform_backfill.go | 5 +- roomserver/state/state.go | 41 +++++++++++++++ roomserver/storage/interface.go | 5 +- roomserver/storage/shared/storage.go | 11 +++- 5 files changed, 76 insertions(+), 36 deletions(-) diff --git a/roomserver/internal/input/input_events.go b/roomserver/internal/input/input_events.go index fcdbd511b..fa24fde33 100644 --- a/roomserver/internal/input/input_events.go +++ b/roomserver/internal/input/input_events.go @@ -26,14 +26,14 @@ import ( "github.com/tidwall/gjson" - "github.com/matrix-org/dendrite/roomserver/internal/helpers" - "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" "github.com/opentracing/opentracing-go" "github.com/prometheus/client_golang/prometheus" "github.com/sirupsen/logrus" + "github.com/matrix-org/dendrite/roomserver/internal/helpers" + userAPI "github.com/matrix-org/dendrite/userapi/api" fedapi "github.com/matrix-org/dendrite/federationapi/api" @@ -275,25 +275,12 @@ func (r *Inputer) processRoomEvent( // Check if the event is allowed by its auth events. If it isn't then // we consider the event to be "rejected" — it will still be persisted. - redactAllowed := true if err = gomatrixserverlib.Allowed(event, &authEvents); err != nil { isRejected = true - redactAllowed = false rejectionErr = err logger.WithError(rejectionErr).Warnf("Event %s not allowed by auth events", event.EventID()) } - if event.Type() == gomatrixserverlib.MRoomRedaction { - ap, _ := authEvents.PowerLevels() - if ap != nil { - var powerLevels *gomatrixserverlib.PowerLevelContent - powerLevels, _ = ap.PowerLevels() - if powerLevels != nil { - redactAllowed = powerLevels.UserLevel(event.Sender()) >= powerLevels.Redact - } - } - } - // Accumulate the auth event NIDs. authEventIDs := event.AuthEventIDs() authEventNIDs := make([]types.EventNID, 0, len(authEventIDs)) @@ -369,22 +356,6 @@ func (r *Inputer) processRoomEvent( return fmt.Errorf("updater.StoreEvent: %w", err) } - // if storing this event results in it being redacted then do so. - var ( - redactedEventID string - redactionEvent *gomatrixserverlib.Event - redactedEvent *gomatrixserverlib.Event - ) - if !isRejected && !isCreateEvent { - redactionEvent, redactedEvent, err = r.DB.MaybeRedactEvent(ctx, roomInfo, eventNID, event, redactAllowed) - if err != nil { - return err - } - if redactedEvent != nil { - redactedEventID = redactedEvent.EventID() - } - } - // For outliers we can stop after we've stored the event itself as it // doesn't have any associated state to store and we don't need to // notify anyone about it. @@ -413,6 +384,23 @@ func (r *Inputer) processRoomEvent( } } + // if storing this event results in it being redacted then do so. + var ( + redactedEventID string + redactionEvent *gomatrixserverlib.Event + redactedEvent *gomatrixserverlib.Event + ) + if !isRejected && !isCreateEvent { + resolver := state.NewStateResolution(r.DB, roomInfo) + redactionEvent, redactedEvent, err = r.DB.MaybeRedactEvent(ctx, roomInfo, eventNID, event, &resolver) + if err != nil { + return err + } + if redactedEvent != nil { + redactedEventID = redactedEvent.EventID() + } + } + // We stop here if the event is rejected: We've stored it but won't update // forward extremities or notify downstream components about it. switch { diff --git a/roomserver/internal/perform/perform_backfill.go b/roomserver/internal/perform/perform_backfill.go index 411f4202b..07ad28b82 100644 --- a/roomserver/internal/perform/perform_backfill.go +++ b/roomserver/internal/perform/perform_backfill.go @@ -26,6 +26,7 @@ import ( "github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/auth" "github.com/matrix-org/dendrite/roomserver/internal/helpers" + "github.com/matrix-org/dendrite/roomserver/state" "github.com/matrix-org/dendrite/roomserver/storage" "github.com/matrix-org/dendrite/roomserver/types" ) @@ -629,7 +630,9 @@ func persistEvents(ctx context.Context, db storage.Database, events []*gomatrixs continue } - _, redactedEvent, err := db.MaybeRedactEvent(ctx, roomInfo, eventNID, ev.Unwrap(), true) + resolver := state.NewStateResolution(db, roomInfo) + + _, redactedEvent, err := db.MaybeRedactEvent(ctx, roomInfo, eventNID, ev.Unwrap(), &resolver) if err != nil { logrus.WithError(err).WithField("event_id", ev.EventID()).Error("Failed to redact event") continue diff --git a/roomserver/state/state.go b/roomserver/state/state.go index 9af2f8577..0c279e31c 100644 --- a/roomserver/state/state.go +++ b/roomserver/state/state.go @@ -59,6 +59,47 @@ func NewStateResolution(db StateResolutionStorage, roomInfo *types.RoomInfo) Sta } } +type PowerLevelResolver interface { + Resolve(ctx context.Context, roomInfo *types.RoomInfo, eventID string) (*gomatrixserverlib.PowerLevelContent, error) +} + +func (p *StateResolution) Resolve(ctx context.Context, roomInfo *types.RoomInfo, eventID string) (*gomatrixserverlib.PowerLevelContent, error) { + stateEntries, err := p.LoadStateAtEvent(ctx, eventID) + if err != nil { + return nil, err + } + + wantTuple := types.StateKeyTuple{ + EventTypeNID: types.MRoomPowerLevelsNID, + EventStateKeyNID: types.EmptyStateKeyNID, + } + + var plNID types.EventNID + for _, entry := range stateEntries { + if entry.StateKeyTuple == wantTuple { + plNID = entry.EventNID + break + } + } + if plNID == 0 { + return nil, fmt.Errorf("unable to find power level event") + } + + events, err := p.db.Events(ctx, roomInfo, []types.EventNID{plNID}) + if err != nil { + return nil, err + } + if len(events) == 0 { + return nil, fmt.Errorf("unable to find power level event") + } + powerlevels, err := events[0].PowerLevels() + if err != nil { + return nil, err + } + + return powerlevels, nil +} + // LoadStateAtSnapshot loads the full state of a room at a particular snapshot. // This is typically the state before an event or the current state of a room. // Returns a sorted list of state entries or an error if there was a problem talking to the database. diff --git a/roomserver/storage/interface.go b/roomserver/storage/interface.go index a41a8a9b4..5b90f8b33 100644 --- a/roomserver/storage/interface.go +++ b/roomserver/storage/interface.go @@ -19,6 +19,7 @@ import ( "github.com/matrix-org/gomatrixserverlib" + "github.com/matrix-org/dendrite/roomserver/state" "github.com/matrix-org/dendrite/roomserver/storage/shared" "github.com/matrix-org/dendrite/roomserver/storage/tables" "github.com/matrix-org/dendrite/roomserver/types" @@ -184,7 +185,7 @@ type Database interface { GetOrCreateEventTypeNID(ctx context.Context, eventType string) (eventTypeNID types.EventTypeNID, err error) GetOrCreateEventStateKeyNID(ctx context.Context, eventStateKey *string) (types.EventStateKeyNID, error) MaybeRedactEvent( - ctx context.Context, roomInfo *types.RoomInfo, eventNID types.EventNID, event *gomatrixserverlib.Event, redactAllowed bool, + ctx context.Context, roomInfo *types.RoomInfo, eventNID types.EventNID, event *gomatrixserverlib.Event, plResolver state.PowerLevelResolver, ) (*gomatrixserverlib.Event, *gomatrixserverlib.Event, error) } @@ -226,7 +227,7 @@ type EventDatabase interface { // MaybeRedactEvent returns the redaction event and the redacted event if this call resulted in a redaction, else an error // (nil if there was nothing to do) MaybeRedactEvent( - ctx context.Context, roomInfo *types.RoomInfo, eventNID types.EventNID, event *gomatrixserverlib.Event, redactAllowed bool, + ctx context.Context, roomInfo *types.RoomInfo, eventNID types.EventNID, event *gomatrixserverlib.Event, plResolver state.PowerLevelResolver, ) (*gomatrixserverlib.Event, *gomatrixserverlib.Event, error) StoreEvent(ctx context.Context, event *gomatrixserverlib.Event, roomInfo *types.RoomInfo, eventTypeNID types.EventTypeNID, eventStateKeyNID types.EventStateKeyNID, authEventNIDs []types.EventNID, isRejected bool) (types.EventNID, types.StateAtEvent, error) } diff --git a/roomserver/storage/shared/storage.go b/roomserver/storage/shared/storage.go index e75770695..e881b8704 100644 --- a/roomserver/storage/shared/storage.go +++ b/roomserver/storage/shared/storage.go @@ -13,6 +13,7 @@ import ( "github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/sqlutil" + "github.com/matrix-org/dendrite/roomserver/state" "github.com/matrix-org/dendrite/roomserver/storage/tables" "github.com/matrix-org/dendrite/roomserver/types" ) @@ -926,7 +927,7 @@ func extractRoomVersionFromCreateEvent(event *gomatrixserverlib.Event) ( // // Returns the redaction event and the redacted event if this call resulted in a redaction. func (d *EventDatabase) MaybeRedactEvent( - ctx context.Context, roomInfo *types.RoomInfo, eventNID types.EventNID, event *gomatrixserverlib.Event, redactAllowed bool, + ctx context.Context, roomInfo *types.RoomInfo, eventNID types.EventNID, event *gomatrixserverlib.Event, plResolver state.PowerLevelResolver, ) (*gomatrixserverlib.Event, *gomatrixserverlib.Event, error) { var ( redactionEvent, redactedEvent *types.Event @@ -968,8 +969,14 @@ func (d *EventDatabase) MaybeRedactEvent( _, sender1, _ := gomatrixserverlib.SplitID('@', redactedEvent.Sender()) _, sender2, _ := gomatrixserverlib.SplitID('@', redactionEvent.Sender()) + var powerlevels *gomatrixserverlib.PowerLevelContent + powerlevels, err = plResolver.Resolve(ctx, roomInfo, redactionEvent.EventID()) + if err != nil { + return err + } + switch { - case redactAllowed: + case powerlevels.UserLevel(redactionEvent.Sender()) >= powerlevels.Redact: // 1. The power level of the redaction event’s sender is greater than or equal to the redact level. case sender1 == sender2: // 2. The domain of the redaction event’s sender matches that of the original event’s sender.