aboutsummaryrefslogtreecommitdiff
path: root/roomserver
diff options
context:
space:
mode:
authorTill <2353100+S7evinK@users.noreply.github.com>2023-07-07 20:37:23 +0200
committerGitHub <noreply@github.com>2023-07-07 20:37:23 +0200
commiteb9e90379d9f19b1b4192248cbf4931874324857 (patch)
tree4178b1b03ee3a33a70d5b6630e580d029ddf8bec /roomserver
parente93bdd56fd2c155eaf577e337e565f2054408fd4 (diff)
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..)
Diffstat (limited to 'roomserver')
-rw-r--r--roomserver/internal/input/input_events.go15
-rw-r--r--roomserver/internal/input/input_missing.go71
2 files changed, 74 insertions, 12 deletions
diff --git a/roomserver/internal/input/input_events.go b/roomserver/internal/input/input_events.go
index db3c9550..93f6cc01 100644
--- a/roomserver/internal/input/input_events.go
+++ b/roomserver/internal/input/input_events.go
@@ -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
diff --git a/roomserver/internal/input/input_missing.go b/roomserver/internal/input/input_missing.go
index 7ee84e4c..5b4c0727 100644
--- a/roomserver/internal/input/input_missing.go
+++ b/roomserver/internal/input/input_missing.go
@@ -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 {