// Copyright 2023 wanderer // SPDX-License-Identifier: AGPL-3.0-only package app import ( "encoding/hex" "net/http" "github.com/gorilla/sessions" "github.com/labstack/echo-contrib/session" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" "golang.org/x/time/rate" ) // SetServerSettings sets up the main Echo instance and panics on err. func (a *App) SetServerSettings() { e := a.E() e.HideBanner = true e.Use(middleware.Logger()) // e.Use(middleware.LoggerWithConfig( // middleware.LoggerConfig{ // Format: `{"time":"${time_rfc3339_nano}","id":"${id}","remote_ip":"${remote_ip}",` + // `"host":"${host}","method":"${method}","uri":"${uri}","user_agent":"${user_agent}",` + // `"status":${status},"error":"${error}","latency":${latency},"latency_human":"${latency_human}"` + // `,"bytes_in":${bytes_in},"bytes_out":${bytes_out}}` + "\n", // CustomTimeFormat: "2006-01-02 15:04:05.00000", // }, // )) // logger := zerolog.New(os.Stdout) // e.Use(middleware.RequestLoggerWithConfig(middleware.RequestLoggerConfig{ // LogURI: true, // LogStatus: true, // LogValuesFunc: func(c echo.Context, v middleware.RequestLoggerValues) error { // logger.Info(). // Str("URI", v.URI). // Int("status", v.Status). // Msg("request") // // return nil // }, // })) // TODO: make this configurable. e.Server.WriteTimeout = a.setting.DefaultServerWriteTimeout() e.Server.ReadHeaderTimeout = a.setting.DefaultServerReadHeaderTimeout() if a.setting.HTTPRateLimitEnabled() { limit := rate.Limit(a.setting.HTTPRateLimit()) e.Use(middleware.RateLimiter( middleware.NewRateLimiterMemoryStore(limit), )) } // TODO: add check for prometheus config setting. // if true { // // import "github.com/labstack/echo-contrib/prometheus" // p := prometheus.NewPrometheus("echo", nil) // p.Use(e) // } e.Use(middleware.Recover()) var ( store *sessions.CookieStore authSecret []byte encrSecret []byte ) if a.setting.SessionAuthIsHex() { b, err := hex.DecodeString(a.setting.SessionCookieAuthSecret()) if err != nil { panic(err) } authSecret = b } if a.setting.SessionEncrIsHex() { b, err := hex.DecodeString(a.setting.SessionCookieEncrSecret()) if err != nil { panic(err) } encrSecret = b } switch { case authSecret != nil && encrSecret != nil: store = sessions.NewCookieStore( authSecret, encrSecret, ) case authSecret != nil && encrSecret == nil: store = sessions.NewCookieStore( authSecret, []byte(a.setting.SessionCookieEncrSecret()), ) case authSecret == nil && encrSecret != nil: store = sessions.NewCookieStore( []byte(a.setting.SessionCookieAuthSecret()), encrSecret, ) case authSecret == nil && encrSecret == nil: store = sessions.NewCookieStore( []byte(a.setting.SessionCookieAuthSecret()), []byte(a.setting.SessionCookieEncrSecret()), ) } store.Options.Domain = a.setting.HTTPDomain() store.Options.HttpOnly = true store.Options.SameSite = http.SameSiteStrictMode store.Options.Secure = a.setting.HTTPSecure() store.Options.MaxAge = a.setting.SessionMaxAge() e.Use(session.Middleware(store)) csrfCookieName := "pcmt_csrf" if a.setting.HTTPSecure() { // https://www.sjoerdlangkemper.nl/2017/02/09/cookie-prefixes/ // https://scotthelme.co.uk/tough-cookies/ // https://check-your-website.server-daten.de/prefix-cookies.html csrfCookieName = "__Host-" + csrfCookieName } e.Use(middleware.CSRFWithConfig(middleware.CSRFConfig{ TokenLookup: "cookie:" + csrfCookieName + ",form:csrf,header:" + echo.HeaderXCSRFToken, CookieName: csrfCookieName, ContextKey: "csrf", // CookieDomain: "localhost", CookieSecure: a.setting.HTTPSecure(), CookieHTTPOnly: true, CookieSameSite: http.SameSiteStrictMode, CookieMaxAge: a.setting.SessionMaxAge(), }), ) e.Use(middleware.Secure()) if a.setting.HTTPGzipEnabled() { e.Use(middleware.GzipWithConfig(middleware.GzipConfig{ Level: a.setting.HTTPGzipLevel(), })) } }