* Initial work on soft-fail

* Fix state block retrieval

* Copy-pasta QueryLatestEventsAndState code

* Fix state lookup

* Clean up

* Fix up failing sytest

* Linting

* Update previous events SQLite insert query

* Update SQLite InsertPreviousEvent properly

* Hopefully fix the event references updates

Co-authored-by: Kegan Dougal <kegan@matrix.org>
This commit is contained in:
Neil Alexander 2020-09-21 14:55:46 +01:00 committed by GitHub
parent 880b164490
commit a06c18bb56
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 128 additions and 22 deletions

View file

@ -16,13 +16,78 @@ package helpers
import (
"context"
"fmt"
"sort"
"github.com/matrix-org/dendrite/roomserver/state"
"github.com/matrix-org/dendrite/roomserver/storage"
"github.com/matrix-org/dendrite/roomserver/types"
"github.com/matrix-org/gomatrixserverlib"
)
// CheckForSoftFail returns true if the event should be soft-failed
// and false otherwise. The return error value should be checked before
// the soft-fail bool.
func CheckForSoftFail(
ctx context.Context,
db storage.Database,
event gomatrixserverlib.HeaderedEvent,
stateEventIDs []string,
) (bool, error) {
rewritesState := len(stateEventIDs) > 1
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.
var roomInfo *types.RoomInfo
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, 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
// state because we haven't received a m.room.create event yet.
// If we're now processing the first create event then never
// soft-fail it.
if len(authStateEntries) == 0 && event.Type() == gomatrixserverlib.MRoomCreate {
return false, nil
}
// Work out which of the state events we actually need.
stateNeeded := gomatrixserverlib.StateNeededForAuth([]gomatrixserverlib.Event{event.Unwrap()})
// Load the actual auth events from the database.
authEvents, err := loadAuthEvents(ctx, db, stateNeeded, authStateEntries)
if err != nil {
return true, fmt.Errorf("loadAuthEvents: %w", err)
}
// Check if the event is allowed.
if err = gomatrixserverlib.Allowed(event.Event, &authEvents); err != nil {
// return true, nil
return true, fmt.Errorf("gomatrixserverlib.Allowed: %w", err)
}
return false, nil
}
// CheckAuthEvents checks that the event passes authentication checks
// Returns the numeric IDs for the auth events.
func CheckAuthEvents(

View file

@ -53,6 +53,20 @@ func (r *Inputer) processRoomEvent(
isRejected = true
}
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.
if input.TransactionID != nil {
tdID := input.TransactionID
@ -88,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
}
@ -110,11 +125,13 @@ func (r *Inputer) processRoomEvent(
}
// We stop here if the event is rejected: We've stored it but won't update forward extremities or notify anyone about it.
if isRejected {
if isRejected || softfail {
logrus.WithFields(logrus.Fields{
"event_id": event.EventID(),
"type": event.Type(),
"room": event.RoomID(),
"event_id": event.EventID(),
"type": event.Type(),
"room": event.RoomID(),
"soft_fail": softfail,
"sender": event.Sender(),
}).Debug("Stored rejected event")
return event.EventID(), rejectionErr
}