Try to handle multiple invite rejections better

This commit is contained in:
Neil Alexander 2020-08-14 18:36:29 +01:00
parent 8605c3bb75
commit 07554bcfb7
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944

View file

@ -76,6 +76,23 @@ func MakeLeave(
return jsonerror.InternalServerError() return jsonerror.InternalServerError()
} }
// If the user has already left then just return their last leave
// event. This means that /send_leave will be a no-op, which helps
// to reject invites multiple times - hopefully.
for _, state := range queryRes.StateEvents {
if state.Type() == gomatrixserverlib.MRoomMember && state.StateKeyEquals(userID) {
if mem, merr := state.Membership(); merr == nil && mem == gomatrixserverlib.Leave {
return util.JSONResponse{
Code: http.StatusOK,
JSON: map[string]interface{}{
"room_version": event.RoomVersion,
"event": state,
},
}
}
}
}
// Check that the leave is allowed or not // Check that the leave is allowed or not
stateEvents := make([]*gomatrixserverlib.Event, len(queryRes.StateEvents)) stateEvents := make([]*gomatrixserverlib.Event, len(queryRes.StateEvents))
for i := range queryRes.StateEvents { for i := range queryRes.StateEvents {
@ -99,6 +116,7 @@ func MakeLeave(
} }
// SendLeave implements the /send_leave API // SendLeave implements the /send_leave API
// nolint:gocyclo
func SendLeave( func SendLeave(
httpReq *http.Request, httpReq *http.Request,
request *gomatrixserverlib.FederationRequest, request *gomatrixserverlib.FederationRequest,
@ -149,6 +167,48 @@ func SendLeave(
} }
} }
// Check if the user has already left. If so, no-op!
queryReq := &api.QueryLatestEventsAndStateRequest{
RoomID: roomID,
StateToFetch: []gomatrixserverlib.StateKeyTuple{
{
EventType: gomatrixserverlib.MRoomMember,
StateKey: *event.StateKey(),
},
},
}
queryRes := &api.QueryLatestEventsAndStateResponse{}
err = rsAPI.QueryLatestEventsAndState(httpReq.Context(), queryReq, queryRes)
if err != nil {
util.GetLogger(httpReq.Context()).WithError(err).Error("rsAPI.QueryLatestEventsAndState failed")
return jsonerror.InternalServerError()
}
// The room doesn't exist or we weren't ever joined to it. Might as well
// no-op here.
if !queryRes.RoomExists || len(queryRes.StateEvents) == 0 {
return util.JSONResponse{
Code: http.StatusOK,
JSON: struct{}{},
}
}
// Check if we're recycling a previous leave event.
if event.EventID() == queryRes.StateEvents[0].EventID() {
return util.JSONResponse{
Code: http.StatusOK,
JSON: struct{}{},
}
}
// We are/were joined/invited/banned or something. Check if
// we can no-op here.
if len(queryRes.StateEvents) == 1 {
if mem, merr := queryRes.StateEvents[0].Membership(); merr == nil && mem == gomatrixserverlib.Leave {
return util.JSONResponse{
Code: http.StatusOK,
JSON: struct{}{},
}
}
}
// Check that the event is signed by the server sending the request. // Check that the event is signed by the server sending the request.
redacted := event.Redact() redacted := event.Redact()
verifyRequests := []gomatrixserverlib.VerifyJSONRequest{{ verifyRequests := []gomatrixserverlib.VerifyJSONRequest{{
@ -174,7 +234,8 @@ func SendLeave(
if err != nil { if err != nil {
util.GetLogger(httpReq.Context()).WithError(err).Error("event.Membership failed") util.GetLogger(httpReq.Context()).WithError(err).Error("event.Membership failed")
return jsonerror.InternalServerError() return jsonerror.InternalServerError()
} else if mem != gomatrixserverlib.Leave { }
if mem != gomatrixserverlib.Leave {
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
JSON: jsonerror.BadJSON("The membership in the event content must be set to leave"), JSON: jsonerror.BadJSON("The membership in the event content must be set to leave"),