pcmt/app/server.go
surtur 96c0b53493
All checks were successful
continuous-integration/drone/push Build is passing
go,tmpl: implement+activate validator
also ad initial password change:
* switch the password field type to `password`
* add a field for repeated password
2023-09-08 22:56:17 +02:00

183 lines
4.7 KiB
Go

// Copyright 2023 wanderer <a_mirre at utb dot cz>
// SPDX-License-Identifier: AGPL-3.0-only
package app
import (
"encoding/hex"
"net/http"
"regexp"
"git.dotya.ml/mirre-mt/pcmt/modules/validation"
"github.com/gorilla/sessions"
"github.com/labstack/echo-contrib/session"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"golang.org/x/exp/slog"
"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
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())
}
// 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),
))
}
e.Validator = validation.New()
// 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.Path = "/"
// let the domain be set automatically based on where the app is running.
// 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))
e.Use(
middleware.SecureWithConfig(
middleware.SecureConfig{
ContentSecurityPolicy: a.setting.HTTPCSP(),
},
),
)
if a.setting.HTTPGzipEnabled() {
e.Use(middleware.GzipWithConfig(middleware.GzipConfig{
Level: a.setting.HTTPGzipLevel(),
}))
}
}
func (a *App) csrfConfig() echo.MiddlewareFunc {
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
}
return 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(),
CookiePath: "/",
},
)
}