diff --git a/cmd/dendrite-federation-api-server/main.go b/cmd/dendrite-federation-api-server/main.go index b8db7927..e3bf5edc 100644 --- a/cmd/dendrite-federation-api-server/main.go +++ b/cmd/dendrite-federation-api-server/main.go @@ -24,18 +24,16 @@ func main() { base := setup.NewBaseDendrite(cfg, "FederationAPI", true) defer base.Close() // nolint: errcheck - accountDB := base.CreateAccountsDB() - deviceDB := base.CreateDeviceDB() + userAPI := base.UserAPIClient() federation := base.CreateFederationClient() serverKeyAPI := base.ServerKeyAPIClient() keyRing := serverKeyAPI.KeyRing() fsAPI := base.FederationSenderHTTPClient() rsAPI := base.RoomserverHTTPClient() - asAPI := base.AppserviceHTTPClient() federationapi.AddPublicRoutes( - base.PublicAPIMux, base.Cfg, accountDB, deviceDB, federation, keyRing, - rsAPI, asAPI, fsAPI, base.EDUServerClient(), + base.PublicAPIMux, base.Cfg, userAPI, federation, keyRing, + rsAPI, fsAPI, base.EDUServerClient(), ) base.SetupAndServeHTTP(string(base.Cfg.Bind.FederationAPI), string(base.Cfg.Listen.FederationAPI)) diff --git a/federationapi/federationapi.go b/federationapi/federationapi.go index db272f1c..c0c00043 100644 --- a/federationapi/federationapi.go +++ b/federationapi/federationapi.go @@ -16,13 +16,11 @@ package federationapi import ( "github.com/gorilla/mux" - appserviceAPI "github.com/matrix-org/dendrite/appservice/api" - "github.com/matrix-org/dendrite/clientapi/auth/storage/accounts" - "github.com/matrix-org/dendrite/clientapi/auth/storage/devices" eduserverAPI "github.com/matrix-org/dendrite/eduserver/api" federationSenderAPI "github.com/matrix-org/dendrite/federationsender/api" "github.com/matrix-org/dendrite/internal/config" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" + userapi "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/dendrite/federationapi/routing" "github.com/matrix-org/gomatrixserverlib" @@ -32,19 +30,17 @@ import ( func AddPublicRoutes( router *mux.Router, cfg *config.Dendrite, - accountsDB accounts.Database, - deviceDB devices.Database, + userAPI userapi.UserInternalAPI, federation *gomatrixserverlib.FederationClient, keyRing gomatrixserverlib.JSONVerifier, rsAPI roomserverAPI.RoomserverInternalAPI, - asAPI appserviceAPI.AppServiceQueryAPI, federationSenderAPI federationSenderAPI.FederationSenderInternalAPI, eduAPI eduserverAPI.EDUServerInputAPI, ) { routing.Setup( - router, cfg, rsAPI, asAPI, + router, cfg, rsAPI, eduAPI, federationSenderAPI, keyRing, - federation, accountsDB, deviceDB, + federation, userAPI, ) } diff --git a/federationapi/federationapi_test.go b/federationapi/federationapi_test.go index cf7d732b..cc85c61b 100644 --- a/federationapi/federationapi_test.go +++ b/federationapi/federationapi_test.go @@ -31,7 +31,7 @@ func TestRoomsV3URLEscapeDoNot404(t *testing.T) { fsAPI := base.FederationSenderHTTPClient() // TODO: This is pretty fragile, as if anything calls anything on these nils this test will break. // Unfortunately, it makes little sense to instantiate these dependencies when we just want to test routing. - federationapi.AddPublicRoutes(base.PublicAPIMux, cfg, nil, nil, nil, keyRing, nil, nil, fsAPI, nil) + federationapi.AddPublicRoutes(base.PublicAPIMux, cfg, nil, nil, keyRing, nil, fsAPI, nil) httputil.SetupHTTPAPI( base.BaseMux, base.PublicAPIMux, diff --git a/federationapi/routing/devices.go b/federationapi/routing/devices.go index caf5fe59..6369c708 100644 --- a/federationapi/routing/devices.go +++ b/federationapi/routing/devices.go @@ -15,9 +15,8 @@ package routing import ( "net/http" - "github.com/matrix-org/dendrite/clientapi/auth/storage/devices" "github.com/matrix-org/dendrite/clientapi/jsonerror" - "github.com/matrix-org/dendrite/clientapi/userutil" + userapi "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" ) @@ -25,17 +24,9 @@ import ( // GetUserDevices for the given user id func GetUserDevices( req *http.Request, - deviceDB devices.Database, + userAPI userapi.UserInternalAPI, userID string, ) util.JSONResponse { - localpart, err := userutil.ParseUsernameParam(userID, nil) - if err != nil { - return util.JSONResponse{ - Code: http.StatusBadRequest, - JSON: jsonerror.InvalidArgumentValue("Invalid user ID"), - } - } - response := gomatrixserverlib.RespUserDevices{ UserID: userID, // TODO: we should return an incrementing stream ID each time the device @@ -43,13 +34,16 @@ func GetUserDevices( StreamID: 0, } - devs, err := deviceDB.GetDevicesByLocalpart(req.Context(), localpart) + var res userapi.QueryDevicesResponse + err := userAPI.QueryDevices(req.Context(), &userapi.QueryDevicesRequest{ + UserID: userID, + }, &res) if err != nil { - util.GetLogger(req.Context()).WithError(err).Error("deviceDB.GetDevicesByLocalPart failed") + util.GetLogger(req.Context()).WithError(err).Error("userAPI.QueryDevices failed") return jsonerror.InternalServerError() } - for _, dev := range devs { + for _, dev := range res.Devices { device := gomatrixserverlib.RespUserDevice{ DeviceID: dev.ID, DisplayName: dev.DisplayName, diff --git a/federationapi/routing/profile.go b/federationapi/routing/profile.go index 61d0682b..a6180ae6 100644 --- a/federationapi/routing/profile.go +++ b/federationapi/routing/profile.go @@ -18,11 +18,10 @@ import ( "fmt" "net/http" - appserviceAPI "github.com/matrix-org/dendrite/appservice/api" - "github.com/matrix-org/dendrite/clientapi/auth/storage/accounts" "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/internal/config" "github.com/matrix-org/dendrite/internal/eventutil" + userapi "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" ) @@ -30,9 +29,8 @@ import ( // GetProfile implements GET /_matrix/federation/v1/query/profile func GetProfile( httpReq *http.Request, - accountDB accounts.Database, + userAPI userapi.UserInternalAPI, cfg *config.Dendrite, - asAPI appserviceAPI.AppServiceQueryAPI, ) util.JSONResponse { userID, field := httpReq.FormValue("user_id"), httpReq.FormValue("field") @@ -60,9 +58,12 @@ func GetProfile( } } - profile, err := appserviceAPI.RetrieveUserProfile(httpReq.Context(), userID, asAPI, accountDB) + var profileRes userapi.QueryProfileResponse + err = userAPI.QueryProfile(httpReq.Context(), &userapi.QueryProfileRequest{ + UserID: userID, + }, &profileRes) if err != nil { - util.GetLogger(httpReq.Context()).WithError(err).Error("appserviceAPI.RetrieveUserProfile failed") + util.GetLogger(httpReq.Context()).WithError(err).Error("userAPI.QueryProfile failed") return jsonerror.InternalServerError() } @@ -73,11 +74,11 @@ func GetProfile( switch field { case "displayname": res = eventutil.DisplayName{ - DisplayName: profile.DisplayName, + DisplayName: profileRes.DisplayName, } case "avatar_url": res = eventutil.AvatarURL{ - AvatarURL: profile.AvatarURL, + AvatarURL: profileRes.AvatarURL, } default: code = http.StatusBadRequest @@ -85,8 +86,8 @@ func GetProfile( } } else { res = eventutil.ProfileResponse{ - AvatarURL: profile.AvatarURL, - DisplayName: profile.DisplayName, + AvatarURL: profileRes.AvatarURL, + DisplayName: profileRes.DisplayName, } } diff --git a/federationapi/routing/routing.go b/federationapi/routing/routing.go index 350febbc..649a43c6 100644 --- a/federationapi/routing/routing.go +++ b/federationapi/routing/routing.go @@ -18,14 +18,12 @@ import ( "net/http" "github.com/gorilla/mux" - appserviceAPI "github.com/matrix-org/dendrite/appservice/api" - "github.com/matrix-org/dendrite/clientapi/auth/storage/accounts" - "github.com/matrix-org/dendrite/clientapi/auth/storage/devices" eduserverAPI "github.com/matrix-org/dendrite/eduserver/api" federationSenderAPI "github.com/matrix-org/dendrite/federationsender/api" "github.com/matrix-org/dendrite/internal/config" "github.com/matrix-org/dendrite/internal/httputil" roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" + userapi "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" ) @@ -48,13 +46,11 @@ func Setup( publicAPIMux *mux.Router, cfg *config.Dendrite, rsAPI roomserverAPI.RoomserverInternalAPI, - asAPI appserviceAPI.AppServiceQueryAPI, eduAPI eduserverAPI.EDUServerInputAPI, fsAPI federationSenderAPI.FederationSenderInternalAPI, keys gomatrixserverlib.JSONVerifier, federation *gomatrixserverlib.FederationClient, - accountDB accounts.Database, - deviceDB devices.Database, + userAPI userapi.UserInternalAPI, ) { v2keysmux := publicAPIMux.PathPrefix(pathPrefixV2Keys).Subrouter() v1fedmux := publicAPIMux.PathPrefix(pathPrefixV1Federation).Subrouter() @@ -98,7 +94,7 @@ func Setup( v1fedmux.Handle("/3pid/onbind", httputil.MakeExternalAPI("3pid_onbind", func(req *http.Request) util.JSONResponse { - return CreateInvitesFrom3PIDInvites(req, rsAPI, asAPI, cfg, federation, accountDB) + return CreateInvitesFrom3PIDInvites(req, rsAPI, cfg, federation, userAPI) }, )).Methods(http.MethodPost, http.MethodOptions) @@ -160,7 +156,7 @@ func Setup( "federation_query_profile", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { return GetProfile( - httpReq, accountDB, cfg, asAPI, + httpReq, userAPI, cfg, ) }, )).Methods(http.MethodGet) @@ -169,7 +165,7 @@ func Setup( "federation_user_devices", cfg.Matrix.ServerName, keys, wakeup, func(httpReq *http.Request, request *gomatrixserverlib.FederationRequest, vars map[string]string) util.JSONResponse { return GetUserDevices( - httpReq, deviceDB, vars["userID"], + httpReq, userAPI, vars["userID"], ) }, )).Methods(http.MethodGet) diff --git a/federationapi/routing/threepid.go b/federationapi/routing/threepid.go index 8f319387..61788010 100644 --- a/federationapi/routing/threepid.go +++ b/federationapi/routing/threepid.go @@ -21,13 +21,11 @@ import ( "net/http" "time" - appserviceAPI "github.com/matrix-org/dendrite/appservice/api" - "github.com/matrix-org/dendrite/clientapi/auth/storage/accounts" "github.com/matrix-org/dendrite/clientapi/httputil" "github.com/matrix-org/dendrite/clientapi/jsonerror" "github.com/matrix-org/dendrite/internal/config" "github.com/matrix-org/dendrite/roomserver/api" - roomserverAPI "github.com/matrix-org/dendrite/roomserver/api" + userapi "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" @@ -57,10 +55,10 @@ var ( // CreateInvitesFrom3PIDInvites implements POST /_matrix/federation/v1/3pid/onbind func CreateInvitesFrom3PIDInvites( - req *http.Request, rsAPI roomserverAPI.RoomserverInternalAPI, - asAPI appserviceAPI.AppServiceQueryAPI, cfg *config.Dendrite, + req *http.Request, rsAPI api.RoomserverInternalAPI, + cfg *config.Dendrite, federation *gomatrixserverlib.FederationClient, - accountDB accounts.Database, + userAPI userapi.UserInternalAPI, ) util.JSONResponse { var body invites if reqErr := httputil.UnmarshalJSONRequest(req, &body); reqErr != nil { @@ -79,7 +77,7 @@ func CreateInvitesFrom3PIDInvites( } event, err := createInviteFrom3PIDInvite( - req.Context(), rsAPI, asAPI, cfg, inv, federation, accountDB, + req.Context(), rsAPI, cfg, inv, federation, userAPI, ) if err != nil { util.GetLogger(req.Context()).WithError(err).Error("createInviteFrom3PIDInvite failed") @@ -107,7 +105,7 @@ func ExchangeThirdPartyInvite( httpReq *http.Request, request *gomatrixserverlib.FederationRequest, roomID string, - rsAPI roomserverAPI.RoomserverInternalAPI, + rsAPI api.RoomserverInternalAPI, cfg *config.Dendrite, federation *gomatrixserverlib.FederationClient, ) util.JSONResponse { @@ -197,10 +195,10 @@ func ExchangeThirdPartyInvite( // Returns an error if there was a problem building the event or fetching the // necessary data to do so. func createInviteFrom3PIDInvite( - ctx context.Context, rsAPI roomserverAPI.RoomserverInternalAPI, - asAPI appserviceAPI.AppServiceQueryAPI, cfg *config.Dendrite, + ctx context.Context, rsAPI api.RoomserverInternalAPI, + cfg *config.Dendrite, inv invite, federation *gomatrixserverlib.FederationClient, - accountDB accounts.Database, + userAPI userapi.UserInternalAPI, ) (*gomatrixserverlib.Event, error) { verReq := api.QueryRoomVersionForRoomRequest{RoomID: inv.RoomID} verRes := api.QueryRoomVersionForRoomResponse{} @@ -225,14 +223,17 @@ func createInviteFrom3PIDInvite( StateKey: &inv.MXID, } - profile, err := appserviceAPI.RetrieveUserProfile(ctx, inv.MXID, asAPI, accountDB) + var res userapi.QueryProfileResponse + err = userAPI.QueryProfile(ctx, &userapi.QueryProfileRequest{ + UserID: inv.MXID, + }, &res) if err != nil { return nil, err } content := gomatrixserverlib.MemberContent{ - AvatarURL: profile.AvatarURL, - DisplayName: profile.DisplayName, + AvatarURL: res.AvatarURL, + DisplayName: res.DisplayName, Membership: gomatrixserverlib.Invite, ThirdPartyInvite: &gomatrixserverlib.MemberThirdPartyInvite{ Signed: inv.Signed, @@ -261,7 +262,7 @@ func createInviteFrom3PIDInvite( // Returns an error if something failed during the process. func buildMembershipEvent( ctx context.Context, - builder *gomatrixserverlib.EventBuilder, rsAPI roomserverAPI.RoomserverInternalAPI, + builder *gomatrixserverlib.EventBuilder, rsAPI api.RoomserverInternalAPI, cfg *config.Dendrite, ) (*gomatrixserverlib.Event, error) { eventsNeeded, err := gomatrixserverlib.StateNeededForEventBuilder(builder) @@ -274,11 +275,11 @@ func buildMembershipEvent( } // Ask the roomserver for information about this room - queryReq := roomserverAPI.QueryLatestEventsAndStateRequest{ + queryReq := api.QueryLatestEventsAndStateRequest{ RoomID: builder.RoomID, StateToFetch: eventsNeeded.Tuples(), } - var queryRes roomserverAPI.QueryLatestEventsAndStateResponse + var queryRes api.QueryLatestEventsAndStateResponse if err = rsAPI.QueryLatestEventsAndState(ctx, &queryReq, &queryRes); err != nil { return nil, err } diff --git a/internal/setup/monolith.go b/internal/setup/monolith.go index b202aa71..aec14aa7 100644 --- a/internal/setup/monolith.go +++ b/internal/setup/monolith.go @@ -77,8 +77,8 @@ func (m *Monolith) AddAllPublicRoutes(publicMux *mux.Router) { keyserver.AddPublicRoutes(publicMux, m.Config, m.UserAPI) federationapi.AddPublicRoutes( - publicMux, m.Config, m.AccountDB, m.DeviceDB, m.FedClient, - m.KeyRing, m.RoomserverAPI, m.AppserviceAPI, m.FederationSenderAPI, + publicMux, m.Config, m.UserAPI, m.FedClient, + m.KeyRing, m.RoomserverAPI, m.FederationSenderAPI, m.EDUInternalAPI, ) mediaapi.AddPublicRoutes(publicMux, m.Config, m.UserAPI, m.Client) diff --git a/userapi/api/api.go b/userapi/api/api.go index 57b5165a..3ed9252c 100644 --- a/userapi/api/api.go +++ b/userapi/api/api.go @@ -20,6 +20,7 @@ import "context" type UserInternalAPI interface { QueryProfile(ctx context.Context, req *QueryProfileRequest, res *QueryProfileResponse) error QueryAccessToken(ctx context.Context, req *QueryAccessTokenRequest, res *QueryAccessTokenResponse) error + QueryDevices(ctx context.Context, req *QueryDevicesRequest, res *QueryDevicesResponse) error } // QueryAccessTokenRequest is the request for QueryAccessToken @@ -36,6 +37,17 @@ type QueryAccessTokenResponse struct { Err error // e.g ErrorForbidden } +// QueryDevicesRequest is the request for QueryDevices +type QueryDevicesRequest struct { + UserID string +} + +// QueryDevicesResponse is the response for QueryDevices +type QueryDevicesResponse struct { + UserExists bool + Devices []Device +} + // QueryProfileRequest is the request for QueryProfile type QueryProfileRequest struct { // The user ID to query diff --git a/userapi/internal/api.go b/userapi/internal/api.go index 1f0d5c94..d8dec11a 100644 --- a/userapi/internal/api.go +++ b/userapi/internal/api.go @@ -57,6 +57,22 @@ func (a *UserInternalAPI) QueryProfile(ctx context.Context, req *api.QueryProfil return nil } +func (a *UserInternalAPI) QueryDevices(ctx context.Context, req *api.QueryDevicesRequest, res *api.QueryDevicesResponse) error { + local, domain, err := gomatrixserverlib.SplitID('@', req.UserID) + if err != nil { + return err + } + if domain != a.ServerName { + return fmt.Errorf("cannot query devices of remote users: got %s want %s", domain, a.ServerName) + } + devs, err := a.DeviceDB.GetDevicesByLocalpart(ctx, local) + if err != nil { + return err + } + res.Devices = devs + return nil +} + func (a *UserInternalAPI) QueryAccessToken(ctx context.Context, req *api.QueryAccessTokenRequest, res *api.QueryAccessTokenResponse) error { if req.AppServiceUserID != "" { appServiceDevice, err := a.queryAppServiceToken(ctx, req.AccessToken, req.AppServiceUserID) diff --git a/userapi/inthttp/client.go b/userapi/inthttp/client.go index 022243fa..638a7e9b 100644 --- a/userapi/inthttp/client.go +++ b/userapi/inthttp/client.go @@ -28,6 +28,7 @@ import ( const ( QueryProfilePath = "/userapi/queryProfile" QueryAccessTokenPath = "/userapi/queryAccessToken" + QueryDevicesPath = "/userapi/queryDevices" ) // NewUserAPIClient creates a UserInternalAPI implemented by talking to a HTTP POST API. @@ -73,3 +74,11 @@ func (h *httpUserInternalAPI) QueryAccessToken( apiURL := h.apiURL + QueryAccessTokenPath return httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) } + +func (h *httpUserInternalAPI) QueryDevices(ctx context.Context, req *api.QueryDevicesRequest, res *api.QueryDevicesResponse) error { + span, ctx := opentracing.StartSpanFromContext(ctx, "QueryDevices") + defer span.Finish() + + apiURL := h.apiURL + QueryDevicesPath + return httputil.PostJSON(ctx, span, h.httpClient, apiURL, req, res) +} diff --git a/userapi/inthttp/server.go b/userapi/inthttp/server.go index 495b161c..19b0e40b 100644 --- a/userapi/inthttp/server.go +++ b/userapi/inthttp/server.go @@ -51,4 +51,17 @@ func AddRoutes(internalAPIMux *mux.Router, s api.UserInternalAPI) { return util.JSONResponse{Code: http.StatusOK, JSON: &response} }), ) + internalAPIMux.Handle(QueryDevicesPath, + httputil.MakeInternalAPI("queryDevices", func(req *http.Request) util.JSONResponse { + request := api.QueryDevicesRequest{} + response := api.QueryDevicesResponse{} + if err := json.NewDecoder(req.Body).Decode(&request); err != nil { + return util.MessageResponse(http.StatusBadRequest, err.Error()) + } + if err := s.QueryDevices(req.Context(), &request, &response); err != nil { + return util.ErrorResponse(err) + } + return util.JSONResponse{Code: http.StatusOK, JSON: &response} + }), + ) }