Merge branch 'main' into invite-refactor

This commit is contained in:
devonh 2023-05-23 19:16:58 +00:00 committed by GitHub
commit 63156b7a29
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 105 additions and 86 deletions

View file

@ -99,7 +99,7 @@ func MakeJoin(
} }
req := api.QueryServerJoinedToRoomRequest{ req := api.QueryServerJoinedToRoomRequest{
ServerName: cfg.Matrix.ServerName, ServerName: request.Destination(),
RoomID: roomID.String(), RoomID: roomID.String(),
} }
res := api.QueryServerJoinedToRoomResponse{} res := api.QueryServerJoinedToRoomResponse{}
@ -162,13 +162,13 @@ func MakeJoin(
switch e := internalErr.(type) { switch e := internalErr.(type) {
case nil: case nil:
case spec.InternalServerError: case spec.InternalServerError:
util.GetLogger(httpReq.Context()).WithError(internalErr) util.GetLogger(httpReq.Context()).WithError(internalErr).Error("failed to handle make_join request")
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusInternalServerError, Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{}, JSON: spec.InternalServerError{},
} }
case spec.MatrixError: case spec.MatrixError:
util.GetLogger(httpReq.Context()).WithError(internalErr) util.GetLogger(httpReq.Context()).WithError(internalErr).Error("failed to handle make_join request")
code := http.StatusInternalServerError code := http.StatusInternalServerError
switch e.ErrCode { switch e.ErrCode {
case spec.ErrorForbidden: case spec.ErrorForbidden:
@ -186,13 +186,13 @@ func MakeJoin(
JSON: e, JSON: e,
} }
case spec.IncompatibleRoomVersionError: case spec.IncompatibleRoomVersionError:
util.GetLogger(httpReq.Context()).WithError(internalErr) util.GetLogger(httpReq.Context()).WithError(internalErr).Error("failed to handle make_join request")
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
JSON: e, JSON: e,
} }
default: default:
util.GetLogger(httpReq.Context()).WithError(internalErr) util.GetLogger(httpReq.Context()).WithError(internalErr).Error("failed to handle make_join request")
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusBadRequest, Code: http.StatusBadRequest,
JSON: spec.Unknown("unknown error"), JSON: spec.Unknown("unknown error"),

View file

@ -34,108 +34,115 @@ func MakeLeave(
request *fclient.FederationRequest, request *fclient.FederationRequest,
cfg *config.FederationAPI, cfg *config.FederationAPI,
rsAPI api.FederationRoomserverAPI, rsAPI api.FederationRoomserverAPI,
roomID, userID string, roomID spec.RoomID, userID spec.UserID,
) util.JSONResponse { ) util.JSONResponse {
_, domain, err := gomatrixserverlib.SplitID('@', userID) roomVersion, err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), roomID.String())
if err != nil { if err != nil {
return util.JSONResponse{ util.GetLogger(httpReq.Context()).WithError(err).Error("failed obtaining room version")
Code: http.StatusBadRequest,
JSON: spec.BadJSON("Invalid UserID"),
}
}
if domain != request.Origin() {
return util.JSONResponse{
Code: http.StatusForbidden,
JSON: spec.Forbidden("The leave must be sent by the server of the user"),
}
}
// Try building an event for the server
proto := gomatrixserverlib.ProtoEvent{
Sender: userID,
RoomID: roomID,
Type: "m.room.member",
StateKey: &userID,
}
err = proto.SetContent(map[string]interface{}{"membership": spec.Leave})
if err != nil {
util.GetLogger(httpReq.Context()).WithError(err).Error("proto.SetContent failed")
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusInternalServerError, Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{}, JSON: spec.InternalServerError{},
} }
} }
identity, err := cfg.Matrix.SigningIdentityFor(request.Destination()) req := api.QueryServerJoinedToRoomRequest{
if err != nil { ServerName: request.Destination(),
RoomID: roomID.String(),
}
res := api.QueryServerJoinedToRoomResponse{}
if err := rsAPI.QueryServerJoinedToRoom(httpReq.Context(), &req, &res); err != nil {
util.GetLogger(httpReq.Context()).WithError(err).Error("rsAPI.QueryServerJoinedToRoom failed")
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusNotFound, Code: http.StatusInternalServerError,
JSON: spec.NotFound( JSON: spec.InternalServerError{},
fmt.Sprintf("Server name %q does not exist", request.Destination()),
),
} }
} }
var queryRes api.QueryLatestEventsAndStateResponse createLeaveTemplate := func(proto *gomatrixserverlib.ProtoEvent) (gomatrixserverlib.PDU, []gomatrixserverlib.PDU, error) {
event, err := eventutil.QueryAndBuildEvent(httpReq.Context(), &proto, cfg.Matrix, identity, time.Now(), rsAPI, &queryRes) identity, err := cfg.Matrix.SigningIdentityFor(request.Destination())
switch e := err.(type) { if err != nil {
case nil: util.GetLogger(httpReq.Context()).WithError(err).Errorf("obtaining signing identity for %s failed", request.Destination())
case eventutil.ErrRoomNoExists: return nil, nil, spec.NotFound(fmt.Sprintf("Server name %q does not exist", request.Destination()))
util.GetLogger(httpReq.Context()).WithError(err).Error("eventutil.BuildEvent failed")
return util.JSONResponse{
Code: http.StatusNotFound,
JSON: spec.NotFound("Room does not exist"),
} }
case gomatrixserverlib.BadJSONError:
util.GetLogger(httpReq.Context()).WithError(err).Error("eventutil.BuildEvent failed") queryRes := api.QueryLatestEventsAndStateResponse{}
event, err := eventutil.QueryAndBuildEvent(httpReq.Context(), proto, cfg.Matrix, identity, time.Now(), rsAPI, &queryRes)
switch e := err.(type) {
case nil:
case eventutil.ErrRoomNoExists:
util.GetLogger(httpReq.Context()).WithError(err).Error("eventutil.BuildEvent failed")
return nil, nil, spec.NotFound("Room does not exist")
case gomatrixserverlib.BadJSONError:
util.GetLogger(httpReq.Context()).WithError(err).Error("eventutil.BuildEvent failed")
return nil, nil, spec.BadJSON(e.Error())
default:
util.GetLogger(httpReq.Context()).WithError(err).Error("eventutil.BuildEvent failed")
return nil, nil, spec.InternalServerError{}
}
stateEvents := make([]gomatrixserverlib.PDU, len(queryRes.StateEvents))
for i, stateEvent := range queryRes.StateEvents {
stateEvents[i] = stateEvent.PDU
}
return event, stateEvents, nil
}
input := gomatrixserverlib.HandleMakeLeaveInput{
UserID: userID,
RoomID: roomID,
RoomVersion: roomVersion,
RequestOrigin: request.Origin(),
LocalServerName: cfg.Matrix.ServerName,
LocalServerInRoom: res.RoomExists && res.IsInRoom,
BuildEventTemplate: createLeaveTemplate,
}
response, internalErr := gomatrixserverlib.HandleMakeLeave(input)
switch e := internalErr.(type) {
case nil:
case spec.InternalServerError:
util.GetLogger(httpReq.Context()).WithError(internalErr).Error("failed to handle make_leave request")
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusBadRequest, Code: http.StatusInternalServerError,
JSON: spec.BadJSON(e.Error()), JSON: spec.InternalServerError{},
}
case spec.MatrixError:
util.GetLogger(httpReq.Context()).WithError(internalErr).Error("failed to handle make_leave request")
code := http.StatusInternalServerError
switch e.ErrCode {
case spec.ErrorForbidden:
code = http.StatusForbidden
case spec.ErrorNotFound:
code = http.StatusNotFound
case spec.ErrorBadJSON:
code = http.StatusBadRequest
}
return util.JSONResponse{
Code: code,
JSON: e,
} }
default: default:
util.GetLogger(httpReq.Context()).WithError(err).Error("eventutil.BuildEvent failed") util.GetLogger(httpReq.Context()).WithError(internalErr).Error("failed to handle make_leave request")
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: spec.Unknown("unknown error"),
}
}
if response == nil {
util.GetLogger(httpReq.Context()).Error("gmsl.HandleMakeLeave returned invalid response")
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusInternalServerError, Code: http.StatusInternalServerError,
JSON: spec.InternalServerError{}, JSON: spec.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.StateKeyEquals(userID) {
continue
}
if mem, merr := state.Membership(); merr == nil && mem == spec.Leave {
return util.JSONResponse{
Code: http.StatusOK,
JSON: map[string]interface{}{
"room_version": event.Version(),
"event": state,
},
}
}
}
// Check that the leave is allowed or not
stateEvents := make([]gomatrixserverlib.PDU, len(queryRes.StateEvents))
for i := range queryRes.StateEvents {
stateEvents[i] = queryRes.StateEvents[i].PDU
}
provider := gomatrixserverlib.NewAuthEvents(stateEvents)
if err = gomatrixserverlib.Allowed(event, &provider); err != nil {
return util.JSONResponse{
Code: http.StatusForbidden,
JSON: spec.Forbidden(err.Error()),
}
}
return util.JSONResponse{ return util.JSONResponse{
Code: http.StatusOK, Code: http.StatusOK,
JSON: map[string]interface{}{ JSON: map[string]interface{}{
"room_version": event.Version(), "event": response.LeaveTemplateEvent,
"event": proto, "room_version": response.RoomVersion,
}, },
} }
} }

View file

@ -428,7 +428,7 @@ func Setup(
}, },
)).Methods(http.MethodPut) )).Methods(http.MethodPut)
v1fedmux.Handle("/make_leave/{roomID}/{eventID}", MakeFedAPI( v1fedmux.Handle("/make_leave/{roomID}/{userID}", MakeFedAPI(
"federation_make_leave", cfg.Matrix.ServerName, cfg.Matrix.IsLocalServerName, keys, wakeup, "federation_make_leave", cfg.Matrix.ServerName, cfg.Matrix.IsLocalServerName, keys, wakeup,
func(httpReq *http.Request, request *fclient.FederationRequest, vars map[string]string) util.JSONResponse { func(httpReq *http.Request, request *fclient.FederationRequest, vars map[string]string) util.JSONResponse {
if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) {
@ -437,10 +437,22 @@ func Setup(
JSON: spec.Forbidden("Forbidden by server ACLs"), JSON: spec.Forbidden("Forbidden by server ACLs"),
} }
} }
roomID := vars["roomID"] roomID, err := spec.NewRoomID(vars["roomID"])
eventID := vars["eventID"] if err != nil {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: spec.InvalidParam("Invalid RoomID"),
}
}
userID, err := spec.NewUserID(vars["userID"], true)
if err != nil {
return util.JSONResponse{
Code: http.StatusBadRequest,
JSON: spec.InvalidParam("Invalid UserID"),
}
}
return MakeLeave( return MakeLeave(
httpReq, request, cfg, rsAPI, roomID, eventID, httpReq, request, cfg, rsAPI, *roomID, *userID,
) )
}, },
)).Methods(http.MethodGet) )).Methods(http.MethodGet)