156 lines
3.5 KiB
Go
156 lines
3.5 KiB
Go
package rest
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"log/slog"
|
||
|
|
"net/http"
|
||
|
|
"os"
|
||
|
|
"strconv"
|
||
|
|
"strings"
|
||
|
|
"time"
|
||
|
|
|
||
|
|
"goAuth/internal/env"
|
||
|
|
)
|
||
|
|
|
||
|
|
const (
|
||
|
|
// Binds to loopback by default so a local run is not exposed on the
|
||
|
|
// network. Override with the ADDR env var (use :8080 to listen on all
|
||
|
|
// interfaces, e.g. inside a container).
|
||
|
|
DefaultAddr = "localhost:8080"
|
||
|
|
DefaultDatabasePath = "gochat.db"
|
||
|
|
|
||
|
|
DefaultSessionCookie = "session"
|
||
|
|
DefaultCsrfCookie = "csrf"
|
||
|
|
|
||
|
|
DefaultShortSession = 24 * time.Hour
|
||
|
|
DefaultLongSession = 30 * 24 * time.Hour
|
||
|
|
DefaultTokenSize = 32
|
||
|
|
)
|
||
|
|
|
||
|
|
type Config struct {
|
||
|
|
Addr string
|
||
|
|
DatabasePath string
|
||
|
|
// PublicBaseURL is the externally reachable base URL of this service, used
|
||
|
|
// to build absolute links (e.g. the avatar URL embedded in Jitsi JWTs).
|
||
|
|
// Leave empty to fall back to the request's Host.
|
||
|
|
PublicBaseURL string
|
||
|
|
Jitsi JitsiConfig
|
||
|
|
Cors CorsConfig
|
||
|
|
Sessions SessionConfig
|
||
|
|
Cookies CookieConfig
|
||
|
|
}
|
||
|
|
|
||
|
|
type JitsiConfig struct {
|
||
|
|
Secret string
|
||
|
|
AppId string
|
||
|
|
AppName string
|
||
|
|
Domain string
|
||
|
|
}
|
||
|
|
|
||
|
|
type CorsConfig struct {
|
||
|
|
Origins []string
|
||
|
|
Methods []string
|
||
|
|
Headers []string
|
||
|
|
}
|
||
|
|
|
||
|
|
type SessionConfig struct {
|
||
|
|
ShortDuration time.Duration
|
||
|
|
LongDuration time.Duration
|
||
|
|
TokenSize int
|
||
|
|
}
|
||
|
|
|
||
|
|
type CookieConfig struct {
|
||
|
|
SessionName string
|
||
|
|
CsrfName string
|
||
|
|
Secure bool
|
||
|
|
}
|
||
|
|
|
||
|
|
func DefaultConfig() Config {
|
||
|
|
return Config{
|
||
|
|
Addr: DefaultAddr,
|
||
|
|
DatabasePath: DefaultDatabasePath,
|
||
|
|
Jitsi: JitsiConfig{
|
||
|
|
Domain: "meet.jit.si",
|
||
|
|
},
|
||
|
|
Cors: CorsConfig{
|
||
|
|
Origins: []string{"http://localhost:3000", "http://localhost:5173"},
|
||
|
|
Methods: []string{
|
||
|
|
http.MethodGet,
|
||
|
|
http.MethodPost,
|
||
|
|
http.MethodPut,
|
||
|
|
http.MethodPatch,
|
||
|
|
http.MethodDelete,
|
||
|
|
http.MethodOptions,
|
||
|
|
},
|
||
|
|
Headers: []string{"Content-Type", "X-CSRF-Token"},
|
||
|
|
},
|
||
|
|
Sessions: SessionConfig{
|
||
|
|
ShortDuration: DefaultShortSession,
|
||
|
|
LongDuration: DefaultLongSession,
|
||
|
|
TokenSize: DefaultTokenSize,
|
||
|
|
},
|
||
|
|
Cookies: CookieConfig{
|
||
|
|
SessionName: DefaultSessionCookie,
|
||
|
|
CsrfName: DefaultCsrfCookie,
|
||
|
|
Secure: true,
|
||
|
|
},
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func LoadConfig() Config {
|
||
|
|
if err := env.LoadEnvDefault(); err != nil {
|
||
|
|
slog.Debug("env file not loaded", slog.String("op", "rest.LoadConfig"), slog.Any("error", err))
|
||
|
|
}
|
||
|
|
return ConfigFromEnvironment()
|
||
|
|
}
|
||
|
|
|
||
|
|
func ConfigFromEnvironment() Config {
|
||
|
|
cfg := DefaultConfig()
|
||
|
|
|
||
|
|
if v := os.Getenv("ADDR"); v != "" {
|
||
|
|
cfg.Addr = v
|
||
|
|
}
|
||
|
|
if v := os.Getenv("DB_PATH"); v != "" {
|
||
|
|
cfg.DatabasePath = v
|
||
|
|
}
|
||
|
|
if v := os.Getenv("PUBLIC_BASE_URL"); v != "" {
|
||
|
|
cfg.PublicBaseURL = strings.TrimRight(v, "/")
|
||
|
|
}
|
||
|
|
if v := os.Getenv("CORS_ORIGINS"); v != "" {
|
||
|
|
cfg.Cors.Origins = splitAndTrim(v)
|
||
|
|
}
|
||
|
|
if v := os.Getenv("COOKIE_SECURE"); v != "" {
|
||
|
|
if parsed, err := strconv.ParseBool(v); err == nil {
|
||
|
|
cfg.Cookies.Secure = parsed
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if v := os.Getenv("SESSION_SHORT_DURATION"); v != "" {
|
||
|
|
if parsed, err := time.ParseDuration(v); err == nil {
|
||
|
|
cfg.Sessions.ShortDuration = parsed
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if v := os.Getenv("SESSION_LONG_DURATION"); v != "" {
|
||
|
|
if parsed, err := time.ParseDuration(v); err == nil {
|
||
|
|
cfg.Sessions.LongDuration = parsed
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
cfg.Jitsi.Secret = os.Getenv("JITSI_SECRET")
|
||
|
|
cfg.Jitsi.AppId = os.Getenv("JITSI_APP_ID")
|
||
|
|
cfg.Jitsi.AppName = os.Getenv("JITSI_APP_NAME")
|
||
|
|
if v := os.Getenv("JITSI_DOMAIN"); v != "" {
|
||
|
|
cfg.Jitsi.Domain = v
|
||
|
|
}
|
||
|
|
|
||
|
|
return cfg
|
||
|
|
}
|
||
|
|
|
||
|
|
func splitAndTrim(value string) []string {
|
||
|
|
parts := strings.Split(value, ",")
|
||
|
|
result := make([]string, 0, len(parts))
|
||
|
|
for _, part := range parts {
|
||
|
|
if trimmed := strings.TrimSpace(part); trimmed != "" {
|
||
|
|
result = append(result, trimmed)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return result
|
||
|
|
}
|