diff options
author | Till Faelligen <2353100+S7evinK@users.noreply.github.com> | 2024-11-14 13:42:51 +0100 |
---|---|---|
committer | Till Faelligen <2353100+S7evinK@users.noreply.github.com> | 2024-11-14 13:42:51 +0100 |
commit | 79b87c7a08045a5b5c676b97cedd49250bff2237 (patch) | |
tree | d0716b0d3bcb85be2a05534bf1cab0597136b168 /contrib/dendrite-demo-i2p/main_i2p.go | |
parent | 488009ca905be78c0cbd5364e879d61232b32868 (diff) | |
parent | 6cd1285ca0276bebd407110c37031bc4622f0b79 (diff) |
Diffstat (limited to 'contrib/dendrite-demo-i2p/main_i2p.go')
-rw-r--r-- | contrib/dendrite-demo-i2p/main_i2p.go | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/contrib/dendrite-demo-i2p/main_i2p.go b/contrib/dendrite-demo-i2p/main_i2p.go new file mode 100644 index 00000000..72fed656 --- /dev/null +++ b/contrib/dendrite-demo-i2p/main_i2p.go @@ -0,0 +1,233 @@ +// Copyright 2017 Vector Creations Ltd +// +// 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 main + +import ( + "bytes" + "context" + "crypto/tls" + "embed" + "net" + "net/http" + "net/url" + "strings" + "sync/atomic" + "text/template" + + "github.com/cretz/bine/tor" + "github.com/eyedeekay/goSam" + "github.com/eyedeekay/onramp" + sentryhttp "github.com/getsentry/sentry-go/http" + "github.com/gorilla/mux" + "github.com/kardianos/minwinsvc" + "github.com/matrix-org/dendrite/internal" + "github.com/matrix-org/dendrite/internal/httputil" + "github.com/matrix-org/dendrite/setup/process" + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/sirupsen/logrus" + + basepkg "github.com/matrix-org/dendrite/setup/base" + "github.com/matrix-org/dendrite/setup/config" +) + +func client() (*goSam.Client, error) { + if skip { + return nil, nil + } + return goSam.NewClient(*samAddr) +} + +var sam, samError = client() + +func start() (*tor.Tor, error) { + if skip { + return nil, nil + } + return tor.Start(context.Background(), nil) +} + +func dialer() (*tor.Dialer, error) { + if skip { + return nil, nil + } + return t.Dialer(context.TODO(), nil) +} + +var ( + t, terr = start() + tdialer, tderr = dialer() +) + +// Dial a network connection to an I2P server or a unix socket. Use Tor, or Fail for clearnet addresses. +func DialContext(ctx context.Context, network, addr string) (net.Conn, error) { + if samError != nil { + return nil, samError + } + if network == "unix" { + return net.Dial(network, addr) + } + + // convert the addr to a full URL + url, err := url.Parse(addr) + if err != nil { + return nil, err + } + if strings.HasSuffix(url.Host, ".i2p") { + return sam.DialContext(ctx, network, addr) + } + if terr != nil { + return nil, terr + } + if (tderr != nil) || (tdialer == nil) { + return nil, tderr + } + return tdialer.DialContext(ctx, network, addr) +} + +//go:embed static/*.gotmpl +var staticContent embed.FS + +// SetupAndServeHTTPS sets up the HTTPS server to serve client & federation APIs +// and adds a prometheus handler under /_dendrite/metrics. +func SetupAndServeHTTPS( + processContext *process.ProcessContext, + cfg *config.Dendrite, + routers httputil.Routers, +) { + // create a transport that uses SAM to dial TCP Connections + httpClient := &http.Client{ + Transport: &http.Transport{ + DialContext: DialContext, + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + }, + } + + http.DefaultClient = httpClient + + garlic, err := onramp.NewGarlic("dendrite", *samAddr, onramp.OPT_HUGE) + if err != nil { + logrus.WithError(err).Fatal("failed to create garlic") + } + defer garlic.Close() // nolint: errcheck + listener, err := garlic.ListenTLS() + if err != nil { + logrus.WithError(err).Fatal("failed to serve HTTPS") + } + defer listener.Close() // nolint: errcheck + + externalHTTPSAddr := config.ServerAddress{} + https, err := config.HTTPAddress("https://" + listener.Addr().String()) + if err != nil { + logrus.WithError(err).Fatalf("Failed to parse http address") + } + externalHTTPSAddr = https + + externalRouter := mux.NewRouter().SkipClean(true).UseEncodedPath() + + externalServ := &http.Server{ + Addr: externalHTTPSAddr.Address, + WriteTimeout: basepkg.HTTPServerTimeout, + Handler: externalRouter, + BaseContext: func(_ net.Listener) context.Context { + return processContext.Context() + }, + } + + // Redirect for Landing Page + externalRouter.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + http.Redirect(w, r, httputil.PublicStaticPath, http.StatusFound) + }) + + if cfg.Global.Metrics.Enabled { + externalRouter.Handle("/metrics", httputil.WrapHandlerInBasicAuth(promhttp.Handler(), cfg.Global.Metrics.BasicAuth)) + } + + basepkg.ConfigureAdminEndpoints(processContext, routers) + + // Parse and execute the landing page template + tmpl := template.Must(template.ParseFS(staticContent, "static/*.gotmpl")) + landingPage := &bytes.Buffer{} + if err := tmpl.ExecuteTemplate(landingPage, "index.gotmpl", map[string]string{ + "Version": internal.VersionString(), + }); err != nil { + logrus.WithError(err).Fatal("failed to execute landing page template") + } + + routers.Static.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write(landingPage.Bytes()) + }) + + var clientHandler http.Handler + clientHandler = routers.Client + if cfg.Global.Sentry.Enabled { + sentryHandler := sentryhttp.New(sentryhttp.Options{ + Repanic: true, + }) + clientHandler = sentryHandler.Handle(routers.Client) + } + var federationHandler http.Handler + federationHandler = routers.Federation + if cfg.Global.Sentry.Enabled { + sentryHandler := sentryhttp.New(sentryhttp.Options{ + Repanic: true, + }) + federationHandler = sentryHandler.Handle(routers.Federation) + } + externalRouter.PathPrefix(httputil.DendriteAdminPathPrefix).Handler(routers.DendriteAdmin) + externalRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(clientHandler) + if !cfg.Global.DisableFederation { + externalRouter.PathPrefix(httputil.PublicKeyPathPrefix).Handler(routers.Keys) + externalRouter.PathPrefix(httputil.PublicFederationPathPrefix).Handler(federationHandler) + } + externalRouter.PathPrefix(httputil.SynapseAdminPathPrefix).Handler(routers.SynapseAdmin) + externalRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(routers.Media) + externalRouter.PathPrefix(httputil.PublicWellKnownPrefix).Handler(routers.WellKnown) + externalRouter.PathPrefix(httputil.PublicStaticPath).Handler(routers.Static) + + externalRouter.NotFoundHandler = httputil.NotFoundCORSHandler + externalRouter.MethodNotAllowedHandler = httputil.NotAllowedHandler + + if externalHTTPSAddr.Enabled() { + go func() { + var externalShutdown atomic.Bool // RegisterOnShutdown can be called more than once + logrus.Infof("Starting external listener on https://%s", externalServ.Addr) + processContext.ComponentStarted() + externalServ.RegisterOnShutdown(func() { + if externalShutdown.CompareAndSwap(false, true) { + processContext.ComponentFinished() + logrus.Infof("Stopped external HTTPS listener") + } + }) + addr := listener.Addr() + externalServ.Addr = addr.String() + if err := externalServ.Serve(listener); err != nil { + if err != http.ErrServerClosed { + logrus.WithError(err).Fatal("failed to serve HTTPS") + } + } + + logrus.Infof("Stopped external listener on %s", externalServ.Addr) + }() + } + + minwinsvc.SetOnExit(processContext.ShutdownDendrite) + <-processContext.WaitForShutdown() + + logrus.Infof("Stopping HTTPS listeners") + _ = externalServ.Shutdown(context.Background()) + logrus.Infof("Stopped HTTPS listeners") +} |