2023-05-20 20:15:57 +02:00
|
|
|
// Copyright 2023 wanderer <a_mirre at utb dot cz>
|
|
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
|
2023-03-22 22:13:23 +01:00
|
|
|
package app
|
|
|
|
|
|
|
|
import (
|
2023-05-21 12:44:18 +02:00
|
|
|
"encoding/hex"
|
2023-04-13 00:07:08 +02:00
|
|
|
"net/http"
|
2023-09-04 14:01:42 +02:00
|
|
|
"regexp"
|
2023-04-13 00:07:08 +02:00
|
|
|
|
2023-05-01 22:48:11 +02:00
|
|
|
"github.com/gorilla/sessions"
|
|
|
|
"github.com/labstack/echo-contrib/session"
|
2023-08-03 14:49:21 +02:00
|
|
|
"github.com/labstack/echo/v4"
|
2023-03-22 22:13:23 +01:00
|
|
|
"github.com/labstack/echo/v4/middleware"
|
2023-09-04 14:01:42 +02:00
|
|
|
"golang.org/x/exp/slog"
|
2023-05-21 12:44:18 +02:00
|
|
|
"golang.org/x/time/rate"
|
2023-03-22 22:13:23 +01:00
|
|
|
)
|
|
|
|
|
2023-08-11 23:18:54 +02:00
|
|
|
// SetServerSettings sets up the main Echo instance and panics on err.
|
|
|
|
func (a *App) SetServerSettings() {
|
2023-03-22 23:04:57 +01:00
|
|
|
e := a.E()
|
|
|
|
|
2023-03-22 22:13:23 +01:00
|
|
|
e.HideBanner = true
|
|
|
|
|
2023-09-04 14:01:42 +02:00
|
|
|
if a.setting.DefaultLoggerSkipAssets() {
|
|
|
|
re := regexp.MustCompile("^/(assets|static)(.*)|favicon.ico")
|
|
|
|
lC := middleware.DefaultLoggerConfig
|
|
|
|
|
|
|
|
lC.Skipper = func(c echo.Context) bool {
|
|
|
|
r := c.Request().URL.Path
|
|
|
|
|
|
|
|
slog.Debug("logger skipper", "path", r)
|
|
|
|
|
|
|
|
return re.MatchString(r)
|
|
|
|
}
|
|
|
|
e.Use(middleware.LoggerWithConfig(lC))
|
|
|
|
} else {
|
|
|
|
e.Use(middleware.Logger())
|
|
|
|
}
|
|
|
|
|
2023-04-13 00:07:08 +02:00
|
|
|
// 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
|
|
|
|
// },
|
|
|
|
// }))
|
|
|
|
|
2023-08-03 14:40:04 +02:00
|
|
|
// TODO: make this configurable.
|
2023-08-05 14:25:34 +02:00
|
|
|
e.Server.WriteTimeout = a.setting.DefaultServerWriteTimeout()
|
|
|
|
e.Server.ReadHeaderTimeout = a.setting.DefaultServerReadHeaderTimeout()
|
2023-08-03 14:40:04 +02:00
|
|
|
|
2023-05-21 12:44:18 +02:00
|
|
|
if a.setting.HTTPRateLimitEnabled() {
|
|
|
|
limit := rate.Limit(a.setting.HTTPRateLimit())
|
|
|
|
|
|
|
|
e.Use(middleware.RateLimiter(
|
|
|
|
middleware.NewRateLimiterMemoryStore(limit),
|
|
|
|
))
|
|
|
|
}
|
2023-05-10 17:48:02 +02:00
|
|
|
|
2023-05-17 20:40:24 +02:00
|
|
|
// TODO: add check for prometheus config setting.
|
|
|
|
// if true {
|
|
|
|
// // import "github.com/labstack/echo-contrib/prometheus"
|
|
|
|
// p := prometheus.NewPrometheus("echo", nil)
|
|
|
|
// p.Use(e)
|
|
|
|
// }
|
|
|
|
|
2023-03-22 22:13:23 +01:00
|
|
|
e.Use(middleware.Recover())
|
2023-04-13 00:07:08 +02:00
|
|
|
|
2023-05-21 12:44:18 +02:00
|
|
|
var (
|
|
|
|
store *sessions.CookieStore
|
|
|
|
authSecret []byte
|
|
|
|
encrSecret []byte
|
|
|
|
)
|
|
|
|
|
2023-08-04 18:13:23 +02:00
|
|
|
if a.setting.SessionAuthIsHex() {
|
2023-05-21 12:44:18 +02:00
|
|
|
b, err := hex.DecodeString(a.setting.SessionCookieAuthSecret())
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
authSecret = b
|
|
|
|
}
|
|
|
|
|
2023-08-04 18:13:23 +02:00
|
|
|
if a.setting.SessionEncrIsHex() {
|
2023-05-21 12:44:18 +02:00
|
|
|
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()),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2023-09-04 21:02:06 +02:00
|
|
|
store.Options.Path = "/"
|
2023-05-21 12:44:18 +02:00
|
|
|
store.Options.Domain = a.setting.HTTPDomain()
|
|
|
|
store.Options.HttpOnly = true
|
|
|
|
store.Options.SameSite = http.SameSiteStrictMode
|
|
|
|
store.Options.Secure = a.setting.HTTPSecure()
|
2023-08-04 18:28:56 +02:00
|
|
|
store.Options.MaxAge = a.setting.SessionMaxAge()
|
2023-05-21 12:44:18 +02:00
|
|
|
|
2023-09-04 21:02:06 +02:00
|
|
|
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
|
|
|
|
store.Options.Domain = "__Host-" + store.Options.Domain
|
|
|
|
}
|
|
|
|
|
2023-05-21 12:44:18 +02:00
|
|
|
e.Use(session.Middleware(store))
|
2023-05-01 22:48:11 +02:00
|
|
|
|
2023-08-13 16:44:40 +02:00
|
|
|
e.Use(middleware.Secure())
|
|
|
|
|
|
|
|
if a.setting.HTTPGzipEnabled() {
|
|
|
|
e.Use(middleware.GzipWithConfig(middleware.GzipConfig{
|
|
|
|
Level: a.setting.HTTPGzipLevel(),
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *App) csrfConfig() echo.MiddlewareFunc {
|
2023-08-03 14:49:21 +02:00
|
|
|
csrfCookieName := "pcmt_csrf"
|
|
|
|
if a.setting.HTTPSecure() {
|
2023-08-04 17:26:51 +02:00
|
|
|
// 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
|
2023-08-03 14:49:21 +02:00
|
|
|
}
|
|
|
|
|
2023-08-13 16:44:40 +02:00
|
|
|
return middleware.CSRFWithConfig(middleware.CSRFConfig{
|
2023-08-03 14:49:21 +02:00
|
|
|
TokenLookup: "cookie:" + csrfCookieName +
|
|
|
|
",form:csrf,header:" + echo.HeaderXCSRFToken,
|
|
|
|
CookieName: csrfCookieName,
|
|
|
|
ContextKey: "csrf",
|
|
|
|
// CookieDomain: "localhost",
|
|
|
|
CookieSecure: a.setting.HTTPSecure(),
|
2023-04-13 00:07:08 +02:00
|
|
|
CookieHTTPOnly: true,
|
|
|
|
CookieSameSite: http.SameSiteStrictMode,
|
2023-08-04 18:28:56 +02:00
|
|
|
CookieMaxAge: a.setting.SessionMaxAge(),
|
2023-09-04 21:02:06 +02:00
|
|
|
CookiePath: "/",
|
2023-08-13 16:44:40 +02:00
|
|
|
},
|
2023-04-13 00:07:08 +02:00
|
|
|
)
|
2023-03-22 22:13:23 +01:00
|
|
|
}
|