From 840e4989dcdb5c1462b934df3da4d47f9c41d490 Mon Sep 17 00:00:00 2001 From: Till Faelligen <2353100+S7evinK@users.noreply.github.com> Date: Tue, 23 May 2023 14:48:15 +0200 Subject: [PATCH] Move MakeLeave to GMSL --- federationapi/routing/join.go | 2 +- federationapi/routing/leave.go | 161 ++++++++++++++++--------------- federationapi/routing/routing.go | 20 +++- 3 files changed, 101 insertions(+), 82 deletions(-) diff --git a/federationapi/routing/join.go b/federationapi/routing/join.go index cbdeca51e..19e887163 100644 --- a/federationapi/routing/join.go +++ b/federationapi/routing/join.go @@ -99,7 +99,7 @@ func MakeJoin( } req := api.QueryServerJoinedToRoomRequest{ - ServerName: cfg.Matrix.ServerName, + ServerName: request.Destination(), RoomID: roomID.String(), } res := api.QueryServerJoinedToRoomResponse{} diff --git a/federationapi/routing/leave.go b/federationapi/routing/leave.go index e65403404..024437907 100644 --- a/federationapi/routing/leave.go +++ b/federationapi/routing/leave.go @@ -34,108 +34,115 @@ func MakeLeave( request *fclient.FederationRequest, cfg *config.FederationAPI, rsAPI api.FederationRoomserverAPI, - roomID, userID string, + roomID spec.RoomID, userID spec.UserID, ) util.JSONResponse { - _, domain, err := gomatrixserverlib.SplitID('@', userID) + roomVersion, err := rsAPI.QueryRoomVersionForRoom(httpReq.Context(), roomID.String()) if err != nil { - return util.JSONResponse{ - 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") + util.GetLogger(httpReq.Context()).WithError(err).Error("failed obtaining room version") return util.JSONResponse{ Code: http.StatusInternalServerError, JSON: spec.InternalServerError{}, } } - identity, err := cfg.Matrix.SigningIdentityFor(request.Destination()) - if err != nil { + req := api.QueryServerJoinedToRoomRequest{ + 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{ - Code: http.StatusNotFound, - JSON: spec.NotFound( - fmt.Sprintf("Server name %q does not exist", request.Destination()), - ), + Code: http.StatusInternalServerError, + JSON: spec.InternalServerError{}, } } - var 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 util.JSONResponse{ - Code: http.StatusNotFound, - JSON: spec.NotFound("Room does not exist"), + createLeaveTemplate := func(proto *gomatrixserverlib.ProtoEvent) (gomatrixserverlib.PDU, []gomatrixserverlib.PDU, error) { + identity, err := cfg.Matrix.SigningIdentityFor(request.Destination()) + if err != nil { + util.GetLogger(httpReq.Context()).WithError(err).Errorf("obtaining signing identity for %s failed", request.Destination()) + return nil, nil, spec.NotFound(fmt.Sprintf("Server name %q does not exist", request.Destination())) } - 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) return util.JSONResponse{ - Code: http.StatusBadRequest, - JSON: spec.BadJSON(e.Error()), + Code: http.StatusInternalServerError, + JSON: spec.InternalServerError{}, + } + case spec.MatrixError: + util.GetLogger(httpReq.Context()).WithError(internalErr) + 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: - util.GetLogger(httpReq.Context()).WithError(err).Error("eventutil.BuildEvent failed") + util.GetLogger(httpReq.Context()).WithError(internalErr) + 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{ Code: http.StatusInternalServerError, 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{ Code: http.StatusOK, JSON: map[string]interface{}{ - "room_version": event.Version(), - "event": proto, + "event": response.LeaveTemplateEvent, + "room_version": response.RoomVersion, }, } } diff --git a/federationapi/routing/routing.go b/federationapi/routing/routing.go index 7be0857a6..fad06c1cf 100644 --- a/federationapi/routing/routing.go +++ b/federationapi/routing/routing.go @@ -412,7 +412,7 @@ func Setup( }, )).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, func(httpReq *http.Request, request *fclient.FederationRequest, vars map[string]string) util.JSONResponse { if roomserverAPI.IsServerBannedFromRoom(httpReq.Context(), rsAPI, vars["roomID"], request.Origin()) { @@ -421,10 +421,22 @@ func Setup( JSON: spec.Forbidden("Forbidden by server ACLs"), } } - roomID := vars["roomID"] - eventID := vars["eventID"] + roomID, err := spec.NewRoomID(vars["roomID"]) + 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( - httpReq, request, cfg, rsAPI, roomID, eventID, + httpReq, request, cfg, rsAPI, *roomID, *userID, ) }, )).Methods(http.MethodGet)