From 9677a95afc529d1766d487db46965266c6fbaa6a Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 13 Aug 2020 12:16:37 +0100 Subject: [PATCH] API setup refactoring (#1266) * Start HTTP endpoint refactoring * Update SetupAndServeHTTP * Fix builds * Don't set up external listener if no address configured * TLS HTTP setup * Break apart client/federation/key/media muxes * Tweaks * Fix P2P demos * Fix media API routing * Review comments @Kegsay * Update sample config * Fix gobind build * Fix External -> Public in federation API test --- build/gobind/monolith.go | 29 ++-- clientapi/routing/routing.go | 12 +- cmd/dendrite-appservice-server/main.go | 7 +- cmd/dendrite-client-api-server/main.go | 9 +- cmd/dendrite-current-state-server/main.go | 7 +- cmd/dendrite-demo-libp2p/main.go | 28 ++-- cmd/dendrite-demo-yggdrasil/main.go | 29 ++-- cmd/dendrite-edu-server/main.go | 7 +- cmd/dendrite-federation-api-server/main.go | 10 +- cmd/dendrite-federation-sender-server/main.go | 7 +- cmd/dendrite-key-server/main.go | 7 +- cmd/dendrite-media-api-server/main.go | 9 +- cmd/dendrite-monolith-server/main.go | 69 ++++----- cmd/dendrite-room-server/main.go | 7 +- cmd/dendrite-server-key-api-server/main.go | 6 +- cmd/dendrite-sync-api-server/main.go | 13 +- cmd/dendrite-user-api-server/main.go | 6 +- cmd/dendritejs/main.go | 27 ++-- cmd/generate-keys/main.go | 5 + cmd/mediaapi-integration-tests/main.go | 2 +- cmd/roomserver-integration-tests/main.go | 2 +- cmd/syncserver-integration-tests/main.go | 3 +- dendrite-config.yaml | 68 ++++++--- federationapi/federationapi.go | 4 +- federationapi/federationapi_test.go | 12 +- federationapi/routing/routing.go | 14 +- federationsender/inthttp/server.go | 15 +- internal/config/config.go | 57 ++++++- internal/config/config_appservice.go | 11 +- internal/config/config_clientapi.go | 16 +- internal/config/config_currentstate.go | 11 +- internal/config/config_eduserver.go | 11 +- internal/config/config_federationapi.go | 16 +- internal/config/config_federationsender.go | 11 +- internal/config/config_keyserver.go | 11 +- internal/config/config_mediaapi.go | 16 +- internal/config/config_roomserver.go | 11 +- internal/config/config_serverkey.go | 11 +- internal/config/config_syncapi.go | 11 +- internal/config/config_test.go | 69 ++++++--- internal/config/config_userapi.go | 11 +- internal/httputil/httpapi.go | 12 -- internal/httputil/paths.go | 7 +- internal/setup/base.go | 142 +++++++++++------- internal/setup/monolith.go | 10 +- internal/test/config.go | 48 +++--- internal/test/server.go | 6 +- mediaapi/routing/routing.go | 7 +- syncapi/routing/routing.go | 6 +- 49 files changed, 542 insertions(+), 383 deletions(-) diff --git a/build/gobind/monolith.go b/build/gobind/monolith.go index e4373490..2ea09f63 100644 --- a/build/gobind/monolith.go +++ b/build/gobind/monolith.go @@ -8,6 +8,7 @@ import ( "net/http" "time" + "github.com/gorilla/mux" "github.com/matrix-org/dendrite/appservice" "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing" "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/yggconn" @@ -170,16 +171,22 @@ func (m *DendriteMonolith) Start() { ygg, fsAPI, federation, ), } - monolith.AddAllPublicRoutes(base.PublicAPIMux) - - httputil.SetupHTTPAPI( - base.BaseMux, - base.PublicAPIMux, - base.InternalAPIMux, - &cfg.Global, - base.UseHTTPAPIs, + monolith.AddAllPublicRoutes( + base.PublicClientAPIMux, + base.PublicFederationAPIMux, + base.PublicKeyAPIMux, + base.PublicMediaAPIMux, ) + httpRouter := mux.NewRouter() + httpRouter.PathPrefix(httputil.InternalPathPrefix).Handler(base.InternalAPIMux) + httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(base.PublicClientAPIMux) + httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux) + + yggRouter := mux.NewRouter() + yggRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(base.PublicFederationAPIMux) + yggRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux) + // Build both ends of a HTTP multiplex. m.httpServer = &http.Server{ Addr: ":0", @@ -190,7 +197,7 @@ func (m *DendriteMonolith) Start() { BaseContext: func(_ net.Listener) context.Context { return context.Background() }, - Handler: base.BaseMux, + Handler: yggRouter, } go func() { @@ -198,8 +205,8 @@ func (m *DendriteMonolith) Start() { m.logger.Fatal(m.httpServer.Serve(ygg)) }() go func() { - m.logger.Info("Listening on ", m.BaseURL()) - m.logger.Fatal(m.httpServer.Serve(m.listener)) + logrus.Info("Listening on ", m.listener.Addr()) + logrus.Fatal(http.Serve(m.listener, httpRouter)) }() go func() { logrus.Info("Sending wake-up message to known nodes") diff --git a/clientapi/routing/routing.go b/clientapi/routing/routing.go index 883b473b..d40621ec 100644 --- a/clientapi/routing/routing.go +++ b/clientapi/routing/routing.go @@ -40,10 +40,6 @@ import ( "github.com/matrix-org/util" ) -const pathPrefixV1 = "/client/api/v1" -const pathPrefixR0 = "/client/r0" -const pathPrefixUnstable = "/client/unstable" - // Setup registers HTTP handlers with the given ServeMux. It also supplies the given http.Client // to clients which need to make outbound HTTP requests. // @@ -68,7 +64,7 @@ func Setup( ) { userInteractiveAuth := auth.NewUserInteractive(accountDB.GetAccountByPassword, cfg) - publicAPIMux.Handle("/client/versions", + publicAPIMux.Handle("/versions", httputil.MakeExternalAPI("versions", func(req *http.Request) util.JSONResponse { return util.JSONResponse{ Code: http.StatusOK, @@ -84,9 +80,9 @@ func Setup( }), ).Methods(http.MethodGet, http.MethodOptions) - r0mux := publicAPIMux.PathPrefix(pathPrefixR0).Subrouter() - v1mux := publicAPIMux.PathPrefix(pathPrefixV1).Subrouter() - unstableMux := publicAPIMux.PathPrefix(pathPrefixUnstable).Subrouter() + r0mux := publicAPIMux.PathPrefix("/r0").Subrouter() + v1mux := publicAPIMux.PathPrefix("/api/v1").Subrouter() + unstableMux := publicAPIMux.PathPrefix("/unstable").Subrouter() r0mux.Handle("/createRoom", httputil.MakeAuthAPI("createRoom", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse { diff --git a/cmd/dendrite-appservice-server/main.go b/cmd/dendrite-appservice-server/main.go index 632b45e6..72b243e2 100644 --- a/cmd/dendrite-appservice-server/main.go +++ b/cmd/dendrite-appservice-server/main.go @@ -30,6 +30,9 @@ func main() { intAPI := appservice.NewInternalAPI(base, userAPI, rsAPI) appservice.AddInternalRoutes(base.InternalAPIMux, intAPI) - base.SetupAndServeHTTP(string(base.Cfg.AppServiceAPI.Bind), string(base.Cfg.AppServiceAPI.Listen)) - + base.SetupAndServeHTTP( + base.Cfg.AppServiceAPI.InternalAPI.Listen, + setup.NoExternalListener, + nil, nil, + ) } diff --git a/cmd/dendrite-client-api-server/main.go b/cmd/dendrite-client-api-server/main.go index 2b6c39b6..4961b34e 100644 --- a/cmd/dendrite-client-api-server/main.go +++ b/cmd/dendrite-client-api-server/main.go @@ -39,10 +39,13 @@ func main() { keyAPI := base.KeyServerHTTPClient() clientapi.AddPublicRoutes( - base.PublicAPIMux, &base.Cfg.ClientAPI, base.KafkaProducer, deviceDB, accountDB, federation, + base.PublicClientAPIMux, &base.Cfg.ClientAPI, base.KafkaProducer, deviceDB, accountDB, federation, rsAPI, eduInputAPI, asQuery, stateAPI, transactions.New(), fsAPI, userAPI, keyAPI, nil, ) - base.SetupAndServeHTTP(string(base.Cfg.ClientAPI.Bind), string(base.Cfg.ClientAPI.Listen)) - + base.SetupAndServeHTTP( + base.Cfg.ClientAPI.InternalAPI.Listen, + base.Cfg.ClientAPI.ExternalAPI.Listen, + nil, nil, + ) } diff --git a/cmd/dendrite-current-state-server/main.go b/cmd/dendrite-current-state-server/main.go index a8c0813f..594bfcf9 100644 --- a/cmd/dendrite-current-state-server/main.go +++ b/cmd/dendrite-current-state-server/main.go @@ -28,6 +28,9 @@ func main() { currentstateserver.AddInternalRoutes(base.InternalAPIMux, stateAPI) - base.SetupAndServeHTTP(string(base.Cfg.CurrentStateServer.Bind), string(base.Cfg.CurrentStateServer.Listen)) - + base.SetupAndServeHTTP( + base.Cfg.CurrentStateServer.InternalAPI.Listen, + setup.NoExternalListener, + nil, nil, + ) } diff --git a/cmd/dendrite-demo-libp2p/main.go b/cmd/dendrite-demo-libp2p/main.go index e3035547..18c85b3b 100644 --- a/cmd/dendrite-demo-libp2p/main.go +++ b/cmd/dendrite-demo-libp2p/main.go @@ -23,6 +23,7 @@ import ( "os" "time" + "github.com/gorilla/mux" gostream "github.com/libp2p/go-libp2p-gostream" p2phttp "github.com/libp2p/go-libp2p-http" p2pdisc "github.com/libp2p/go-libp2p/p2p/discovery" @@ -190,21 +191,28 @@ func main() { KeyAPI: keyAPI, ExtPublicRoomsProvider: provider, } - monolith.AddAllPublicRoutes(base.Base.PublicAPIMux) - - httputil.SetupHTTPAPI( - base.Base.BaseMux, - base.Base.PublicAPIMux, - base.Base.InternalAPIMux, - &cfg.Global, - base.Base.UseHTTPAPIs, + monolith.AddAllPublicRoutes( + base.Base.PublicClientAPIMux, + base.Base.PublicFederationAPIMux, + base.Base.PublicKeyAPIMux, + base.Base.PublicMediaAPIMux, ) + httpRouter := mux.NewRouter() + httpRouter.PathPrefix(httputil.InternalPathPrefix).Handler(base.Base.InternalAPIMux) + httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(base.Base.PublicClientAPIMux) + httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.Base.PublicMediaAPIMux) + + libp2pRouter := mux.NewRouter() + libp2pRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(base.Base.PublicFederationAPIMux) + libp2pRouter.PathPrefix(httputil.PublicKeyPathPrefix).Handler(base.Base.PublicKeyAPIMux) + libp2pRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.Base.PublicMediaAPIMux) + // Expose the matrix APIs directly rather than putting them under a /api path. go func() { httpBindAddr := fmt.Sprintf(":%d", *instancePort) logrus.Info("Listening on ", httpBindAddr) - logrus.Fatal(http.ListenAndServe(httpBindAddr, base.Base.BaseMux)) + logrus.Fatal(http.ListenAndServe(httpBindAddr, httpRouter)) }() // Expose the matrix APIs also via libp2p if base.LibP2P != nil { @@ -217,7 +225,7 @@ func main() { defer func() { logrus.Fatal(listener.Close()) }() - logrus.Fatal(http.Serve(listener, base.Base.BaseMux)) + logrus.Fatal(http.Serve(listener, libp2pRouter)) }() } diff --git a/cmd/dendrite-demo-yggdrasil/main.go b/cmd/dendrite-demo-yggdrasil/main.go index 33ed1542..43bbe94f 100644 --- a/cmd/dendrite-demo-yggdrasil/main.go +++ b/cmd/dendrite-demo-yggdrasil/main.go @@ -23,6 +23,7 @@ import ( "net/http" "time" + "github.com/gorilla/mux" "github.com/matrix-org/dendrite/appservice" "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/embed" "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing" @@ -132,7 +133,7 @@ func main() { rsComponent.SetFederationSenderAPI(fsAPI) - embed.Embed(base.BaseMux, *instancePort, "Yggdrasil Demo") + embed.Embed(base.PublicClientAPIMux, *instancePort, "Yggdrasil Demo") monolith := setup.Monolith{ Config: base.Cfg, @@ -155,16 +156,22 @@ func main() { ygg, fsAPI, federation, ), } - monolith.AddAllPublicRoutes(base.PublicAPIMux) - - httputil.SetupHTTPAPI( - base.BaseMux, - base.PublicAPIMux, - base.InternalAPIMux, - &cfg.Global, - base.UseHTTPAPIs, + monolith.AddAllPublicRoutes( + base.PublicClientAPIMux, + base.PublicFederationAPIMux, + base.PublicKeyAPIMux, + base.PublicMediaAPIMux, ) + httpRouter := mux.NewRouter() + httpRouter.PathPrefix(httputil.InternalPathPrefix).Handler(base.InternalAPIMux) + httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(base.PublicClientAPIMux) + httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux) + + yggRouter := mux.NewRouter() + yggRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(base.PublicFederationAPIMux) + yggRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux) + // Build both ends of a HTTP multiplex. httpServer := &http.Server{ Addr: ":0", @@ -175,7 +182,7 @@ func main() { BaseContext: func(_ net.Listener) context.Context { return context.Background() }, - Handler: base.BaseMux, + Handler: yggRouter, } go func() { @@ -185,7 +192,7 @@ func main() { go func() { httpBindAddr := fmt.Sprintf(":%d", *instancePort) logrus.Info("Listening on ", httpBindAddr) - logrus.Fatal(http.ListenAndServe(httpBindAddr, base.BaseMux)) + logrus.Fatal(http.ListenAndServe(httpBindAddr, httpRouter)) }() go func() { logrus.Info("Sending wake-up message to known nodes") diff --git a/cmd/dendrite-edu-server/main.go b/cmd/dendrite-edu-server/main.go index d3e4e0a0..e0956619 100644 --- a/cmd/dendrite-edu-server/main.go +++ b/cmd/dendrite-edu-server/main.go @@ -33,6 +33,9 @@ func main() { intAPI := eduserver.NewInternalAPI(base, cache.New(), base.UserAPIClient()) eduserver.AddInternalRoutes(base.InternalAPIMux, intAPI) - base.SetupAndServeHTTP(string(base.Cfg.EDUServer.Bind), string(base.Cfg.EDUServer.Listen)) - + base.SetupAndServeHTTP( + base.Cfg.EDUServer.InternalAPI.Listen, + setup.NoExternalListener, + nil, nil, + ) } diff --git a/cmd/dendrite-federation-api-server/main.go b/cmd/dendrite-federation-api-server/main.go index 3b12a295..4181ee0c 100644 --- a/cmd/dendrite-federation-api-server/main.go +++ b/cmd/dendrite-federation-api-server/main.go @@ -33,10 +33,14 @@ func main() { keyAPI := base.KeyServerHTTPClient() federationapi.AddPublicRoutes( - base.PublicAPIMux, &base.Cfg.FederationAPI, userAPI, federation, keyRing, + base.PublicFederationAPIMux, base.PublicKeyAPIMux, + &base.Cfg.FederationAPI, userAPI, federation, keyRing, rsAPI, fsAPI, base.EDUServerClient(), base.CurrentStateAPIClient(), keyAPI, ) - base.SetupAndServeHTTP(string(base.Cfg.FederationAPI.Bind), string(base.Cfg.FederationAPI.Listen)) - + base.SetupAndServeHTTP( + base.Cfg.FederationAPI.InternalAPI.Listen, + base.Cfg.FederationAPI.ExternalAPI.Listen, + nil, nil, + ) } diff --git a/cmd/dendrite-federation-sender-server/main.go b/cmd/dendrite-federation-sender-server/main.go index 152c798a..36906019 100644 --- a/cmd/dendrite-federation-sender-server/main.go +++ b/cmd/dendrite-federation-sender-server/main.go @@ -35,6 +35,9 @@ func main() { ) federationsender.AddInternalRoutes(base.InternalAPIMux, fsAPI) - base.SetupAndServeHTTP(string(base.Cfg.FederationSender.Bind), string(base.Cfg.FederationSender.Listen)) - + base.SetupAndServeHTTP( + base.Cfg.FederationSender.InternalAPI.Listen, + setup.NoExternalListener, + nil, nil, + ) } diff --git a/cmd/dendrite-key-server/main.go b/cmd/dendrite-key-server/main.go index f3110a1e..2110b216 100644 --- a/cmd/dendrite-key-server/main.go +++ b/cmd/dendrite-key-server/main.go @@ -29,6 +29,9 @@ func main() { keyserver.AddInternalRoutes(base.InternalAPIMux, intAPI) - base.SetupAndServeHTTP(string(base.Cfg.KeyServer.Bind), string(base.Cfg.KeyServer.Listen)) - + base.SetupAndServeHTTP( + base.Cfg.KeyServer.InternalAPI.Listen, + setup.NoExternalListener, + nil, nil, + ) } diff --git a/cmd/dendrite-media-api-server/main.go b/cmd/dendrite-media-api-server/main.go index 1bbb62bd..f442abfa 100644 --- a/cmd/dendrite-media-api-server/main.go +++ b/cmd/dendrite-media-api-server/main.go @@ -28,8 +28,11 @@ func main() { userAPI := base.UserAPIClient() client := gomatrixserverlib.NewClient(cfg.FederationSender.DisableTLSValidation) - mediaapi.AddPublicRoutes(base.PublicAPIMux, &base.Cfg.MediaAPI, userAPI, client) - - base.SetupAndServeHTTP(string(base.Cfg.MediaAPI.Bind), string(base.Cfg.MediaAPI.Listen)) + mediaapi.AddPublicRoutes(base.PublicMediaAPIMux, &base.Cfg.MediaAPI, userAPI, client) + base.SetupAndServeHTTP( + base.Cfg.MediaAPI.InternalAPI.Listen, + base.Cfg.MediaAPI.ExternalAPI.Listen, + nil, nil, + ) } diff --git a/cmd/dendrite-monolith-server/main.go b/cmd/dendrite-monolith-server/main.go index 8f98cdd0..bf752708 100644 --- a/cmd/dendrite-monolith-server/main.go +++ b/cmd/dendrite-monolith-server/main.go @@ -16,7 +16,6 @@ package main import ( "flag" - "net/http" "os" "github.com/matrix-org/dendrite/appservice" @@ -25,7 +24,6 @@ import ( "github.com/matrix-org/dendrite/eduserver/cache" "github.com/matrix-org/dendrite/federationsender" "github.com/matrix-org/dendrite/internal/config" - "github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/setup" "github.com/matrix-org/dendrite/keyserver" "github.com/matrix-org/dendrite/roomserver" @@ -33,8 +31,6 @@ import ( "github.com/matrix-org/dendrite/serverkeyapi" "github.com/matrix-org/dendrite/userapi" "github.com/matrix-org/gomatrixserverlib" - - "github.com/sirupsen/logrus" ) var ( @@ -48,23 +44,25 @@ var ( func main() { cfg := setup.ParseFlags(true) + httpAddr := config.HTTPAddress("http://" + *httpBindAddr) + httpsAddr := config.HTTPAddress("https://" + *httpsBindAddr) + if *enableHTTPAPIs { // If the HTTP APIs are enabled then we need to update the Listen // statements in the configuration so that we know where to find // the API endpoints. They'll listen on the same port as the monolith // itself. - addr := config.Address(*httpBindAddr) - cfg.AppServiceAPI.Listen = addr - cfg.ClientAPI.Listen = addr - cfg.CurrentStateServer.Listen = addr - cfg.EDUServer.Listen = addr - cfg.FederationAPI.Listen = addr - cfg.FederationSender.Listen = addr - cfg.KeyServer.Listen = addr - cfg.MediaAPI.Listen = addr - cfg.RoomServer.Listen = addr - cfg.ServerKeyAPI.Listen = addr - cfg.SyncAPI.Listen = addr + cfg.AppServiceAPI.InternalAPI.Connect = httpAddr + cfg.ClientAPI.InternalAPI.Connect = httpAddr + cfg.CurrentStateServer.InternalAPI.Connect = httpAddr + cfg.EDUServer.InternalAPI.Connect = httpAddr + cfg.FederationAPI.InternalAPI.Connect = httpAddr + cfg.FederationSender.InternalAPI.Connect = httpAddr + cfg.KeyServer.InternalAPI.Connect = httpAddr + cfg.MediaAPI.InternalAPI.Connect = httpAddr + cfg.RoomServer.InternalAPI.Connect = httpAddr + cfg.ServerKeyAPI.InternalAPI.Connect = httpAddr + cfg.SyncAPI.InternalAPI.Connect = httpAddr } base := setup.NewBaseDendrite(cfg, "Monolith", *enableHTTPAPIs) @@ -147,38 +145,29 @@ func main() { UserAPI: userAPI, KeyAPI: keyAPI, } - monolith.AddAllPublicRoutes(base.PublicAPIMux) - - httputil.SetupHTTPAPI( - base.BaseMux, - base.PublicAPIMux, - base.InternalAPIMux, - &cfg.Global, - base.UseHTTPAPIs, + monolith.AddAllPublicRoutes( + base.PublicClientAPIMux, + base.PublicFederationAPIMux, + base.PublicKeyAPIMux, + base.PublicMediaAPIMux, ) // Expose the matrix APIs directly rather than putting them under a /api path. go func() { - serv := http.Server{ - Addr: *httpBindAddr, - WriteTimeout: setup.HTTPServerTimeout, - Handler: base.BaseMux, - } - - logrus.Info("Listening on ", serv.Addr) - logrus.Fatal(serv.ListenAndServe()) + base.SetupAndServeHTTP( + config.HTTPAddress(httpAddr), // internal API + config.HTTPAddress(httpAddr), // external API + nil, nil, // TLS settings + ) }() // Handle HTTPS if certificate and key are provided if *certFile != "" && *keyFile != "" { go func() { - serv := http.Server{ - Addr: *httpsBindAddr, - WriteTimeout: setup.HTTPServerTimeout, - Handler: base.BaseMux, - } - - logrus.Info("Listening on ", serv.Addr) - logrus.Fatal(serv.ListenAndServeTLS(*certFile, *keyFile)) + base.SetupAndServeHTTP( + config.HTTPAddress(httpsAddr), // internal API + config.HTTPAddress(httpsAddr), // external API + certFile, keyFile, // TLS settings + ) }() } diff --git a/cmd/dendrite-room-server/main.go b/cmd/dendrite-room-server/main.go index e1d4b16b..0d587e6e 100644 --- a/cmd/dendrite-room-server/main.go +++ b/cmd/dendrite-room-server/main.go @@ -33,6 +33,9 @@ func main() { rsAPI.SetFederationSenderAPI(fsAPI) roomserver.AddInternalRoutes(base.InternalAPIMux, rsAPI) - base.SetupAndServeHTTP(string(base.Cfg.RoomServer.Bind), string(base.Cfg.RoomServer.Listen)) - + base.SetupAndServeHTTP( + base.Cfg.RoomServer.InternalAPI.Listen, + setup.NoExternalListener, + nil, nil, + ) } diff --git a/cmd/dendrite-server-key-api-server/main.go b/cmd/dendrite-server-key-api-server/main.go index 36f34890..1ad4ede2 100644 --- a/cmd/dendrite-server-key-api-server/main.go +++ b/cmd/dendrite-server-key-api-server/main.go @@ -29,5 +29,9 @@ func main() { intAPI := serverkeyapi.NewInternalAPI(&base.Cfg.ServerKeyAPI, federation, base.Caches) serverkeyapi.AddInternalRoutes(base.InternalAPIMux, intAPI, base.Caches) - base.SetupAndServeHTTP(string(base.Cfg.ServerKeyAPI.Bind), string(base.Cfg.ServerKeyAPI.Listen)) + base.SetupAndServeHTTP( + base.Cfg.ServerKeyAPI.InternalAPI.Listen, + setup.NoExternalListener, + nil, nil, + ) } diff --git a/cmd/dendrite-sync-api-server/main.go b/cmd/dendrite-sync-api-server/main.go index c25f8ec1..ec53af6e 100644 --- a/cmd/dendrite-sync-api-server/main.go +++ b/cmd/dendrite-sync-api-server/main.go @@ -30,9 +30,14 @@ func main() { rsAPI := base.RoomserverHTTPClient() syncapi.AddPublicRoutes( - base.PublicAPIMux, base.KafkaConsumer, userAPI, rsAPI, base.KeyServerHTTPClient(), base.CurrentStateAPIClient(), - federation, &cfg.SyncAPI) - - base.SetupAndServeHTTP(string(base.Cfg.SyncAPI.Bind), string(base.Cfg.SyncAPI.Listen)) + base.PublicClientAPIMux, base.KafkaConsumer, userAPI, rsAPI, + base.KeyServerHTTPClient(), base.CurrentStateAPIClient(), + federation, &cfg.SyncAPI, + ) + base.SetupAndServeHTTP( + base.Cfg.SyncAPI.InternalAPI.Listen, + setup.NoExternalListener, + nil, nil, + ) } diff --git a/cmd/dendrite-user-api-server/main.go b/cmd/dendrite-user-api-server/main.go index 22b6255e..c21525e6 100644 --- a/cmd/dendrite-user-api-server/main.go +++ b/cmd/dendrite-user-api-server/main.go @@ -31,5 +31,9 @@ func main() { userapi.AddInternalRoutes(base.InternalAPIMux, userAPI) - base.SetupAndServeHTTP(string(base.Cfg.UserAPI.Bind), string(base.Cfg.UserAPI.Listen)) + base.SetupAndServeHTTP( + base.Cfg.UserAPI.InternalAPI.Listen, + setup.NoExternalListener, + nil, nil, + ) } diff --git a/cmd/dendritejs/main.go b/cmd/dendritejs/main.go index f350a938..ada48cd8 100644 --- a/cmd/dendritejs/main.go +++ b/cmd/dendritejs/main.go @@ -21,6 +21,7 @@ import ( "fmt" "syscall/js" + "github.com/gorilla/mux" "github.com/matrix-org/dendrite/appservice" "github.com/matrix-org/dendrite/currentstateserver" "github.com/matrix-org/dendrite/eduserver" @@ -234,22 +235,28 @@ func main() { //ServerKeyAPI: serverKeyAPI, ExtPublicRoomsProvider: p2pPublicRoomProvider, } - monolith.AddAllPublicRoutes(base.PublicAPIMux) - - httputil.SetupHTTPAPI( - base.BaseMux, - base.PublicAPIMux, - base.InternalAPIMux, - &cfg.Global, - base.UseHTTPAPIs, + monolith.AddAllPublicRoutes( + base.PublicClientAPIMux, + base.PublicFederationAPIMux, + base.PublicKeyAPIMux, + base.PublicMediaAPIMux, ) + httpRouter := mux.NewRouter() + httpRouter.PathPrefix(httputil.InternalPathPrefix).Handler(base.InternalAPIMux) + httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(base.PublicClientAPIMux) + httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux) + + libp2pRouter := mux.NewRouter() + libp2pRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(base.PublicFederationAPIMux) + libp2pRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux) + // Expose the matrix APIs via libp2p-js - for federation traffic if node != nil { go func() { logrus.Info("Listening on libp2p-js host ID ", node.Id) s := JSServer{ - Mux: base.BaseMux, + Mux: libp2pRouter, } s.ListenAndServe("p2p") }() @@ -259,7 +266,7 @@ func main() { go func() { logrus.Info("Listening for service-worker fetch traffic") s := JSServer{ - Mux: base.BaseMux, + Mux: httpRouter, } s.ListenAndServe("fetch") }() diff --git a/cmd/generate-keys/main.go b/cmd/generate-keys/main.go index ceeca567..743109f1 100644 --- a/cmd/generate-keys/main.go +++ b/cmd/generate-keys/main.go @@ -45,6 +45,11 @@ func main() { flag.Parse() + if *tlsCertFile == "" && *tlsKeyFile == "" && *privateKeyFile == "" { + flag.Usage() + return + } + if *tlsCertFile != "" || *tlsKeyFile != "" { if *tlsCertFile == "" || *tlsKeyFile == "" { log.Fatal("Zero or both of --tls-key and --tls-cert must be supplied") diff --git a/cmd/mediaapi-integration-tests/main.go b/cmd/mediaapi-integration-tests/main.go index 4c584979..8a5a0d54 100644 --- a/cmd/mediaapi-integration-tests/main.go +++ b/cmd/mediaapi-integration-tests/main.go @@ -120,7 +120,7 @@ func startMediaAPI(suffix string, dynamicThumbnails bool) (*exec.Cmd, chan error serverArgs, ) - fmt.Printf("==TESTSERVER== STARTED %v -> %v : %v\n", proxyAddr, cfg.MediaAPI.Listen, dir) + fmt.Printf("==TESTSERVER== STARTED %v -> %v : %v\n", proxyAddr, cfg.MediaAPI.InternalAPI.Listen, dir) return cmd, cmdChan, proxyCmd, proxyAddr, dir } diff --git a/cmd/roomserver-integration-tests/main.go b/cmd/roomserver-integration-tests/main.go index a9c88ae1..43574778 100644 --- a/cmd/roomserver-integration-tests/main.go +++ b/cmd/roomserver-integration-tests/main.go @@ -278,7 +278,7 @@ func testRoomserver(input []string, wantOutput []string, checkQueries func(api.R cmd.Args = []string{"dendrite-room-server", "--config", filepath.Join(dir, test.ConfigFile)} gotOutput, err := runAndReadFromTopic(cmd, cfg.RoomServerURL()+"/metrics", doInput, outputTopic, len(wantOutput), func() { - queryAPI, _ := inthttp.NewRoomserverClient("http://"+string(cfg.RoomServer.Listen), &http.Client{Timeout: timeoutHTTP}, cache) + queryAPI, _ := inthttp.NewRoomserverClient("http://"+string(cfg.RoomServer.InternalAPI.Connect), &http.Client{Timeout: timeoutHTTP}, cache) checkQueries(queryAPI) }) if err != nil { diff --git a/cmd/syncserver-integration-tests/main.go b/cmd/syncserver-integration-tests/main.go index bba8fd96..a11dd2a0 100644 --- a/cmd/syncserver-integration-tests/main.go +++ b/cmd/syncserver-integration-tests/main.go @@ -133,7 +133,8 @@ func startSyncServer() (*exec.Cmd, chan error) { } // TODO use the address assigned by the config generator rather than clobbering. cfg.Global.ServerName = "localhost" - cfg.SyncAPI.Listen = config.Address(syncserverAddr) + cfg.SyncAPI.InternalAPI.Listen = config.HTTPAddress("http://" + syncserverAddr) + cfg.SyncAPI.InternalAPI.Connect = cfg.SyncAPI.InternalAPI.Listen if err := test.WriteConfig(cfg, dir); err != nil { panic(err) diff --git a/dendrite-config.yaml b/dendrite-config.yaml index 74bb0711..d1b27c28 100644 --- a/dendrite-config.yaml +++ b/dendrite-config.yaml @@ -88,8 +88,9 @@ global: # Configuration for the Appservice API. app_service_api: - listen: localhost:7777 - bind: localhost:7777 + internal_api: + listen: http://localhost:7777 + connect: http://localhost:7777 database: connection_string: file:appservice.db max_open_conns: 100 @@ -101,8 +102,11 @@ app_service_api: # Configuration for the Client API. client_api: - listen: localhost:7771 - bind: localhost:7771 + internal_api: + listen: http://localhost:7771 + connect: http://localhost:7771 + external_api: + listen: http://[::]:8071 # Prevents new users from being able to register on this homeserver, except when # using the registration shared secret below. @@ -131,8 +135,9 @@ client_api: # Configuration for the Current State Server. current_state_server: - listen: localhost:7782 - bind: localhost:7782 + internal_api: + listen: http://localhost:7782 + connect: http://localhost:7782 database: connection_string: file:currentstate.db max_open_conns: 100 @@ -141,13 +146,17 @@ current_state_server: # Configuration for the EDU server. edu_server: - listen: localhost:7778 - bind: localhost:7778 + internal_api: + listen: http://localhost:7778 + connect: http://localhost:7778 # Configuration for the Federation API. federation_api: - listen: localhost:7772 - bind: localhost:7772 + internal_api: + listen: http://localhost:7772 + connect: http://localhost:7772 + external_api: + listen: http://[::]:8072 # List of paths to X.509 certificates to be used by the external federation listeners. # These certificates will be used to calculate the TLS fingerprints and other servers @@ -157,8 +166,9 @@ federation_api: # Configuration for the Federation Sender. federation_sender: - listen: localhost:7775 - bind: localhost:7775 + internal_api: + listen: http://localhost:7775 + connect: http://localhost:7775 database: connection_string: file:federationsender.db max_open_conns: 100 @@ -182,8 +192,9 @@ federation_sender: # Configuration for the Key Server (for end-to-end encryption). key_server: - listen: localhost:7779 - bind: localhost:7779 + internal_api: + listen: http://localhost:7779 + connect: http://localhost:7779 database: connection_string: file:keyserver.db max_open_conns: 100 @@ -192,8 +203,11 @@ key_server: # Configuration for the Media API. media_api: - listen: localhost:7774 - bind: localhost:7774 + internal_api: + listen: http://localhost:7774 + connect: http://localhost:7774 + external_api: + listen: http://[::]:8074 database: connection_string: file:mediaapi.db max_open_conns: 100 @@ -227,8 +241,9 @@ media_api: # Configuration for the Room Server. room_server: - listen: localhost:7770 - bind: localhost:7770 + internal_api: + listen: http://localhost:7770 + connect: http://localhost:7770 database: connection_string: file:roomserver.db max_open_conns: 100 @@ -237,8 +252,9 @@ room_server: # Configuration for the Server Key API (for server signing keys). server_key_api: - listen: localhost:7780 - bind: localhost:7780 + internal_api: + listen: http://localhost:7780 + connect: http://localhost:7780 database: connection_string: file:serverkeyapi.db max_open_conns: 100 @@ -258,8 +274,9 @@ server_key_api: # Configuration for the Sync API. sync_api: - listen: localhost:7773 - bind: localhost:7773 + internal_api: + listen: http://localhost:7773 + connect: http://localhost:7773 database: connection_string: file:syncapi.db max_open_conns: 100 @@ -268,8 +285,9 @@ sync_api: # Configuration for the User API. user_api: - listen: localhost:7781 - bind: localhost:7781 + internal_api: + listen: http://localhost:7781 + connect: http://localhost:7781 account_database: connection_string: file:userapi_accounts.db max_open_conns: 100 @@ -301,4 +319,4 @@ logging: - type: file level: info params: - path: /var/log/dendrite \ No newline at end of file + path: /var/log/dendrite diff --git a/federationapi/federationapi.go b/federationapi/federationapi.go index e838e8e3..9193685a 100644 --- a/federationapi/federationapi.go +++ b/federationapi/federationapi.go @@ -30,7 +30,7 @@ import ( // AddPublicRoutes sets up and registers HTTP handlers on the base API muxes for the FederationAPI component. func AddPublicRoutes( - router *mux.Router, + fedRouter, keyRouter *mux.Router, cfg *config.FederationAPI, userAPI userapi.UserInternalAPI, federation *gomatrixserverlib.FederationClient, @@ -42,7 +42,7 @@ func AddPublicRoutes( keyAPI keyserverAPI.KeyInternalAPI, ) { routing.Setup( - router, cfg, rsAPI, + fedRouter, keyRouter, cfg, rsAPI, eduAPI, federationSenderAPI, keyRing, federation, userAPI, stateAPI, keyAPI, ) diff --git a/federationapi/federationapi_test.go b/federationapi/federationapi_test.go index 331d3329..45346bc0 100644 --- a/federationapi/federationapi_test.go +++ b/federationapi/federationapi_test.go @@ -8,7 +8,6 @@ import ( "github.com/matrix-org/dendrite/federationapi" "github.com/matrix-org/dendrite/internal/config" - "github.com/matrix-org/dendrite/internal/httputil" "github.com/matrix-org/dendrite/internal/setup" "github.com/matrix-org/dendrite/internal/test" "github.com/matrix-org/gomatrix" @@ -32,15 +31,8 @@ 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.FederationAPI, nil, nil, keyRing, nil, fsAPI, nil, nil, nil) - httputil.SetupHTTPAPI( - base.BaseMux, - base.PublicAPIMux, - base.InternalAPIMux, - &cfg.Global, - base.UseHTTPAPIs, - ) - baseURL, cancel := test.ListenAndServe(t, base.BaseMux, true) + federationapi.AddPublicRoutes(base.PublicFederationAPIMux, base.PublicKeyAPIMux, &cfg.FederationAPI, nil, nil, keyRing, nil, fsAPI, nil, nil, nil) + baseURL, cancel := test.ListenAndServe(t, base.PublicFederationAPIMux, true) defer cancel() serverName := gomatrixserverlib.ServerName(strings.TrimPrefix(baseURL, "https://")) diff --git a/federationapi/routing/routing.go b/federationapi/routing/routing.go index 027827fa..650ef16d 100644 --- a/federationapi/routing/routing.go +++ b/federationapi/routing/routing.go @@ -31,12 +31,6 @@ import ( "github.com/matrix-org/util" ) -const ( - pathPrefixV2Keys = "/key/v2" - pathPrefixV1Federation = "/federation/v1" - pathPrefixV2Federation = "/federation/v2" -) - // Setup registers HTTP handlers with the given ServeMux. // The provided publicAPIMux MUST have `UseEncodedPath()` enabled or else routes will incorrectly // path unescape twice (once from the router, once from MakeFedAPI). We need to have this enabled @@ -46,7 +40,7 @@ const ( // applied: // nolint: gocyclo func Setup( - publicAPIMux *mux.Router, + fedMux, keyMux *mux.Router, cfg *config.FederationAPI, rsAPI roomserverAPI.RoomserverInternalAPI, eduAPI eduserverAPI.EDUServerInputAPI, @@ -57,9 +51,9 @@ func Setup( stateAPI currentstateAPI.CurrentStateInternalAPI, keyAPI keyserverAPI.KeyInternalAPI, ) { - v2keysmux := publicAPIMux.PathPrefix(pathPrefixV2Keys).Subrouter() - v1fedmux := publicAPIMux.PathPrefix(pathPrefixV1Federation).Subrouter() - v2fedmux := publicAPIMux.PathPrefix(pathPrefixV2Federation).Subrouter() + v2keysmux := keyMux.PathPrefix("/v2").Subrouter() + v1fedmux := fedMux.PathPrefix("/v1").Subrouter() + v2fedmux := fedMux.PathPrefix("/v2").Subrouter() wakeup := &httputil.FederationWakeups{ FsAPI: fsAPI, diff --git a/federationsender/inthttp/server.go b/federationsender/inthttp/server.go index ee05cf95..16ef4b09 100644 --- a/federationsender/inthttp/server.go +++ b/federationsender/inthttp/server.go @@ -26,7 +26,8 @@ func AddRoutes(intAPI api.FederationSenderInternalAPI, internalAPIMux *mux.Route return util.JSONResponse{Code: http.StatusOK, JSON: &response} }), ) - internalAPIMux.Handle(FederationSenderPerformJoinRequestPath, + internalAPIMux.Handle( + FederationSenderPerformJoinRequestPath, httputil.MakeInternalAPI("PerformJoinRequest", func(req *http.Request) util.JSONResponse { var request api.PerformJoinRequest var response api.PerformJoinResponse @@ -37,7 +38,8 @@ func AddRoutes(intAPI api.FederationSenderInternalAPI, internalAPIMux *mux.Route return util.JSONResponse{Code: http.StatusOK, JSON: &response} }), ) - internalAPIMux.Handle(FederationSenderPerformLeaveRequestPath, + internalAPIMux.Handle( + FederationSenderPerformLeaveRequestPath, httputil.MakeInternalAPI("PerformLeaveRequest", func(req *http.Request) util.JSONResponse { var request api.PerformLeaveRequest var response api.PerformLeaveResponse @@ -50,7 +52,8 @@ func AddRoutes(intAPI api.FederationSenderInternalAPI, internalAPIMux *mux.Route return util.JSONResponse{Code: http.StatusOK, JSON: &response} }), ) - internalAPIMux.Handle(FederationSenderPerformDirectoryLookupRequestPath, + internalAPIMux.Handle( + FederationSenderPerformDirectoryLookupRequestPath, httputil.MakeInternalAPI("PerformDirectoryLookupRequest", func(req *http.Request) util.JSONResponse { var request api.PerformDirectoryLookupRequest var response api.PerformDirectoryLookupResponse @@ -63,7 +66,8 @@ func AddRoutes(intAPI api.FederationSenderInternalAPI, internalAPIMux *mux.Route return util.JSONResponse{Code: http.StatusOK, JSON: &response} }), ) - internalAPIMux.Handle(FederationSenderPerformServersAlivePath, + internalAPIMux.Handle( + FederationSenderPerformServersAlivePath, httputil.MakeInternalAPI("PerformServersAliveRequest", func(req *http.Request) util.JSONResponse { var request api.PerformServersAliveRequest var response api.PerformServersAliveResponse @@ -76,7 +80,8 @@ func AddRoutes(intAPI api.FederationSenderInternalAPI, internalAPIMux *mux.Route return util.JSONResponse{Code: http.StatusOK, JSON: &response} }), ) - internalAPIMux.Handle(FederationSenderPerformBroadcastEDUPath, + internalAPIMux.Handle( + FederationSenderPerformBroadcastEDUPath, httputil.MakeInternalAPI("PerformBroadcastEDU", func(req *http.Request) util.JSONResponse { var request api.PerformBroadcastEDURequest var response api.PerformBroadcastEDUResponse diff --git a/internal/config/config.go b/internal/config/config.go index 6cd04722..4f812885 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -21,6 +21,7 @@ import ( "fmt" "io" "io/ioutil" + "net/url" "path/filepath" "regexp" "strings" @@ -110,6 +111,15 @@ type Derived struct { // servers from creating RoomIDs in exclusive application service namespaces } +type InternalAPIOptions struct { + Listen HTTPAddress `yaml:"listen"` + Connect HTTPAddress `yaml:"connect"` +} + +type ExternalAPIOptions struct { + Listen HTTPAddress `yaml:"listen"` +} + // A Path on the filesystem. type Path string @@ -132,6 +142,17 @@ type Topic string // An Address to listen on. type Address string +// An HTTPAddress to listen on, starting with either http:// or https://. +type HTTPAddress string + +func (h HTTPAddress) Address() (Address, error) { + url, err := url.Parse(string(h)) + if err != nil { + return "", err + } + return Address(url.Host), nil +} + // FileSizeBytes is a file size in bytes type FileSizeBytes int64 @@ -360,6 +381,26 @@ func checkPositive(configErrs *ConfigErrors, key string, value int64) { } } +// checkURL verifies that the parameter is a valid URL +func checkURL(configErrs *ConfigErrors, key, value string) { + if value == "" { + configErrs.Add(fmt.Sprintf("missing config key %q", key)) + return + } + url, err := url.Parse(value) + if err != nil { + configErrs.Add(fmt.Sprintf("config key %q contains invalid URL (%s)", key, err.Error())) + return + } + switch url.Scheme { + case "http": + case "https": + default: + configErrs.Add(fmt.Sprintf("config key %q URL should be http:// or https://", key)) + return + } +} + // checkLogging verifies the parameters logging.* are valid. func (config *Dendrite) checkLogging(configErrs *ConfigErrors) { for _, logrusHook := range config.Logging { @@ -450,7 +491,7 @@ func (config *Dendrite) AppServiceURL() string { // If we support HTTPS we need to think of a practical way to do certificate validation. // People setting up servers shouldn't need to get a certificate valid for the public // internet for an internal API. - return "http://" + string(config.AppServiceAPI.Listen) + return string(config.AppServiceAPI.InternalAPI.Connect) } // RoomServerURL returns an HTTP URL for where the roomserver is listening. @@ -459,7 +500,7 @@ func (config *Dendrite) RoomServerURL() string { // If we support HTTPS we need to think of a practical way to do certificate validation. // People setting up servers shouldn't need to get a certificate valid for the public // internet for an internal API. - return "http://" + string(config.RoomServer.Listen) + return string(config.RoomServer.InternalAPI.Connect) } // UserAPIURL returns an HTTP URL for where the userapi is listening. @@ -468,7 +509,7 @@ func (config *Dendrite) UserAPIURL() string { // If we support HTTPS we need to think of a practical way to do certificate validation. // People setting up servers shouldn't need to get a certificate valid for the public // internet for an internal API. - return "http://" + string(config.UserAPI.Listen) + return string(config.UserAPI.InternalAPI.Connect) } // CurrentStateAPIURL returns an HTTP URL for where the currentstateserver is listening. @@ -477,7 +518,7 @@ func (config *Dendrite) CurrentStateAPIURL() string { // If we support HTTPS we need to think of a practical way to do certificate validation. // People setting up servers shouldn't need to get a certificate valid for the public // internet for an internal API. - return "http://" + string(config.CurrentStateServer.Listen) + return string(config.CurrentStateServer.InternalAPI.Connect) } // EDUServerURL returns an HTTP URL for where the EDU server is listening. @@ -486,7 +527,7 @@ func (config *Dendrite) EDUServerURL() string { // If we support HTTPS we need to think of a practical way to do certificate validation. // People setting up servers shouldn't need to get a certificate valid for the public // internet for an internal API. - return "http://" + string(config.EDUServer.Listen) + return string(config.EDUServer.InternalAPI.Connect) } // FederationSenderURL returns an HTTP URL for where the federation sender is listening. @@ -495,7 +536,7 @@ func (config *Dendrite) FederationSenderURL() string { // If we support HTTPS we need to think of a practical way to do certificate validation. // People setting up servers shouldn't need to get a certificate valid for the public // internet for an internal API. - return "http://" + string(config.FederationSender.Listen) + return string(config.FederationSender.InternalAPI.Connect) } // ServerKeyAPIURL returns an HTTP URL for where the server key API is listening. @@ -504,7 +545,7 @@ func (config *Dendrite) ServerKeyAPIURL() string { // If we support HTTPS we need to think of a practical way to do certificate validation. // People setting up servers shouldn't need to get a certificate valid for the public // internet for an internal API. - return "http://" + string(config.ServerKeyAPI.Listen) + return string(config.ServerKeyAPI.InternalAPI.Connect) } // KeyServerURL returns an HTTP URL for where the key server is listening. @@ -513,7 +554,7 @@ func (config *Dendrite) KeyServerURL() string { // If we support HTTPS we need to think of a practical way to do certificate validation. // People setting up servers shouldn't need to get a certificate valid for the public // internet for an internal API. - return "http://" + string(config.KeyServer.Listen) + return string(config.KeyServer.InternalAPI.Connect) } // SetupTracing configures the opentracing using the supplied configuration. diff --git a/internal/config/config_appservice.go b/internal/config/config_appservice.go index b8962ded..a042691d 100644 --- a/internal/config/config_appservice.go +++ b/internal/config/config_appservice.go @@ -29,8 +29,7 @@ type AppServiceAPI struct { Matrix *Global `yaml:"-"` Derived *Derived `yaml:"-"` // TODO: Nuke Derived from orbit - Listen Address `yaml:"listen"` - Bind Address `yaml:"bind"` + InternalAPI InternalAPIOptions `yaml:"internal_api"` Database DatabaseOptions `yaml:"database"` @@ -38,15 +37,15 @@ type AppServiceAPI struct { } func (c *AppServiceAPI) Defaults() { - c.Listen = "localhost:7777" - c.Bind = "localhost:7777" + c.InternalAPI.Listen = "http://localhost:7777" + c.InternalAPI.Connect = "http://localhost:7777" c.Database.Defaults() c.Database.ConnectionString = "file:appservice.db" } func (c *AppServiceAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { - checkNotEmpty(configErrs, "app_service_api.listen", string(c.Listen)) - checkNotEmpty(configErrs, "app_service_api.bind", string(c.Bind)) + checkURL(configErrs, "app_service_api.internal_api.listen", string(c.InternalAPI.Listen)) + checkURL(configErrs, "app_service_api.internal_api.bind", string(c.InternalAPI.Connect)) checkNotEmpty(configErrs, "app_service_api.database.connection_string", string(c.Database.ConnectionString)) } diff --git a/internal/config/config_clientapi.go b/internal/config/config_clientapi.go index ae146fcb..f7878276 100644 --- a/internal/config/config_clientapi.go +++ b/internal/config/config_clientapi.go @@ -9,8 +9,8 @@ type ClientAPI struct { Matrix *Global `yaml:"-"` Derived *Derived `yaml:"-"` // TODO: Nuke Derived from orbit - Listen Address `yaml:"listen"` - Bind Address `yaml:"bind"` + InternalAPI InternalAPIOptions `yaml:"internal_api"` + ExternalAPI ExternalAPIOptions `yaml:"external_api"` // If set disables new users from registering (except via shared // secrets) @@ -37,8 +37,9 @@ type ClientAPI struct { } func (c *ClientAPI) Defaults() { - c.Listen = "localhost:7771" - c.Bind = "localhost:7771" + c.InternalAPI.Listen = "http://localhost:7771" + c.InternalAPI.Connect = "http://localhost:7771" + c.ExternalAPI.Listen = "http://[::]:8071" c.RegistrationSharedSecret = "" c.RecaptchaPublicKey = "" c.RecaptchaPrivateKey = "" @@ -49,8 +50,11 @@ func (c *ClientAPI) Defaults() { } func (c *ClientAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { - checkNotEmpty(configErrs, "client_api.listen", string(c.Listen)) - checkNotEmpty(configErrs, "client_api.bind", string(c.Bind)) + checkURL(configErrs, "client_api.internal_api.listen", string(c.InternalAPI.Listen)) + checkURL(configErrs, "client_api.internal_api.connect", string(c.InternalAPI.Connect)) + if !isMonolith { + checkURL(configErrs, "client_api.external_api.listen", string(c.ExternalAPI.Listen)) + } if c.RecaptchaEnabled { checkNotEmpty(configErrs, "client_api.recaptcha_public_key", string(c.RecaptchaPublicKey)) checkNotEmpty(configErrs, "client_api.recaptcha_private_key", string(c.RecaptchaPrivateKey)) diff --git a/internal/config/config_currentstate.go b/internal/config/config_currentstate.go index 2687f7f5..c07ebe15 100644 --- a/internal/config/config_currentstate.go +++ b/internal/config/config_currentstate.go @@ -3,8 +3,7 @@ package config type CurrentStateServer struct { Matrix *Global `yaml:"-"` - Listen Address `yaml:"listen"` - Bind Address `yaml:"bind"` + InternalAPI InternalAPIOptions `yaml:"internal_api"` // The CurrentState database stores the current state of all rooms. // It is accessed by the CurrentStateServer. @@ -12,14 +11,14 @@ type CurrentStateServer struct { } func (c *CurrentStateServer) Defaults() { - c.Listen = "localhost:7782" - c.Bind = "localhost:7782" + c.InternalAPI.Listen = "http://localhost:7782" + c.InternalAPI.Connect = "http://localhost:7782" c.Database.Defaults() c.Database.ConnectionString = "file:currentstate.db" } func (c *CurrentStateServer) Verify(configErrs *ConfigErrors, isMonolith bool) { - checkNotEmpty(configErrs, "current_state_server.listen", string(c.Listen)) - checkNotEmpty(configErrs, "current_state_server.bind", string(c.Bind)) + checkURL(configErrs, "current_state_server.internal_api.listen", string(c.InternalAPI.Listen)) + checkURL(configErrs, "current_state_server.internal_api.connect", string(c.InternalAPI.Connect)) checkNotEmpty(configErrs, "current_state_server.database.connection_string", string(c.Database.ConnectionString)) } diff --git a/internal/config/config_eduserver.go b/internal/config/config_eduserver.go index 02743041..a2ff3697 100644 --- a/internal/config/config_eduserver.go +++ b/internal/config/config_eduserver.go @@ -3,16 +3,15 @@ package config type EDUServer struct { Matrix *Global `yaml:"-"` - Listen Address `yaml:"listen"` - Bind Address `yaml:"bind"` + InternalAPI InternalAPIOptions `yaml:"internal_api"` } func (c *EDUServer) Defaults() { - c.Listen = "localhost:7778" - c.Bind = "localhost:7778" + c.InternalAPI.Listen = "http://localhost:7778" + c.InternalAPI.Connect = "http://localhost:7778" } func (c *EDUServer) Verify(configErrs *ConfigErrors, isMonolith bool) { - checkNotEmpty(configErrs, "edu_server.listen", string(c.Listen)) - checkNotEmpty(configErrs, "edu_server.bind", string(c.Bind)) + checkURL(configErrs, "edu_server.internal_api.listen", string(c.InternalAPI.Listen)) + checkURL(configErrs, "edu_server.internal_api.connect", string(c.InternalAPI.Connect)) } diff --git a/internal/config/config_federationapi.go b/internal/config/config_federationapi.go index d155ef25..727bfce2 100644 --- a/internal/config/config_federationapi.go +++ b/internal/config/config_federationapi.go @@ -5,8 +5,8 @@ import "github.com/matrix-org/gomatrixserverlib" type FederationAPI struct { Matrix *Global `yaml:"-"` - Listen Address `yaml:"listen"` - Bind Address `yaml:"bind"` + InternalAPI InternalAPIOptions `yaml:"internal_api"` + ExternalAPI ExternalAPIOptions `yaml:"external_api"` // List of paths to X509 certificates used by the external federation listeners. // These are used to calculate the TLS fingerprints to publish for this server. @@ -21,13 +21,17 @@ type FederationAPI struct { } func (c *FederationAPI) Defaults() { - c.Listen = "localhost:7772" - c.Bind = "localhost:7772" + c.InternalAPI.Listen = "http://localhost:7772" + c.InternalAPI.Connect = "http://localhost:7772" + c.ExternalAPI.Listen = "http://[::]:8072" } func (c *FederationAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { - checkNotEmpty(configErrs, "federation_api.listen", string(c.Listen)) - checkNotEmpty(configErrs, "federation_api.bind", string(c.Bind)) + checkURL(configErrs, "federation_api.internal_api.listen", string(c.InternalAPI.Listen)) + checkURL(configErrs, "federation_api.internal_api.connect", string(c.InternalAPI.Connect)) + if !isMonolith { + checkURL(configErrs, "federation_api.external_api.listen", string(c.ExternalAPI.Listen)) + } // TODO: not applicable always, e.g. in demos //checkNotZero(configErrs, "federation_api.federation_certificates", int64(len(c.FederationCertificatePaths))) } diff --git a/internal/config/config_federationsender.go b/internal/config/config_federationsender.go index 09d8287b..84f5b6f4 100644 --- a/internal/config/config_federationsender.go +++ b/internal/config/config_federationsender.go @@ -3,8 +3,7 @@ package config type FederationSender struct { Matrix *Global `yaml:"-"` - Listen Address `yaml:"listen"` - Bind Address `yaml:"bind"` + InternalAPI InternalAPIOptions `yaml:"internal_api"` // The FederationSender database stores information used by the FederationSender // It is only accessed by the FederationSender. @@ -24,8 +23,8 @@ type FederationSender struct { } func (c *FederationSender) Defaults() { - c.Listen = "localhost:7775" - c.Bind = "localhost:7775" + c.InternalAPI.Listen = "http://localhost:7775" + c.InternalAPI.Connect = "http://localhost:7775" c.Database.Defaults() c.Database.ConnectionString = "file:federationsender.db" @@ -36,8 +35,8 @@ func (c *FederationSender) Defaults() { } func (c *FederationSender) Verify(configErrs *ConfigErrors, isMonolith bool) { - checkNotEmpty(configErrs, "federation_sender.listen", string(c.Listen)) - checkNotEmpty(configErrs, "federation_sender.bind", string(c.Bind)) + checkURL(configErrs, "federation_sender.internal_api.listen", string(c.InternalAPI.Listen)) + checkURL(configErrs, "federation_sender.internal_api.connect", string(c.InternalAPI.Connect)) checkNotEmpty(configErrs, "federation_sender.database.connection_string", string(c.Database.ConnectionString)) } diff --git a/internal/config/config_keyserver.go b/internal/config/config_keyserver.go index c0967a8a..89162300 100644 --- a/internal/config/config_keyserver.go +++ b/internal/config/config_keyserver.go @@ -3,21 +3,20 @@ package config type KeyServer struct { Matrix *Global `yaml:"-"` - Listen Address `yaml:"listen"` - Bind Address `yaml:"bind"` + InternalAPI InternalAPIOptions `yaml:"internal_api"` Database DatabaseOptions `yaml:"database"` } func (c *KeyServer) Defaults() { - c.Listen = "localhost:7779" - c.Bind = "localhost:7779" + c.InternalAPI.Listen = "http://localhost:7779" + c.InternalAPI.Connect = "http://localhost:7779" c.Database.Defaults() c.Database.ConnectionString = "file:keyserver.db" } func (c *KeyServer) Verify(configErrs *ConfigErrors, isMonolith bool) { - checkNotEmpty(configErrs, "key_server.listen", string(c.Listen)) - checkNotEmpty(configErrs, "key_server.bind", string(c.Bind)) + checkURL(configErrs, "key_server.internal_api.listen", string(c.InternalAPI.Listen)) + checkURL(configErrs, "key_server.internal_api.bind", string(c.InternalAPI.Connect)) checkNotEmpty(configErrs, "key_server.database.connection_string", string(c.Database.ConnectionString)) } diff --git a/internal/config/config_mediaapi.go b/internal/config/config_mediaapi.go index 9a4d7e0a..a9425b7b 100644 --- a/internal/config/config_mediaapi.go +++ b/internal/config/config_mediaapi.go @@ -7,8 +7,8 @@ import ( type MediaAPI struct { Matrix *Global `yaml:"-"` - Listen Address `yaml:"listen"` - Bind Address `yaml:"bind"` + InternalAPI InternalAPIOptions `yaml:"internal_api"` + ExternalAPI ExternalAPIOptions `yaml:"external_api"` // The MediaAPI database stores information about files uploaded and downloaded // by local users. It is only accessed by the MediaAPI. @@ -36,8 +36,9 @@ type MediaAPI struct { } func (c *MediaAPI) Defaults() { - c.Listen = "localhost:7774" - c.Bind = "localhost:7774" + c.InternalAPI.Listen = "http://localhost:7774" + c.InternalAPI.Connect = "http://localhost:7774" + c.ExternalAPI.Listen = "http://[::]:8074" c.Database.Defaults() c.Database.ConnectionString = "file:mediaapi.db" @@ -48,8 +49,11 @@ func (c *MediaAPI) Defaults() { } func (c *MediaAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { - checkNotEmpty(configErrs, "media_api.listen", string(c.Listen)) - checkNotEmpty(configErrs, "media_api.bind", string(c.Bind)) + checkURL(configErrs, "media_api.internal_api.listen", string(c.InternalAPI.Listen)) + checkURL(configErrs, "media_api.internal_api.connect", string(c.InternalAPI.Connect)) + if !isMonolith { + checkURL(configErrs, "media_api.external_api.listen", string(c.ExternalAPI.Listen)) + } checkNotEmpty(configErrs, "media_api.database.connection_string", string(c.Database.ConnectionString)) checkNotEmpty(configErrs, "media_api.base_path", string(c.BasePath)) diff --git a/internal/config/config_roomserver.go b/internal/config/config_roomserver.go index 1a16e2b1..2a1fc38b 100644 --- a/internal/config/config_roomserver.go +++ b/internal/config/config_roomserver.go @@ -3,21 +3,20 @@ package config type RoomServer struct { Matrix *Global `yaml:"-"` - Listen Address `yaml:"listen"` - Bind Address `yaml:"bind"` + InternalAPI InternalAPIOptions `yaml:"internal_api"` Database DatabaseOptions `yaml:"database"` } func (c *RoomServer) Defaults() { - c.Listen = "localhost:7770" - c.Bind = "localhost:7770" + c.InternalAPI.Listen = "http://localhost:7770" + c.InternalAPI.Connect = "http://localhost:7770" c.Database.Defaults() c.Database.ConnectionString = "file:roomserver.db" } func (c *RoomServer) Verify(configErrs *ConfigErrors, isMonolith bool) { - checkNotEmpty(configErrs, "room_server.listen", string(c.Listen)) - checkNotEmpty(configErrs, "room_server.bind", string(c.Bind)) + checkURL(configErrs, "room_server.internal_api.listen", string(c.InternalAPI.Listen)) + checkURL(configErrs, "room_server.internal_ap.bind", string(c.InternalAPI.Connect)) checkNotEmpty(configErrs, "room_server.database.connection_string", string(c.Database.ConnectionString)) } diff --git a/internal/config/config_serverkey.go b/internal/config/config_serverkey.go index 78dc1194..40506d23 100644 --- a/internal/config/config_serverkey.go +++ b/internal/config/config_serverkey.go @@ -5,8 +5,7 @@ import "github.com/matrix-org/gomatrixserverlib" type ServerKeyAPI struct { Matrix *Global `yaml:"-"` - Listen Address `yaml:"listen"` - Bind Address `yaml:"bind"` + InternalAPI InternalAPIOptions `yaml:"internal_api"` // The ServerKey database caches the public keys of remote servers. // It may be accessed by the FederationAPI, the ClientAPI, and the MediaAPI. @@ -18,15 +17,15 @@ type ServerKeyAPI struct { } func (c *ServerKeyAPI) Defaults() { - c.Listen = "localhost:7780" - c.Bind = "localhost:7780" + c.InternalAPI.Listen = "http://localhost:7780" + c.InternalAPI.Connect = "http://localhost:7780" c.Database.Defaults() c.Database.ConnectionString = "file:serverkeyapi.db" } func (c *ServerKeyAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { - checkNotEmpty(configErrs, "server_key_api.listen", string(c.Listen)) - checkNotEmpty(configErrs, "server_key_api.bind", string(c.Bind)) + checkURL(configErrs, "server_key_api.internal_api.listen", string(c.InternalAPI.Listen)) + checkURL(configErrs, "server_key_api.internal_api.bind", string(c.InternalAPI.Connect)) checkNotEmpty(configErrs, "server_key_api.database.connection_string", string(c.Database.ConnectionString)) } diff --git a/internal/config/config_syncapi.go b/internal/config/config_syncapi.go index 488f6658..fc1bbcf8 100644 --- a/internal/config/config_syncapi.go +++ b/internal/config/config_syncapi.go @@ -3,21 +3,20 @@ package config type SyncAPI struct { Matrix *Global `yaml:"-"` - Listen Address `yaml:"listen"` - Bind Address `yaml:"bind"` + InternalAPI InternalAPIOptions `yaml:"internal_api"` Database DatabaseOptions `yaml:"database"` } func (c *SyncAPI) Defaults() { - c.Listen = "localhost:7773" - c.Bind = "localhost:7773" + c.InternalAPI.Listen = "http://localhost:7773" + c.InternalAPI.Connect = "http://localhost:7773" c.Database.Defaults() c.Database.ConnectionString = "file:syncapi.db" } func (c *SyncAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { - checkNotEmpty(configErrs, "sync_api.listen", string(c.Listen)) - checkNotEmpty(configErrs, "sync_api.bind", string(c.Bind)) + checkURL(configErrs, "sync_api.internal_api.listen", string(c.InternalAPI.Listen)) + checkURL(configErrs, "sync_api.internal_api.bind", string(c.InternalAPI.Connect)) checkNotEmpty(configErrs, "sync_api.database", string(c.Database.ConnectionString)) } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 050debff..39b3ee47 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -43,7 +43,8 @@ global: - matrix.org - vector.im kafka: - addresses: [] + addresses: + - localhost:2181 topic_prefix: Dendrite use_naffka: true naffka_database: @@ -57,8 +58,9 @@ global: username: metrics password: metrics app_service_api: - listen: localhost:7777 - bind: localhost:7777 + internal_api: + listen: http://localhost:7777 + connect: http://localhost:7777 database: connection_string: file:appservice.db max_open_conns: 100 @@ -66,8 +68,11 @@ app_service_api: conn_max_lifetime: -1 config_files: [] client_api: - listen: localhost:7771 - bind: localhost:7771 + internal_api: + listen: http://localhost:7771 + connect: http://localhost:7771 + external_api: + listen: http://[::]:8071 registration_disabled: false registration_shared_secret: "" enable_registration_captcha: false @@ -82,23 +87,29 @@ client_api: turn_username: "" turn_password: "" current_state_server: - listen: localhost:7782 - bind: localhost:7782 + internal_api: + listen: http://localhost:7782 + connect: http://localhost:7782 database: connection_string: file:currentstate.db max_open_conns: 100 max_idle_conns: 2 conn_max_lifetime: -1 edu_server: - listen: localhost:7778 - bind: localhost:7778 + internal_api: + listen: http://localhost:7778 + connect: http://localhost:7778 federation_api: - listen: localhost:7772 - bind: localhost:7772 + internal_api: + listen: http://localhost:7772 + connect: http://localhost:7772 + external_api: + listen: http://[::]:8072 federation_certificates: [] federation_sender: - listen: localhost:7775 - bind: localhost:7775 + internal_api: + listen: http://localhost:7775 + connect: http://localhost:7775 database: connection_string: file:federationsender.db max_open_conns: 100 @@ -112,16 +123,20 @@ federation_sender: host: localhost port: 8080 key_server: - listen: localhost:7779 - bind: localhost:7779 + internal_api: + listen: http://localhost:7779 + connect: http://localhost:7779 database: connection_string: file:keyserver.db max_open_conns: 100 max_idle_conns: 2 conn_max_lifetime: -1 media_api: - listen: localhost:7774 - bind: localhost:7774 + internal_api: + listen: http://localhost:7774 + connect: http://localhost:7774 + external_api: + listen: http://[::]:8074 database: connection_string: file:mediaapi.db max_open_conns: 100 @@ -142,16 +157,18 @@ media_api: height: 480 method: scale room_server: - listen: localhost:7770 - bind: localhost:7770 + internal_api: + listen: http://localhost:7770 + connect: http://localhost:7770 database: connection_string: file:roomserver.db max_open_conns: 100 max_idle_conns: 2 conn_max_lifetime: -1 server_key_api: - listen: localhost:7780 - bind: localhost:7780 + internal_api: + listen: http://localhost:7780 + connect: http://localhost:7780 database: connection_string: file:serverkeyapi.db max_open_conns: 100 @@ -165,16 +182,18 @@ server_key_api: - key_id: ed25519:a_RXGa public_key: l8Hft5qXKn1vfHrg3p4+W8gELQVo8N13JkluMfmn2sQ sync_api: - listen: localhost:7773 - bind: localhost:7773 + internal_api: + listen: http://localhost:7773 + connect: http://localhost:7773 database: connection_string: file:syncapi.db max_open_conns: 100 max_idle_conns: 2 conn_max_lifetime: -1 user_api: - listen: localhost:7781 - bind: localhost:7781 + internal_api: + listen: http://localhost:7781 + connect: http://localhost:7781 account_database: connection_string: file:userapi_accounts.db max_open_conns: 100 diff --git a/internal/config/config_userapi.go b/internal/config/config_userapi.go index f7da9e59..2cbd8a45 100644 --- a/internal/config/config_userapi.go +++ b/internal/config/config_userapi.go @@ -3,8 +3,7 @@ package config type UserAPI struct { Matrix *Global `yaml:"-"` - Listen Address `yaml:"listen"` - Bind Address `yaml:"bind"` + InternalAPI InternalAPIOptions `yaml:"internal_api"` // The Account database stores the login details and account information // for local users. It is accessed by the UserAPI. @@ -15,8 +14,8 @@ type UserAPI struct { } func (c *UserAPI) Defaults() { - c.Listen = "localhost:7781" - c.Bind = "localhost:7781" + c.InternalAPI.Listen = "http://localhost:7781" + c.InternalAPI.Connect = "http://localhost:7781" c.AccountDatabase.Defaults() c.DeviceDatabase.Defaults() c.AccountDatabase.ConnectionString = "file:userapi_accounts.db" @@ -24,8 +23,8 @@ func (c *UserAPI) Defaults() { } func (c *UserAPI) Verify(configErrs *ConfigErrors, isMonolith bool) { - checkNotEmpty(configErrs, "user_api.listen", string(c.Listen)) - checkNotEmpty(configErrs, "user_api.bind", string(c.Bind)) + checkURL(configErrs, "user_api.internal_api.listen", string(c.InternalAPI.Listen)) + checkURL(configErrs, "user_api.internal_api.connect", string(c.InternalAPI.Connect)) checkNotEmpty(configErrs, "user_api.account_database.connection_string", string(c.AccountDatabase.ConnectionString)) checkNotEmpty(configErrs, "user_api.device_database.connection_string", string(c.DeviceDatabase.ConnectionString)) } diff --git a/internal/httputil/httpapi.go b/internal/httputil/httpapi.go index 8f7723ef..c69468e6 100644 --- a/internal/httputil/httpapi.go +++ b/internal/httputil/httpapi.go @@ -28,7 +28,6 @@ import ( "github.com/gorilla/mux" "github.com/matrix-org/dendrite/clientapi/auth" federationsenderAPI "github.com/matrix-org/dendrite/federationsender/api" - "github.com/matrix-org/dendrite/internal/config" userapi "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/util" @@ -233,17 +232,6 @@ func (f *FederationWakeups) Wakeup(ctx context.Context, origin gomatrixserverlib } } -// SetupHTTPAPI registers an HTTP API mux under /api and sets up a metrics listener -func SetupHTTPAPI(servMux, publicApiMux, internalApiMux *mux.Router, cfg *config.Global, enableHTTPAPIs bool) { - if cfg.Metrics.Enabled { - servMux.Handle("/metrics", WrapHandlerInBasicAuth(promhttp.Handler(), cfg.Metrics.BasicAuth)) - } - if enableHTTPAPIs { - servMux.Handle(InternalPathPrefix, internalApiMux) - } - servMux.Handle(PublicPathPrefix, WrapHandlerInCORS(publicApiMux)) -} - // WrapHandlerInBasicAuth adds basic auth to a handler. Only used for /metrics func WrapHandlerInBasicAuth(h http.Handler, b BasicAuth) http.HandlerFunc { if b.Username == "" || b.Password == "" { diff --git a/internal/httputil/paths.go b/internal/httputil/paths.go index 728b5a87..b0f4b8cb 100644 --- a/internal/httputil/paths.go +++ b/internal/httputil/paths.go @@ -15,6 +15,9 @@ package httputil const ( - PublicPathPrefix = "/_matrix/" - InternalPathPrefix = "/api/" + PublicClientPathPrefix = "/_matrix/client/" + PublicFederationPathPrefix = "/_matrix/federation/" + PublicKeyPathPrefix = "/_matrix/key/" + PublicMediaPathPrefix = "/_matrix/media/" + InternalPathPrefix = "/api/" ) diff --git a/internal/setup/base.go b/internal/setup/base.go index f59d136e..2cffb4e8 100644 --- a/internal/setup/base.go +++ b/internal/setup/base.go @@ -27,6 +27,7 @@ import ( "github.com/matrix-org/dendrite/internal/sqlutil" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/naffka" + "github.com/prometheus/client_golang/prometheus/promhttp" "github.com/matrix-org/dendrite/internal" "github.com/matrix-org/dendrite/userapi/storage/accounts" @@ -62,24 +63,26 @@ import ( // should only be used during start up. // Must be closed when shutting down. type BaseDendrite struct { - componentName string - tracerCloser io.Closer - - // PublicAPIMux should be used to register new public matrix api endpoints - PublicAPIMux *mux.Router - InternalAPIMux *mux.Router - BaseMux *mux.Router // base router which created public/internal subrouters - UseHTTPAPIs bool - httpClient *http.Client - Cfg *config.Dendrite - Caches *caching.Caches - KafkaConsumer sarama.Consumer - KafkaProducer sarama.SyncProducer + componentName string + tracerCloser io.Closer + PublicClientAPIMux *mux.Router + PublicFederationAPIMux *mux.Router + PublicKeyAPIMux *mux.Router + PublicMediaAPIMux *mux.Router + InternalAPIMux *mux.Router + UseHTTPAPIs bool + httpClient *http.Client + Cfg *config.Dendrite + Caches *caching.Caches + KafkaConsumer sarama.Consumer + KafkaProducer sarama.SyncProducer } const HTTPServerTimeout = time.Minute * 5 const HTTPClientTimeout = time.Second * 30 +const NoExternalListener = "" + // NewBaseDendrite creates a new instance to be used by a component. // The componentName is used for logging purposes, and should be a friendly name // of the compontent running, e.g. "SyncAPI" @@ -134,20 +137,20 @@ func NewBaseDendrite(cfg *config.Dendrite, componentName string, useHTTPAPIs boo // We need to be careful with media APIs if they read from a filesystem to make sure they // are not inadvertently reading paths without cleaning, else this could introduce a // directory traversal attack e.g /../../../etc/passwd - httpmux := mux.NewRouter().SkipClean(true) - return &BaseDendrite{ - componentName: componentName, - UseHTTPAPIs: useHTTPAPIs, - tracerCloser: closer, - Cfg: cfg, - Caches: cache, - BaseMux: httpmux, - PublicAPIMux: httpmux.PathPrefix(httputil.PublicPathPrefix).Subrouter().UseEncodedPath(), - InternalAPIMux: httpmux.PathPrefix(httputil.InternalPathPrefix).Subrouter().UseEncodedPath(), - httpClient: &client, - KafkaConsumer: kafkaConsumer, - KafkaProducer: kafkaProducer, + componentName: componentName, + UseHTTPAPIs: useHTTPAPIs, + tracerCloser: closer, + Cfg: cfg, + Caches: cache, + PublicClientAPIMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicClientPathPrefix).Subrouter().UseEncodedPath(), + PublicFederationAPIMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicFederationPathPrefix).Subrouter().UseEncodedPath(), + PublicKeyAPIMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicKeyPathPrefix).Subrouter().UseEncodedPath(), + PublicMediaAPIMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.PublicMediaPathPrefix).Subrouter().UseEncodedPath(), + InternalAPIMux: mux.NewRouter().SkipClean(true).PathPrefix(httputil.InternalPathPrefix).Subrouter().UseEncodedPath(), + httpClient: &client, + KafkaConsumer: kafkaConsumer, + KafkaProducer: kafkaProducer, } } @@ -266,37 +269,74 @@ func (b *BaseDendrite) CreateFederationClient() *gomatrixserverlib.FederationCli // SetupAndServeHTTP sets up the HTTP server to serve endpoints registered on // ApiMux under /api/ and adds a prometheus handler under /metrics. -func (b *BaseDendrite) SetupAndServeHTTP(bindaddr string, listenaddr string) { - // If a separate bind address is defined, listen on that. Otherwise use - // the listen address - var addr string - if bindaddr != "" { - addr = bindaddr - } else { - addr = listenaddr - } +// nolint:gocyclo +func (b *BaseDendrite) SetupAndServeHTTP( + internalHTTPAddr, externalHTTPAddr config.HTTPAddress, + certFile, keyFile *string, +) { + internalAddr, _ := internalHTTPAddr.Address() + externalAddr, _ := externalHTTPAddr.Address() - serv := http.Server{ - Addr: addr, + internalRouter := mux.NewRouter() + externalRouter := internalRouter + + internalServ := &http.Server{ + Addr: string(internalAddr), WriteTimeout: HTTPServerTimeout, + Handler: internalRouter, + } + externalServ := internalServ + + if externalAddr != "" && externalAddr != internalAddr { + externalRouter = mux.NewRouter() + externalServ = &http.Server{ + Addr: string(externalAddr), + WriteTimeout: HTTPServerTimeout, + Handler: externalRouter, + } } - httputil.SetupHTTPAPI( - b.BaseMux, - b.PublicAPIMux, - b.InternalAPIMux, - &b.Cfg.Global, - b.UseHTTPAPIs, - ) - serv.Handler = b.BaseMux - logrus.Infof("Starting %s server on %s", b.componentName, serv.Addr) - - err := serv.ListenAndServe() - if err != nil { - logrus.WithError(err).Fatal("failed to serve http") + internalRouter.PathPrefix(httputil.InternalPathPrefix).Handler(b.InternalAPIMux) + if b.Cfg.Global.Metrics.Enabled { + internalRouter.Handle("/metrics", httputil.WrapHandlerInBasicAuth(promhttp.Handler(), b.Cfg.Global.Metrics.BasicAuth)) } - logrus.Infof("Stopped %s server on %s", b.componentName, serv.Addr) + externalRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(b.PublicClientAPIMux) + externalRouter.PathPrefix(httputil.PublicKeyPathPrefix).Handler(b.PublicKeyAPIMux) + externalRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(b.PublicFederationAPIMux) + externalRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(b.PublicMediaAPIMux) + + go func() { + logrus.Infof("Starting %s listener on %s", b.componentName, externalServ.Addr) + if certFile != nil && keyFile != nil { + if err := externalServ.ListenAndServeTLS(*certFile, *keyFile); err != nil { + logrus.WithError(err).Fatal("failed to serve HTTPS") + } + } else { + if err := externalServ.ListenAndServe(); err != nil { + logrus.WithError(err).Fatal("failed to serve HTTP") + } + } + logrus.Infof("Stopped %s listener on %s", b.componentName, externalServ.Addr) + }() + + if internalAddr != "" && internalAddr != externalAddr { + go func() { + logrus.Infof("Starting %s listener on %s", b.componentName, internalServ.Addr) + if certFile != nil && keyFile != nil { + if err := internalServ.ListenAndServeTLS(*certFile, *keyFile); err != nil { + logrus.WithError(err).Fatal("failed to serve HTTPS") + } + } else { + if err := internalServ.ListenAndServe(); err != nil { + logrus.WithError(err).Fatal("failed to serve HTTP") + } + } + logrus.Infof("Stopped %s listener on %s", b.componentName, internalServ.Addr) + }() + } + + select {} } // setupKafka creates kafka consumer/producer pair from the config. diff --git a/internal/setup/monolith.go b/internal/setup/monolith.go index 92bbca72..5e6c8fcf 100644 --- a/internal/setup/monolith.go +++ b/internal/setup/monolith.go @@ -63,21 +63,21 @@ type Monolith struct { } // AddAllPublicRoutes attaches all public paths to the given router -func (m *Monolith) AddAllPublicRoutes(publicMux *mux.Router) { +func (m *Monolith) AddAllPublicRoutes(csMux, ssMux, keyMux, mediaMux *mux.Router) { clientapi.AddPublicRoutes( - publicMux, &m.Config.ClientAPI, m.KafkaProducer, m.DeviceDB, m.AccountDB, + csMux, &m.Config.ClientAPI, m.KafkaProducer, m.DeviceDB, m.AccountDB, m.FedClient, m.RoomserverAPI, m.EDUInternalAPI, m.AppserviceAPI, m.StateAPI, transactions.New(), m.FederationSenderAPI, m.UserAPI, m.KeyAPI, m.ExtPublicRoomsProvider, ) federationapi.AddPublicRoutes( - publicMux, &m.Config.FederationAPI, m.UserAPI, m.FedClient, + ssMux, keyMux, &m.Config.FederationAPI, m.UserAPI, m.FedClient, m.KeyRing, m.RoomserverAPI, m.FederationSenderAPI, m.EDUInternalAPI, m.StateAPI, m.KeyAPI, ) - mediaapi.AddPublicRoutes(publicMux, &m.Config.MediaAPI, m.UserAPI, m.Client) + mediaapi.AddPublicRoutes(mediaMux, &m.Config.MediaAPI, m.UserAPI, m.Client) syncapi.AddPublicRoutes( - publicMux, m.KafkaConsumer, m.UserAPI, m.RoomserverAPI, + csMux, m.KafkaConsumer, m.UserAPI, m.RoomserverAPI, m.KeyAPI, m.StateAPI, m.FedClient, &m.Config.SyncAPI, ) } diff --git a/internal/test/config.go b/internal/test/config.go index 43a5d1ff..e2106de4 100644 --- a/internal/test/config.go +++ b/internal/test/config.go @@ -52,8 +52,8 @@ func MakeConfig(configDir, kafkaURI, database, host string, startPort int) (*con cfg.Defaults() port := startPort - assignAddress := func() config.Address { - result := config.Address(fmt.Sprintf("%s:%d", host, port)) + assignAddress := func() config.HTTPAddress { + result := config.HTTPAddress(fmt.Sprintf("http://%s:%d", host, port)) port++ return result } @@ -97,29 +97,29 @@ func MakeConfig(configDir, kafkaURI, database, host string, startPort int) (*con cfg.UserAPI.AccountDatabase.ConnectionString = config.DataSource(database) cfg.UserAPI.DeviceDatabase.ConnectionString = config.DataSource(database) - cfg.AppServiceAPI.Listen = assignAddress() - cfg.CurrentStateServer.Listen = assignAddress() - cfg.EDUServer.Listen = assignAddress() - cfg.FederationAPI.Listen = assignAddress() - cfg.FederationSender.Listen = assignAddress() - cfg.KeyServer.Listen = assignAddress() - cfg.MediaAPI.Listen = assignAddress() - cfg.RoomServer.Listen = assignAddress() - cfg.ServerKeyAPI.Listen = assignAddress() - cfg.SyncAPI.Listen = assignAddress() - cfg.UserAPI.Listen = assignAddress() + cfg.AppServiceAPI.InternalAPI.Listen = assignAddress() + cfg.CurrentStateServer.InternalAPI.Listen = assignAddress() + cfg.EDUServer.InternalAPI.Listen = assignAddress() + cfg.FederationAPI.InternalAPI.Listen = assignAddress() + cfg.FederationSender.InternalAPI.Listen = assignAddress() + cfg.KeyServer.InternalAPI.Listen = assignAddress() + cfg.MediaAPI.InternalAPI.Listen = assignAddress() + cfg.RoomServer.InternalAPI.Listen = assignAddress() + cfg.ServerKeyAPI.InternalAPI.Listen = assignAddress() + cfg.SyncAPI.InternalAPI.Listen = assignAddress() + cfg.UserAPI.InternalAPI.Listen = assignAddress() - cfg.AppServiceAPI.Bind = cfg.AppServiceAPI.Listen - cfg.CurrentStateServer.Bind = cfg.CurrentStateServer.Listen - cfg.EDUServer.Bind = cfg.EDUServer.Listen - cfg.FederationAPI.Bind = cfg.FederationAPI.Listen - cfg.FederationSender.Bind = cfg.FederationSender.Listen - cfg.KeyServer.Bind = cfg.KeyServer.Listen - cfg.MediaAPI.Bind = cfg.MediaAPI.Listen - cfg.RoomServer.Bind = cfg.RoomServer.Listen - cfg.ServerKeyAPI.Bind = cfg.ServerKeyAPI.Listen - cfg.SyncAPI.Bind = cfg.SyncAPI.Listen - cfg.UserAPI.Bind = cfg.UserAPI.Listen + cfg.AppServiceAPI.InternalAPI.Connect = cfg.AppServiceAPI.InternalAPI.Listen + cfg.CurrentStateServer.InternalAPI.Connect = cfg.CurrentStateServer.InternalAPI.Listen + cfg.EDUServer.InternalAPI.Connect = cfg.EDUServer.InternalAPI.Listen + cfg.FederationAPI.InternalAPI.Connect = cfg.FederationAPI.InternalAPI.Listen + cfg.FederationSender.InternalAPI.Connect = cfg.FederationSender.InternalAPI.Listen + cfg.KeyServer.InternalAPI.Connect = cfg.KeyServer.InternalAPI.Listen + cfg.MediaAPI.InternalAPI.Connect = cfg.MediaAPI.InternalAPI.Listen + cfg.RoomServer.InternalAPI.Connect = cfg.RoomServer.InternalAPI.Listen + cfg.ServerKeyAPI.InternalAPI.Connect = cfg.ServerKeyAPI.InternalAPI.Listen + cfg.SyncAPI.InternalAPI.Connect = cfg.SyncAPI.InternalAPI.Listen + cfg.UserAPI.InternalAPI.Connect = cfg.UserAPI.InternalAPI.Listen return &cfg, port, nil } diff --git a/internal/test/server.go b/internal/test/server.go index 57df21db..ed4e7e28 100644 --- a/internal/test/server.go +++ b/internal/test/server.go @@ -96,9 +96,9 @@ func InitDatabase(postgresDatabase, postgresContainerName string, databases []st func StartProxy(bindAddr string, cfg *config.Dendrite) (*exec.Cmd, chan error) { proxyArgs := []string{ "--bind-address", bindAddr, - "--sync-api-server-url", "http://" + string(cfg.SyncAPI.Listen), - "--client-api-server-url", "http://" + string(cfg.ClientAPI.Listen), - "--media-api-server-url", "http://" + string(cfg.MediaAPI.Listen), + "--sync-api-server-url", "http://" + string(cfg.SyncAPI.InternalAPI.Connect), + "--client-api-server-url", "http://" + string(cfg.ClientAPI.InternalAPI.Connect), + "--media-api-server-url", "http://" + string(cfg.MediaAPI.InternalAPI.Connect), "--tls-cert", "server.crt", "--tls-key", "server.key", } diff --git a/mediaapi/routing/routing.go b/mediaapi/routing/routing.go index ee5f28f9..75f195cd 100644 --- a/mediaapi/routing/routing.go +++ b/mediaapi/routing/routing.go @@ -32,9 +32,6 @@ import ( "github.com/prometheus/client_golang/prometheus/promhttp" ) -const pathPrefixR0 = "/media/r0" -const pathPrefixV1 = "/media/v1" // TODO: remove when synapse is fixed - // Setup registers the media API HTTP handlers // // Due to Setup being used to call many other functions, a gocyclo nolint is @@ -47,8 +44,8 @@ func Setup( userAPI userapi.UserInternalAPI, client *gomatrixserverlib.Client, ) { - r0mux := publicAPIMux.PathPrefix(pathPrefixR0).Subrouter() - v1mux := publicAPIMux.PathPrefix(pathPrefixV1).Subrouter() + r0mux := publicAPIMux.PathPrefix("/r0").Subrouter() + v1mux := publicAPIMux.PathPrefix("/v1").Subrouter() activeThumbnailGeneration := &types.ActiveThumbnailGeneration{ PathToResult: map[string]*types.ThumbnailGenerationResult{}, diff --git a/syncapi/routing/routing.go b/syncapi/routing/routing.go index ec21c1b4..f42679c6 100644 --- a/syncapi/routing/routing.go +++ b/syncapi/routing/routing.go @@ -28,20 +28,18 @@ import ( "github.com/matrix-org/util" ) -const pathPrefixR0 = "/client/r0" - // Setup configures the given mux with sync-server listeners // // Due to Setup being used to call many other functions, a gocyclo nolint is // applied: // nolint: gocyclo func Setup( - publicAPIMux *mux.Router, srp *sync.RequestPool, syncDB storage.Database, + csMux *mux.Router, srp *sync.RequestPool, syncDB storage.Database, userAPI userapi.UserInternalAPI, federation *gomatrixserverlib.FederationClient, rsAPI api.RoomserverInternalAPI, cfg *config.SyncAPI, ) { - r0mux := publicAPIMux.PathPrefix(pathPrefixR0).Subrouter() + r0mux := csMux.PathPrefix("/r0").Subrouter() // TODO: Add AS support for all handlers below. r0mux.Handle("/sync", httputil.MakeAuthAPI("sync", userAPI, func(req *http.Request, device *userapi.Device) util.JSONResponse {