Add PowerLevelResolver to resolve the powerlevels before a redaction

event
This commit is contained in:
Till Faelligen 2023-03-02 14:59:11 +01:00
parent b8aa0c7c92
commit b8d425165d
No known key found for this signature in database
GPG key ID: 3DF82D8AB9211D4E
5 changed files with 76 additions and 36 deletions

View file

@ -26,14 +26,14 @@ import (
"github.com/tidwall/gjson" "github.com/tidwall/gjson"
"github.com/matrix-org/dendrite/roomserver/internal/helpers"
"github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib"
"github.com/matrix-org/util" "github.com/matrix-org/util"
"github.com/opentracing/opentracing-go" "github.com/opentracing/opentracing-go"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/matrix-org/dendrite/roomserver/internal/helpers"
userAPI "github.com/matrix-org/dendrite/userapi/api" userAPI "github.com/matrix-org/dendrite/userapi/api"
fedapi "github.com/matrix-org/dendrite/federationapi/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 // 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. // we consider the event to be "rejected" — it will still be persisted.
redactAllowed := true
if err = gomatrixserverlib.Allowed(event, &authEvents); err != nil { if err = gomatrixserverlib.Allowed(event, &authEvents); err != nil {
isRejected = true isRejected = true
redactAllowed = false
rejectionErr = err rejectionErr = err
logger.WithError(rejectionErr).Warnf("Event %s not allowed by auth events", event.EventID()) 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. // Accumulate the auth event NIDs.
authEventIDs := event.AuthEventIDs() authEventIDs := event.AuthEventIDs()
authEventNIDs := make([]types.EventNID, 0, len(authEventIDs)) authEventNIDs := make([]types.EventNID, 0, len(authEventIDs))
@ -369,22 +356,6 @@ func (r *Inputer) processRoomEvent(
return fmt.Errorf("updater.StoreEvent: %w", err) 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 // 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 // doesn't have any associated state to store and we don't need to
// notify anyone about it. // 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 // We stop here if the event is rejected: We've stored it but won't update
// forward extremities or notify downstream components about it. // forward extremities or notify downstream components about it.
switch { switch {

View file

@ -26,6 +26,7 @@ import (
"github.com/matrix-org/dendrite/roomserver/api" "github.com/matrix-org/dendrite/roomserver/api"
"github.com/matrix-org/dendrite/roomserver/auth" "github.com/matrix-org/dendrite/roomserver/auth"
"github.com/matrix-org/dendrite/roomserver/internal/helpers" "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/storage"
"github.com/matrix-org/dendrite/roomserver/types" "github.com/matrix-org/dendrite/roomserver/types"
) )
@ -629,7 +630,9 @@ func persistEvents(ctx context.Context, db storage.Database, events []*gomatrixs
continue 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 { if err != nil {
logrus.WithError(err).WithField("event_id", ev.EventID()).Error("Failed to redact event") logrus.WithError(err).WithField("event_id", ev.EventID()).Error("Failed to redact event")
continue continue

View file

@ -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. // 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. // 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. // Returns a sorted list of state entries or an error if there was a problem talking to the database.

View file

@ -19,6 +19,7 @@ import (
"github.com/matrix-org/gomatrixserverlib" "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/shared"
"github.com/matrix-org/dendrite/roomserver/storage/tables" "github.com/matrix-org/dendrite/roomserver/storage/tables"
"github.com/matrix-org/dendrite/roomserver/types" "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) GetOrCreateEventTypeNID(ctx context.Context, eventType string) (eventTypeNID types.EventTypeNID, err error)
GetOrCreateEventStateKeyNID(ctx context.Context, eventStateKey *string) (types.EventStateKeyNID, error) GetOrCreateEventStateKeyNID(ctx context.Context, eventStateKey *string) (types.EventStateKeyNID, error)
MaybeRedactEvent( 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) ) (*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 // 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) // (nil if there was nothing to do)
MaybeRedactEvent( 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) ) (*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) 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)
} }

View file

@ -13,6 +13,7 @@ import (
"github.com/matrix-org/dendrite/internal/caching" "github.com/matrix-org/dendrite/internal/caching"
"github.com/matrix-org/dendrite/internal/sqlutil" "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/storage/tables"
"github.com/matrix-org/dendrite/roomserver/types" "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. // Returns the redaction event and the redacted event if this call resulted in a redaction.
func (d *EventDatabase) MaybeRedactEvent( 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) { ) (*gomatrixserverlib.Event, *gomatrixserverlib.Event, error) {
var ( var (
redactionEvent, redactedEvent *types.Event redactionEvent, redactedEvent *types.Event
@ -968,8 +969,14 @@ func (d *EventDatabase) MaybeRedactEvent(
_, sender1, _ := gomatrixserverlib.SplitID('@', redactedEvent.Sender()) _, sender1, _ := gomatrixserverlib.SplitID('@', redactedEvent.Sender())
_, sender2, _ := gomatrixserverlib.SplitID('@', redactionEvent.Sender()) _, sender2, _ := gomatrixserverlib.SplitID('@', redactionEvent.Sender())
var powerlevels *gomatrixserverlib.PowerLevelContent
powerlevels, err = plResolver.Resolve(ctx, roomInfo, redactionEvent.EventID())
if err != nil {
return err
}
switch { switch {
case redactAllowed: case powerlevels.UserLevel(redactionEvent.Sender()) >= powerlevels.Redact:
// 1. The power level of the redaction events sender is greater than or equal to the redact level. // 1. The power level of the redaction events sender is greater than or equal to the redact level.
case sender1 == sender2: case sender1 == sender2:
// 2. The domain of the redaction events sender matches that of the original events sender. // 2. The domain of the redaction events sender matches that of the original events sender.