mirror of
https://github.com/hoernschen/dendrite.git
synced 2025-07-30 21:12:45 +00:00
Add event size checks similar to Synapse (#3140)
Companion to https://github.com/matrix-org/gomatrixserverlib/pull/400 This tries to mimic the logic found in Synapse, as dropping events can break rooms (and we may end up in endless loops..)
This commit is contained in:
parent
e93bdd56fd
commit
eb9e90379d
5 changed files with 82 additions and 15 deletions
|
@ -250,6 +250,21 @@ func (r *Inputer) processRoomEvent(
|
|||
// really do anything with the event other than reject it at this point.
|
||||
isRejected = true
|
||||
rejectionErr = fmt.Errorf("missingState.processEventWithMissingState: %w", err)
|
||||
switch e := err.(type) {
|
||||
case gomatrixserverlib.EventValidationError:
|
||||
if e.Persistable && stateSnapshot != nil {
|
||||
// We retrieved some state and we ended up having to call /state_ids for
|
||||
// the new event in question (probably because closing the gap by using
|
||||
// /get_missing_events didn't do what we hoped) so we'll instead overwrite
|
||||
// the state snapshot with the newly resolved state.
|
||||
missingPrev = false
|
||||
input.HasState = true
|
||||
input.StateEventIDs = make([]string, 0, len(stateSnapshot.StateEvents))
|
||||
for _, se := range stateSnapshot.StateEvents {
|
||||
input.StateEventIDs = append(input.StateEventIDs, se.EventID())
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if stateSnapshot != nil {
|
||||
// We retrieved some state and we ended up having to call /state_ids for
|
||||
// the new event in question (probably because closing the gap by using
|
||||
|
|
|
@ -259,12 +259,20 @@ func (t *missingStateReq) lookupResolvedStateBeforeEvent(ctx context.Context, e
|
|||
// Therefore, we cannot just query /state_ids with this event to get the state before. Instead, we need to query
|
||||
// the state AFTER all the prev_events for this event, then apply state resolution to that to get the state before the event.
|
||||
var states []*respState
|
||||
var validationError error
|
||||
for _, prevEventID := range e.PrevEventIDs() {
|
||||
// Look up what the state is after the backward extremity. This will either
|
||||
// come from the roomserver, if we know all the required events, or it will
|
||||
// come from a remote server via /state_ids if not.
|
||||
prevState, trustworthy, err := t.lookupStateAfterEvent(ctx, roomVersion, e.RoomID(), prevEventID)
|
||||
if err != nil {
|
||||
switch err2 := err.(type) {
|
||||
case gomatrixserverlib.EventValidationError:
|
||||
if !err2.Persistable {
|
||||
return nil, err2
|
||||
}
|
||||
validationError = err2
|
||||
case nil:
|
||||
default:
|
||||
return nil, fmt.Errorf("t.lookupStateAfterEvent: %w", err)
|
||||
}
|
||||
// Append the state onto the collected state. We'll run this through the
|
||||
|
@ -311,12 +319,19 @@ func (t *missingStateReq) lookupResolvedStateBeforeEvent(ctx context.Context, e
|
|||
t.roomsMu.Lock(e.RoomID())
|
||||
resolvedState, err = t.resolveStatesAndCheck(ctx, roomVersion, respStates, e)
|
||||
t.roomsMu.Unlock(e.RoomID())
|
||||
if err != nil {
|
||||
switch err2 := err.(type) {
|
||||
case gomatrixserverlib.EventValidationError:
|
||||
if !err2.Persistable {
|
||||
return nil, err2
|
||||
}
|
||||
validationError = err2
|
||||
case nil:
|
||||
default:
|
||||
return nil, fmt.Errorf("t.resolveStatesAndCheck: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return resolvedState, nil
|
||||
return resolvedState, validationError
|
||||
}
|
||||
|
||||
// lookupStateAfterEvent returns the room state after `eventID`, which is the state before eventID with the state of `eventID` (if it's a state event)
|
||||
|
@ -339,8 +354,15 @@ func (t *missingStateReq) lookupStateAfterEvent(ctx context.Context, roomVersion
|
|||
}
|
||||
|
||||
// fetch the event we're missing and add it to the pile
|
||||
var validationError error
|
||||
h, err := t.lookupEvent(ctx, roomVersion, roomID, eventID, false)
|
||||
switch err.(type) {
|
||||
switch e := err.(type) {
|
||||
case gomatrixserverlib.EventValidationError:
|
||||
if !e.Persistable {
|
||||
logrus.WithContext(ctx).WithError(err).Errorf("Failed to look up event %s", eventID)
|
||||
return nil, false, e
|
||||
}
|
||||
validationError = e
|
||||
case verifySigError:
|
||||
return respState, false, nil
|
||||
case nil:
|
||||
|
@ -365,7 +387,7 @@ func (t *missingStateReq) lookupStateAfterEvent(ctx context.Context, roomVersion
|
|||
}
|
||||
}
|
||||
|
||||
return respState, false, nil
|
||||
return respState, false, validationError
|
||||
}
|
||||
|
||||
func (t *missingStateReq) cacheAndReturn(ev gomatrixserverlib.PDU) gomatrixserverlib.PDU {
|
||||
|
@ -481,6 +503,7 @@ func (t *missingStateReq) resolveStatesAndCheck(ctx context.Context, roomVersion
|
|||
return nil, err
|
||||
}
|
||||
// apply the current event
|
||||
var validationError error
|
||||
retryAllowedState:
|
||||
if err = checkAllowedByState(backwardsExtremity, resolvedStateEvents, func(roomID spec.RoomID, senderID spec.SenderID) (*spec.UserID, error) {
|
||||
return t.inputer.Queryer.QueryUserIDForSender(ctx, roomID, senderID)
|
||||
|
@ -488,7 +511,12 @@ retryAllowedState:
|
|||
switch missing := err.(type) {
|
||||
case gomatrixserverlib.MissingAuthEventError:
|
||||
h, err2 := t.lookupEvent(ctx, roomVersion, backwardsExtremity.RoomID(), missing.AuthEventID, true)
|
||||
switch err2.(type) {
|
||||
switch e := err2.(type) {
|
||||
case gomatrixserverlib.EventValidationError:
|
||||
if !e.Persistable {
|
||||
return nil, e
|
||||
}
|
||||
validationError = e
|
||||
case verifySigError:
|
||||
return &parsedRespState{
|
||||
AuthEvents: authEventList,
|
||||
|
@ -509,7 +537,7 @@ retryAllowedState:
|
|||
return &parsedRespState{
|
||||
AuthEvents: authEventList,
|
||||
StateEvents: resolvedStateEvents,
|
||||
}, nil
|
||||
}, validationError
|
||||
}
|
||||
|
||||
// get missing events for `e`. If `isGapFilled`=true then `newEvents` contains all the events to inject,
|
||||
|
@ -779,7 +807,11 @@ func (t *missingStateReq) lookupMissingStateViaStateIDs(ctx context.Context, roo
|
|||
// Define what we'll do in order to fetch the missing event ID.
|
||||
fetch := func(missingEventID string) {
|
||||
h, herr := t.lookupEvent(ctx, roomVersion, roomID, missingEventID, false)
|
||||
switch herr.(type) {
|
||||
switch e := herr.(type) {
|
||||
case gomatrixserverlib.EventValidationError:
|
||||
if !e.Persistable {
|
||||
return
|
||||
}
|
||||
case verifySigError:
|
||||
return
|
||||
case nil:
|
||||
|
@ -869,6 +901,8 @@ func (t *missingStateReq) lookupEvent(ctx context.Context, roomVersion gomatrixs
|
|||
}
|
||||
var event gomatrixserverlib.PDU
|
||||
found := false
|
||||
var validationError error
|
||||
serverLoop:
|
||||
for _, serverName := range t.servers {
|
||||
reqctx, cancel := context.WithTimeout(ctx, time.Second*30)
|
||||
defer cancel()
|
||||
|
@ -886,12 +920,25 @@ func (t *missingStateReq) lookupEvent(ctx context.Context, roomVersion gomatrixs
|
|||
continue
|
||||
}
|
||||
event, err = verImpl.NewEventFromUntrustedJSON(txn.PDUs[0])
|
||||
if err != nil {
|
||||
switch e := err.(type) {
|
||||
case gomatrixserverlib.EventValidationError:
|
||||
// If the event is persistable, e.g. failed validation for exceeding
|
||||
// byte sizes, we can "accept" the event.
|
||||
if e.Persistable {
|
||||
validationError = e
|
||||
found = true
|
||||
break serverLoop
|
||||
}
|
||||
// If we can't persist the event, we probably can't do so with results
|
||||
// from other servers, so also break the loop.
|
||||
break serverLoop
|
||||
case nil:
|
||||
found = true
|
||||
break serverLoop
|
||||
default:
|
||||
t.log.WithError(err).WithField("missing_event_id", missingEventID).Warnf("Failed to parse event JSON of event returned from /event")
|
||||
continue
|
||||
}
|
||||
found = true
|
||||
break
|
||||
}
|
||||
if !found {
|
||||
t.log.WithField("missing_event_id", missingEventID).Warnf("Failed to get missing /event for event ID from %d server(s)", len(t.servers))
|
||||
|
@ -903,7 +950,7 @@ func (t *missingStateReq) lookupEvent(ctx context.Context, roomVersion gomatrixs
|
|||
t.log.WithError(err).Warnf("Couldn't validate signature of event %q from /event", event.EventID())
|
||||
return nil, verifySigError{event.EventID(), err}
|
||||
}
|
||||
return t.cacheAndReturn(event), nil
|
||||
return t.cacheAndReturn(event), validationError
|
||||
}
|
||||
|
||||
func checkAllowedByState(e gomatrixserverlib.PDU, stateEvents []gomatrixserverlib.PDU, userIDForSender spec.UserIDForSender) error {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue