66 lines
1.9 KiB
Go
66 lines
1.9 KiB
Go
// Package config reads the process environment once, at startup, so that a
|
|
// missing setting fails the boot rather than the first request that needs it.
|
|
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
type Config struct {
|
|
DatabaseURL string
|
|
// BaseURL is the public origin. It decides whether the session cookie is
|
|
// marked Secure and what host magic links point at, so it must be the real
|
|
// external URL in production, not the listen address.
|
|
BaseURL string
|
|
Addr string
|
|
SessionKey []byte
|
|
AdminEmails []string
|
|
// WebDir holds the built frontend: index.html is never served from here,
|
|
// only the hashed assets and the Vite manifest the shell reads.
|
|
WebDir string
|
|
Dev bool
|
|
}
|
|
|
|
func Load() (*Config, error) {
|
|
c := &Config{
|
|
DatabaseURL: os.Getenv("DATABASE_URL"),
|
|
BaseURL: envOr("BASE_URL", "http://localhost:3000"),
|
|
Addr: envOr("ADDR", ":3000"),
|
|
WebDir: envOr("WEB_DIR", "./web"),
|
|
Dev: os.Getenv("APP_ENV") == "development",
|
|
}
|
|
|
|
if c.DatabaseURL == "" {
|
|
return nil, fmt.Errorf("DATABASE_URL environment variable is missing")
|
|
}
|
|
|
|
secret := os.Getenv("SESSION_SECRET")
|
|
if secret == "" {
|
|
return nil, fmt.Errorf("SESSION_SECRET environment variable is missing (openssl rand -base64 32)")
|
|
}
|
|
c.SessionKey = []byte(secret)
|
|
|
|
for _, e := range strings.Split(os.Getenv("ADMIN_EMAILS"), ",") {
|
|
if e = strings.ToLower(strings.TrimSpace(e)); e != "" {
|
|
c.AdminEmails = append(c.AdminEmails, e)
|
|
}
|
|
}
|
|
|
|
c.BaseURL = strings.TrimRight(c.BaseURL, "/")
|
|
return c, nil
|
|
}
|
|
|
|
// Secure reports whether cookies may carry the Secure flag. Setting it on a
|
|
// plain-HTTP origin would make the browser drop the cookie silently, which
|
|
// looks exactly like a broken login.
|
|
func (c *Config) Secure() bool { return strings.HasPrefix(c.BaseURL, "https://") }
|
|
|
|
func envOr(key, fallback string) string {
|
|
if v := os.Getenv(key); v != "" {
|
|
return v
|
|
}
|
|
return fallback
|
|
}
|