aboutsummaryrefslogtreecommitdiff
path: root/internal/setup/base.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/setup/base.go')
-rw-r--r--internal/setup/base.go359
1 files changed, 0 insertions, 359 deletions
diff --git a/internal/setup/base.go b/internal/setup/base.go
deleted file mode 100644
index 1820778a..00000000
--- a/internal/setup/base.go
+++ /dev/null
@@ -1,359 +0,0 @@
-// Copyright 2020 The Matrix.org Foundation C.I.C.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package setup
-
-import (
- "crypto/tls"
- "fmt"
- "io"
- "net"
- "net/http"
- "net/url"
- "time"
-
- "github.com/matrix-org/dendrite/internal/caching"
- "github.com/matrix-org/dendrite/internal/httputil"
- "github.com/matrix-org/gomatrixserverlib"
- "github.com/prometheus/client_golang/prometheus/promhttp"
- "golang.org/x/net/http2"
- "golang.org/x/net/http2/h2c"
-
- "github.com/matrix-org/dendrite/internal"
- "github.com/matrix-org/dendrite/userapi/storage/accounts"
-
- "github.com/gorilla/mux"
-
- appserviceAPI "github.com/matrix-org/dendrite/appservice/api"
- asinthttp "github.com/matrix-org/dendrite/appservice/inthttp"
- eduServerAPI "github.com/matrix-org/dendrite/eduserver/api"
- eduinthttp "github.com/matrix-org/dendrite/eduserver/inthttp"
- federationSenderAPI "github.com/matrix-org/dendrite/federationsender/api"
- fsinthttp "github.com/matrix-org/dendrite/federationsender/inthttp"
- "github.com/matrix-org/dendrite/internal/config"
- keyserverAPI "github.com/matrix-org/dendrite/keyserver/api"
- keyinthttp "github.com/matrix-org/dendrite/keyserver/inthttp"
- roomserverAPI "github.com/matrix-org/dendrite/roomserver/api"
- rsinthttp "github.com/matrix-org/dendrite/roomserver/inthttp"
- skapi "github.com/matrix-org/dendrite/signingkeyserver/api"
- skinthttp "github.com/matrix-org/dendrite/signingkeyserver/inthttp"
- userapi "github.com/matrix-org/dendrite/userapi/api"
- userapiinthttp "github.com/matrix-org/dendrite/userapi/inthttp"
- "github.com/sirupsen/logrus"
-
- _ "net/http/pprof"
-)
-
-// BaseDendrite is a base for creating new instances of dendrite. It parses
-// command line flags and config, and exposes methods for creating various
-// resources. All errors are handled by logging then exiting, so all methods
-// should only be used during start up.
-// Must be closed when shutting down.
-type BaseDendrite struct {
- componentName string
- tracerCloser io.Closer
- PublicClientAPIMux *mux.Router
- PublicFederationAPIMux *mux.Router
- PublicKeyAPIMux *mux.Router
- PublicMediaAPIMux *mux.Router
- InternalAPIMux *mux.Router
- UseHTTPAPIs bool
- apiHttpClient *http.Client
- 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 NoListener = ""
-
-// 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"
-func NewBaseDendrite(cfg *config.Dendrite, componentName string, useHTTPAPIs bool) *BaseDendrite {
- configErrors := &config.ConfigErrors{}
- cfg.Verify(configErrors, componentName == "Monolith") // TODO: better way?
- if len(*configErrors) > 0 {
- for _, err := range *configErrors {
- logrus.Errorf("Configuration error: %s", err)
- }
- logrus.Fatalf("Failed to start due to configuration errors")
- }
-
- internal.SetupStdLogging()
- internal.SetupHookLogging(cfg.Logging, componentName)
- internal.SetupPprof()
-
- logrus.Infof("Dendrite version %s", internal.VersionString())
-
- closer, err := cfg.SetupTracing("Dendrite" + componentName)
- if err != nil {
- logrus.WithError(err).Panicf("failed to start opentracing")
- }
-
- cache, err := caching.NewInMemoryLRUCache(true)
- if err != nil {
- logrus.WithError(err).Warnf("Failed to create cache")
- }
-
- apiClient := http.Client{
- Timeout: time.Minute * 10,
- Transport: &http2.Transport{
- AllowHTTP: true,
- DialTLS: func(network, addr string, _ *tls.Config) (net.Conn, error) {
- // Ordinarily HTTP/2 would expect TLS, but the remote listener is
- // H2C-enabled (HTTP/2 without encryption). Overriding the DialTLS
- // function with a plain Dial allows us to trick the HTTP client
- // into establishing a HTTP/2 connection without TLS.
- // TODO: Eventually we will want to look at authenticating and
- // encrypting these internal HTTP APIs, at which point we will have
- // to reconsider H2C and change all this anyway.
- return net.Dial(network, addr)
- },
- },
- }
- client := http.Client{Timeout: HTTPClientTimeout}
- if cfg.FederationSender.Proxy.Enabled {
- client.Transport = &http.Transport{Proxy: http.ProxyURL(&url.URL{
- Scheme: cfg.FederationSender.Proxy.Protocol,
- Host: fmt.Sprintf("%s:%d", cfg.FederationSender.Proxy.Host, cfg.FederationSender.Proxy.Port),
- })}
- }
-
- // Ideally we would only use SkipClean on routes which we know can allow '/' but due to
- // https://github.com/gorilla/mux/issues/460 we have to attach this at the top router.
- // When used in conjunction with UseEncodedPath() we get the behaviour we want when parsing
- // path parameters:
- // /foo/bar%2Fbaz == [foo, bar%2Fbaz] (from UseEncodedPath)
- // /foo/bar%2F%2Fbaz == [foo, bar%2F%2Fbaz] (from SkipClean)
- // In particular, rooms v3 event IDs are not urlsafe and can include '/' and because they
- // are randomly generated it results in flakey tests.
- // 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
- return &BaseDendrite{
- 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(),
- apiHttpClient: &apiClient,
- httpClient: &client,
- }
-}
-
-// Close implements io.Closer
-func (b *BaseDendrite) Close() error {
- return b.tracerCloser.Close()
-}
-
-// AppserviceHTTPClient returns the AppServiceQueryAPI for hitting the appservice component over HTTP.
-func (b *BaseDendrite) AppserviceHTTPClient() appserviceAPI.AppServiceQueryAPI {
- a, err := asinthttp.NewAppserviceClient(b.Cfg.AppServiceURL(), b.apiHttpClient)
- if err != nil {
- logrus.WithError(err).Panic("CreateHTTPAppServiceAPIs failed")
- }
- return a
-}
-
-// RoomserverHTTPClient returns RoomserverInternalAPI for hitting the roomserver over HTTP.
-func (b *BaseDendrite) RoomserverHTTPClient() roomserverAPI.RoomserverInternalAPI {
- rsAPI, err := rsinthttp.NewRoomserverClient(b.Cfg.RoomServerURL(), b.apiHttpClient, b.Caches)
- if err != nil {
- logrus.WithError(err).Panic("RoomserverHTTPClient failed", b.apiHttpClient)
- }
- return rsAPI
-}
-
-// UserAPIClient returns UserInternalAPI for hitting the userapi over HTTP.
-func (b *BaseDendrite) UserAPIClient() userapi.UserInternalAPI {
- userAPI, err := userapiinthttp.NewUserAPIClient(b.Cfg.UserAPIURL(), b.apiHttpClient)
- if err != nil {
- logrus.WithError(err).Panic("UserAPIClient failed", b.apiHttpClient)
- }
- return userAPI
-}
-
-// EDUServerClient returns EDUServerInputAPI for hitting the EDU server over HTTP
-func (b *BaseDendrite) EDUServerClient() eduServerAPI.EDUServerInputAPI {
- e, err := eduinthttp.NewEDUServerClient(b.Cfg.EDUServerURL(), b.apiHttpClient)
- if err != nil {
- logrus.WithError(err).Panic("EDUServerClient failed", b.apiHttpClient)
- }
- return e
-}
-
-// FederationSenderHTTPClient returns FederationSenderInternalAPI for hitting
-// the federation sender over HTTP
-func (b *BaseDendrite) FederationSenderHTTPClient() federationSenderAPI.FederationSenderInternalAPI {
- f, err := fsinthttp.NewFederationSenderClient(b.Cfg.FederationSenderURL(), b.apiHttpClient)
- if err != nil {
- logrus.WithError(err).Panic("FederationSenderHTTPClient failed", b.apiHttpClient)
- }
- return f
-}
-
-// SigningKeyServerHTTPClient returns SigningKeyServer for hitting the signing key server over HTTP
-func (b *BaseDendrite) SigningKeyServerHTTPClient() skapi.SigningKeyServerAPI {
- f, err := skinthttp.NewSigningKeyServerClient(
- b.Cfg.SigningKeyServerURL(),
- b.apiHttpClient,
- b.Caches,
- )
- if err != nil {
- logrus.WithError(err).Panic("SigningKeyServerHTTPClient failed", b.httpClient)
- }
- return f
-}
-
-// KeyServerHTTPClient returns KeyInternalAPI for hitting the key server over HTTP
-func (b *BaseDendrite) KeyServerHTTPClient() keyserverAPI.KeyInternalAPI {
- f, err := keyinthttp.NewKeyServerClient(b.Cfg.KeyServerURL(), b.apiHttpClient)
- if err != nil {
- logrus.WithError(err).Panic("KeyServerHTTPClient failed", b.apiHttpClient)
- }
- return f
-}
-
-// CreateAccountsDB creates a new instance of the accounts database. Should only
-// be called once per component.
-func (b *BaseDendrite) CreateAccountsDB() accounts.Database {
- db, err := accounts.NewDatabase(&b.Cfg.UserAPI.AccountDatabase, b.Cfg.Global.ServerName)
- if err != nil {
- logrus.WithError(err).Panicf("failed to connect to accounts db")
- }
-
- return db
-}
-
-// CreateClient creates a new client (normally used for media fetch requests).
-// Should only be called once per component.
-func (b *BaseDendrite) CreateClient() *gomatrixserverlib.Client {
- if b.Cfg.Global.DisableFederation {
- return gomatrixserverlib.NewClientWithTransport(noOpHTTPTransport)
- }
- client := gomatrixserverlib.NewClient(
- b.Cfg.FederationSender.DisableTLSValidation,
- )
- client.SetUserAgent(fmt.Sprintf("Dendrite/%s", internal.VersionString()))
- return client
-}
-
-// CreateFederationClient creates a new federation client. Should only be called
-// once per component.
-func (b *BaseDendrite) CreateFederationClient() *gomatrixserverlib.FederationClient {
- if b.Cfg.Global.DisableFederation {
- return gomatrixserverlib.NewFederationClientWithTransport(
- b.Cfg.Global.ServerName, b.Cfg.Global.KeyID, b.Cfg.Global.PrivateKey,
- b.Cfg.FederationSender.DisableTLSValidation, noOpHTTPTransport,
- )
- }
- client := gomatrixserverlib.NewFederationClientWithTimeout(
- b.Cfg.Global.ServerName, b.Cfg.Global.KeyID, b.Cfg.Global.PrivateKey,
- b.Cfg.FederationSender.DisableTLSValidation, time.Minute*5,
- )
- client.SetUserAgent(fmt.Sprintf("Dendrite/%s", internal.VersionString()))
- return client
-}
-
-// SetupAndServeHTTP sets up the HTTP server to serve endpoints registered on
-// ApiMux under /api/ and adds a prometheus handler under /metrics.
-// nolint:gocyclo
-func (b *BaseDendrite) SetupAndServeHTTP(
- internalHTTPAddr, externalHTTPAddr config.HTTPAddress,
- certFile, keyFile *string,
-) {
- internalAddr, _ := internalHTTPAddr.Address()
- externalAddr, _ := externalHTTPAddr.Address()
-
- externalRouter := mux.NewRouter().SkipClean(true).UseEncodedPath()
- internalRouter := externalRouter
-
- externalServ := &http.Server{
- Addr: string(externalAddr),
- WriteTimeout: HTTPServerTimeout,
- Handler: externalRouter,
- }
- internalServ := externalServ
-
- if internalAddr != NoListener && externalAddr != internalAddr {
- // H2C allows us to accept HTTP/2 connections without TLS
- // encryption. Since we don't currently require any form of
- // authentication or encryption on these internal HTTP APIs,
- // H2C gives us all of the advantages of HTTP/2 (such as
- // stream multiplexing and avoiding head-of-line blocking)
- // without enabling TLS.
- internalH2S := &http2.Server{}
- internalRouter = mux.NewRouter().SkipClean(true).UseEncodedPath()
- internalServ = &http.Server{
- Addr: string(internalAddr),
- Handler: h2c.NewHandler(internalRouter, internalH2S),
- }
- }
-
- 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))
- }
-
- externalRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(b.PublicClientAPIMux)
- if !b.Cfg.Global.DisableFederation {
- externalRouter.PathPrefix(httputil.PublicKeyPathPrefix).Handler(b.PublicKeyAPIMux)
- externalRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(b.PublicFederationAPIMux)
- }
- externalRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(b.PublicMediaAPIMux)
-
- if internalAddr != NoListener && internalAddr != externalAddr {
- go func() {
- logrus.Infof("Starting internal %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 internal %s listener on %s", b.componentName, internalServ.Addr)
- }()
- }
-
- if externalAddr != NoListener {
- go func() {
- logrus.Infof("Starting external %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 external %s listener on %s", b.componentName, externalServ.Addr)
- }()
- }
-
- select {}
-}