Final tweaks

This commit is contained in:
Kegan Dougal 2020-05-12 10:57:12 +01:00
parent 6a4f145def
commit 8ffc5d18b5
3 changed files with 46 additions and 46 deletions

View file

@ -179,6 +179,7 @@ func (t *txnReq) processTransaction() (*gomatrixserverlib.RespSend, error) {
case *gomatrixserverlib.NotAllowed: case *gomatrixserverlib.NotAllowed:
case missingPrevEventsError: case missingPrevEventsError:
default: default:
util.GetLogger(t.context).Warnf("Processing %s failed: %s", e.EventID(), err)
// Any other error should be the result of a temporary error in // Any other error should be the result of a temporary error in
// our server so we should bail processing the transaction entirely. // our server so we should bail processing the transaction entirely.
return nil, err return nil, err
@ -285,18 +286,10 @@ func (t *txnReq) processEvent(e gomatrixserverlib.Event, isInboundTxn bool) erro
} }
// Check that the event is allowed by the state at the event. // Check that the event is allowed by the state at the event.
var events []gomatrixserverlib.Event if err := checkAllowedByState(e, gomatrixserverlib.UnwrapEventHeaders(stateResp.StateEvents)); err != nil {
for _, headeredEvent := range stateResp.StateEvents {
events = append(events, headeredEvent.Unwrap())
util.GetLogger(t.context).Infof("Room state: %s -> %s", headeredEvent.Type(), string(headeredEvent.Content()))
}
if err := checkAllowedByState(e, events); err != nil {
return err return err
} }
// TODO: Check that the roomserver has a copy of all of the auth_events.
// TODO: Check that the event is allowed by its auth_events.
// pass the event to the roomserver // pass the event to the roomserver
_, err := t.producer.SendEvents( _, err := t.producer.SendEvents(
t.context, t.context,
@ -437,14 +430,13 @@ func (t *txnReq) lookupStateAfterEvent(roomVersion gomatrixserverlib.RoomVersion
}, nil }, nil
} }
// don't do auth checks on this RespState as we're just interested in grabbing state/auth events and putting it into the pot respState, err := t.lookupStateBeforeEvent(roomVersion, roomID, eventID)
respState, err := t.lookupStateBeforeEvent(roomVersion, false, roomID, eventID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// fetch the event we're missing and add it to the pile // fetch the event we're missing and add it to the pile
h, err := t.lookupEvent(roomVersion, eventID) h, err := t.lookupEvent(roomVersion, eventID, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -477,21 +469,22 @@ func (t *txnReq) lookupCurrentState(newEvent *gomatrixserverlib.Event) (*gomatri
if err := t.rsAPI.QueryLatestEventsAndState(t.context, &queryReq, &queryRes); err != nil { if err := t.rsAPI.QueryLatestEventsAndState(t.context, &queryReq, &queryRes); err != nil {
return nil, fmt.Errorf("lookupCurrentState rsAPI.QueryLatestEventsAndState: %w", err) return nil, fmt.Errorf("lookupCurrentState rsAPI.QueryLatestEventsAndState: %w", err)
} }
evs := gomatrixserverlib.UnwrapEventHeaders(queryRes.StateEvents)
return &gomatrixserverlib.RespState{ return &gomatrixserverlib.RespState{
StateEvents: gomatrixserverlib.UnwrapEventHeaders(queryRes.StateEvents), StateEvents: evs,
// TODO: Auth events? AuthEvents: evs,
}, nil }, nil
} }
// lookuptStateBeforeEvent returns the room state before the event e, which is just /state_ids and/or /state depending on what // lookuptStateBeforeEvent returns the room state before the event e, which is just /state_ids and/or /state depending on what
// the server supports. // the server supports.
func (t *txnReq) lookupStateBeforeEvent(roomVersion gomatrixserverlib.RoomVersion, doAuthCheck bool, roomID, eventID string) ( func (t *txnReq) lookupStateBeforeEvent(roomVersion gomatrixserverlib.RoomVersion, roomID, eventID string) (
respState *gomatrixserverlib.RespState, err error) { respState *gomatrixserverlib.RespState, err error) {
util.GetLogger(t.context).Infof("lookupStateBeforeEvent %s", eventID) util.GetLogger(t.context).Infof("lookupStateBeforeEvent %s", eventID)
// Attempt to fetch the missing state using /state_ids and /events // Attempt to fetch the missing state using /state_ids and /events
respState, err = t.lookupMissingStateViaStateIDs(roomID, eventID, doAuthCheck, roomVersion) respState, err = t.lookupMissingStateViaStateIDs(roomID, eventID, roomVersion)
if err != nil { if err != nil {
// Fallback to /state // Fallback to /state
util.GetLogger(t.context).WithError(err).Warn("lookupStateBeforeEvent failed to /state_ids, falling back to /state") util.GetLogger(t.context).WithError(err).Warn("lookupStateBeforeEvent failed to /state_ids, falling back to /state")
@ -516,7 +509,19 @@ func (t *txnReq) resolveStatesAndCheck(roomVersion gomatrixserverlib.RoomVersion
return nil, err return nil, err
} }
// apply the current event // apply the current event
retryAllowedState:
if err = checkAllowedByState(*backwardsExtremity, resolvedStateEvents); err != nil { if err = checkAllowedByState(*backwardsExtremity, resolvedStateEvents); err != nil {
switch missing := err.(type) {
case gomatrixserverlib.MissingAuthEventError:
h, err := t.lookupEvent(roomVersion, missing.AuthEventID, true)
if err != nil {
return nil, fmt.Errorf("missing auth event %s and failed to look it up: %w", missing.AuthEventID, err)
}
util.GetLogger(t.context).Infof("fetched event %s", missing.AuthEventID)
resolvedStateEvents = append(resolvedStateEvents, h.Unwrap())
goto retryAllowedState
default:
}
return nil, err return nil, err
} }
return &gomatrixserverlib.RespState{ return &gomatrixserverlib.RespState{
@ -633,7 +638,7 @@ func (t *txnReq) lookupMissingStateViaState(roomID, eventID string, roomVersion
return &state, nil return &state, nil
} }
func (t *txnReq) lookupMissingStateViaStateIDs(roomID, eventID string, doAuthCheck bool, roomVersion gomatrixserverlib.RoomVersion) ( func (t *txnReq) lookupMissingStateViaStateIDs(roomID, eventID string, roomVersion gomatrixserverlib.RoomVersion) (
*gomatrixserverlib.RespState, error) { *gomatrixserverlib.RespState, error) {
util.GetLogger(t.context).Infof("lookupMissingStateViaStateIDs %s", eventID) util.GetLogger(t.context).Infof("lookupMissingStateViaStateIDs %s", eventID)
// fetch the state event IDs at the time of the event // fetch the state event IDs at the time of the event
@ -680,24 +685,23 @@ func (t *txnReq) lookupMissingStateViaStateIDs(roomID, eventID string, doAuthChe
for missingEventID := range missing { for missingEventID := range missing {
var h *gomatrixserverlib.HeaderedEvent var h *gomatrixserverlib.HeaderedEvent
h, err = t.lookupEvent(roomVersion, missingEventID) h, err = t.lookupEvent(roomVersion, missingEventID, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
t.haveEvents[h.EventID()] = h t.haveEvents[h.EventID()] = h
} }
resp, err := t.createRespStateFromStateIDs(stateIDs, doAuthCheck) resp, err := t.createRespStateFromStateIDs(stateIDs)
return resp, err return resp, err
} }
func (t *txnReq) createRespStateFromStateIDs(stateIDs gomatrixserverlib.RespStateIDs, doAuthCheck bool) ( func (t *txnReq) createRespStateFromStateIDs(stateIDs gomatrixserverlib.RespStateIDs) (
*gomatrixserverlib.RespState, error) { *gomatrixserverlib.RespState, error) {
// create a RespState response using the response to /state_ids as a guide // create a RespState response using the response to /state_ids as a guide
respState := gomatrixserverlib.RespState{ respState := gomatrixserverlib.RespState{
AuthEvents: make([]gomatrixserverlib.Event, len(stateIDs.AuthEventIDs)), AuthEvents: make([]gomatrixserverlib.Event, len(stateIDs.AuthEventIDs)),
StateEvents: make([]gomatrixserverlib.Event, len(stateIDs.StateEventIDs)), StateEvents: make([]gomatrixserverlib.Event, len(stateIDs.StateEventIDs)),
} }
var roomVer gomatrixserverlib.RoomVersion
for i := range stateIDs.StateEventIDs { for i := range stateIDs.StateEventIDs {
ev, ok := t.haveEvents[stateIDs.StateEventIDs[i]] ev, ok := t.haveEvents[stateIDs.StateEventIDs[i]]
@ -705,7 +709,6 @@ func (t *txnReq) createRespStateFromStateIDs(stateIDs gomatrixserverlib.RespStat
return nil, fmt.Errorf("missing state event %s", stateIDs.StateEventIDs[i]) return nil, fmt.Errorf("missing state event %s", stateIDs.StateEventIDs[i])
} }
respState.StateEvents[i] = ev.Unwrap() respState.StateEvents[i] = ev.Unwrap()
roomVer = ev.RoomVersion
} }
for i := range stateIDs.AuthEventIDs { for i := range stateIDs.AuthEventIDs {
ev, ok := t.haveEvents[stateIDs.AuthEventIDs[i]] ev, ok := t.haveEvents[stateIDs.AuthEventIDs[i]]
@ -714,31 +717,25 @@ func (t *txnReq) createRespStateFromStateIDs(stateIDs gomatrixserverlib.RespStat
} }
respState.AuthEvents[i] = ev.Unwrap() respState.AuthEvents[i] = ev.Unwrap()
} }
// We purposefully do not do auth checks on the returned events, as they will still
if !doAuthCheck { // be processed in the exact same way, just as a 'rejected' event
return &respState, nil // TODO: Add a field to HeaderedEvent to indicate if the event is rejected.
}
// Check that the returned state is valid.
retryCheck:
if err := respState.Check(t.context, t.keys); err != nil {
switch missing := err.(type) {
case gomatrixserverlib.MissingAuthEventError:
// An auth event was missing so let's look up that event over federation
var newEv *gomatrixserverlib.HeaderedEvent
newEv, err = t.lookupEvent(roomVer, missing.AuthEventID)
if err != nil {
// we can't find this event, fail
return nil, fmt.Errorf("missing auth event %s and cannot find it: %w", missing.AuthEventID, err)
}
respState.AuthEvents = append(respState.AuthEvents, newEv.Unwrap())
goto retryCheck
}
return nil, err
}
return &respState, nil return &respState, nil
} }
func (t *txnReq) lookupEvent(roomVersion gomatrixserverlib.RoomVersion, missingEventID string) (*gomatrixserverlib.HeaderedEvent, error) { func (t *txnReq) lookupEvent(roomVersion gomatrixserverlib.RoomVersion, missingEventID string, localFirst bool) (*gomatrixserverlib.HeaderedEvent, error) {
if localFirst {
// fetch from the roomserver
queryReq := api.QueryEventsByIDRequest{
EventIDs: []string{missingEventID},
}
var queryRes api.QueryEventsByIDResponse
if err := t.rsAPI.QueryEventsByID(t.context, &queryReq, &queryRes); err != nil {
util.GetLogger(t.context).Warnf("Failed to query roomserver for missing event %s: %s - falling back to remote", missingEventID, err)
} else if len(queryRes.Events) == 1 {
return &queryRes.Events[0], nil
}
}
txn, err := t.federation.GetEvent(t.context, t.Origin, missingEventID) txn, err := t.federation.GetEvent(t.context, t.Origin, missingEventID)
if err != nil || len(txn.PDUs) == 0 { if err != nil || len(txn.PDUs) == 0 {
util.GetLogger(t.context).WithError(err).WithField("event_id", missingEventID).Warn("failed to get missing /event for event ID") util.GetLogger(t.context).WithError(err).WithField("event_id", missingEventID).Warn("failed to get missing /event for event ID")

View file

@ -54,7 +54,7 @@ func processRoomEvent(
// Check that the event passes authentication checks and work out the numeric IDs for the auth events. // Check that the event passes authentication checks and work out the numeric IDs for the auth events.
authEventNIDs, err := checkAuthEvents(ctx, db, headered, input.AuthEventIDs) authEventNIDs, err := checkAuthEvents(ctx, db, headered, input.AuthEventIDs)
if err != nil { if err != nil {
logrus.WithError(err).WithField("event_id", event.EventID()).Error("processRoomEvent.checkAuthEvents failed for event") logrus.WithError(err).WithField("event_id", event.EventID()).WithField("auth_event_ids", input.AuthEventIDs).Error("processRoomEvent.checkAuthEvents failed for event")
return return
} }

View file

@ -264,6 +264,9 @@ User can invite local user to room with version 5
remote user can join room with version 5 remote user can join room with version 5
User can invite remote user to room with version 5 User can invite remote user to room with version 5
Remote user can backfill in a room with version 5 Remote user can backfill in a room with version 5
Inbound federation can get state for a room
Inbound federation of state requires event_id as a mandatory paramater
Inbound federation can get state_ids for a room
Inbound federation of state_ids requires event_id as a mandatory paramater
Federation rejects inbound events where the prev_events cannot be found Federation rejects inbound events where the prev_events cannot be found
Outbound federation requests missing prev_events and then asks for /state_ids and resolves the state Outbound federation requests missing prev_events and then asks for /state_ids and resolves the state
Should not be able to take over the room by pretending there is no PL event