diff --git a/federationapi/routing/join.go b/federationapi/routing/join.go index cbdeca51e..4cbfc5e87 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{} @@ -162,13 +162,13 @@ func MakeJoin( switch e := internalErr.(type) { case nil: 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{ Code: http.StatusInternalServerError, JSON: spec.InternalServerError{}, } 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 switch e.ErrCode { case spec.ErrorForbidden: @@ -186,13 +186,13 @@ func MakeJoin( JSON: e, } 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{ Code: http.StatusBadRequest, JSON: e, } default: - util.GetLogger(httpReq.Context()).WithError(internalErr) + util.GetLogger(httpReq.Context()).WithError(internalErr).Error("failed to handle make_join request") return util.JSONResponse{ Code: http.StatusBadRequest, JSON: spec.Unknown("unknown error"), diff --git a/federationapi/routing/leave.go b/federationapi/routing/leave.go index e65403404..3e576e09c 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).Error("failed to handle make_leave request") 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).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: - 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{ 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) diff --git a/go.mod b/go.mod index e85051777..bf2dc5de0 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/matrix-org/dugong v0.0.0-20210921133753-66e6b1c67e2e github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91 github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 - github.com/matrix-org/gomatrixserverlib v0.0.0-20230519160810-b92e84b02a7c + github.com/matrix-org/gomatrixserverlib v0.0.0-20230523164045-3fddabebb511 github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 github.com/mattn/go-sqlite3 v1.14.16 diff --git a/go.sum b/go.sum index 6f034fef6..574a7bd7e 100644 --- a/go.sum +++ b/go.sum @@ -323,8 +323,8 @@ github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91 h1:s7fexw github.com/matrix-org/go-sqlite3-js v0.0.0-20220419092513-28aa791a1c91/go.mod h1:e+cg2q7C7yE5QnAXgzo512tgFh1RbQLC0+jozuegKgo= github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 h1:kHKxCOLcHH8r4Fzarl4+Y3K5hjothkVW5z7T1dUM11U= github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s= -github.com/matrix-org/gomatrixserverlib v0.0.0-20230519160810-b92e84b02a7c h1:EF04pmshcDmBQOrBQbzT5htyTivetfyvR70gX2hB9AM= -github.com/matrix-org/gomatrixserverlib v0.0.0-20230519160810-b92e84b02a7c/go.mod h1:H9V9N3Uqn1bBJqYJNGK1noqtgJTaCEhtTdcH/mp50uU= +github.com/matrix-org/gomatrixserverlib v0.0.0-20230523164045-3fddabebb511 h1:om6z/WEVZMxZfgtiyfp5r5ubAObGMyRrnlVD07gIRY4= +github.com/matrix-org/gomatrixserverlib v0.0.0-20230523164045-3fddabebb511/go.mod h1:H9V9N3Uqn1bBJqYJNGK1noqtgJTaCEhtTdcH/mp50uU= github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a h1:awrPDf9LEFySxTLKYBMCiObelNx/cBuv/wzllvCCH3A= github.com/matrix-org/pinecone v0.11.1-0.20230210171230-8c3b24f2649a/go.mod h1:HchJX9oKMXaT2xYFs0Ha/6Zs06mxLU8k6F1ODnrGkeQ= github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 h1:6z4KxomXSIGWqhHcfzExgkH3Z3UkIXry4ibJS4Aqz2Y=