aboutsummaryrefslogtreecommitdiffstats
path: root/internal/config/config.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/config/config.go')
-rw-r--r--internal/config/config.go90
1 files changed, 90 insertions, 0 deletions
diff --git a/internal/config/config.go b/internal/config/config.go
new file mode 100644
index 0000000..4972178
--- /dev/null
+++ b/internal/config/config.go
@@ -0,0 +1,90 @@
+// Package config reads application settings from the environment.
+package config
+
+import (
+ "fmt"
+ "os"
+ "strconv"
+ "strings"
+)
+
+type Config struct {
+ Addr string // listen address, e.g. ":8080"
+ BaseDomain string // e.g. "example.com" (no port)
+ PublicPort string // port to append to generated blog URLs ("" in prod behind a proxy)
+ DatabaseURL string
+ JWTSecret []byte
+ // Bootstrap superadmin created on first start if no superadmin exists.
+ SuperadminUsername string
+ SuperadminPassword string
+ MaxUploadBytes int64
+ Dev bool // reload templates/static from disk
+}
+
+func Load() (*Config, error) {
+ c := &Config{
+ Addr: env("ADDR", ":8080"),
+ BaseDomain: strings.ToLower(strings.TrimSpace(env("BASE_DOMAIN", "blogspace.localhost"))),
+ PublicPort: env("PUBLIC_PORT", ""),
+ DatabaseURL: env("DATABASE_URL", "postgres://blogspace:blogspace@localhost:5432/blogspace?sslmode=disable"),
+ JWTSecret: []byte(env("JWT_SECRET", "")),
+ SuperadminUsername: env("SUPERADMIN_USERNAME", "admin"),
+ SuperadminPassword: env("SUPERADMIN_PASSWORD", ""),
+ Dev: envBool("DEV", false),
+ }
+ mb, err := strconv.Atoi(env("MAX_UPLOAD_MB", "5"))
+ if err != nil || mb <= 0 {
+ return nil, fmt.Errorf("MAX_UPLOAD_MB must be a positive integer")
+ }
+ c.MaxUploadBytes = int64(mb) << 20
+
+ if len(c.JWTSecret) == 0 {
+ if !c.Dev {
+ return nil, fmt.Errorf("JWT_SECRET must be set")
+ }
+ c.JWTSecret = []byte("dev-insecure-secret-change-me")
+ }
+ if len(c.JWTSecret) < 16 && !c.Dev {
+ return nil, fmt.Errorf("JWT_SECRET must be at least 16 bytes")
+ }
+ if c.BaseDomain == "" {
+ return nil, fmt.Errorf("BASE_DOMAIN must be set")
+ }
+ return c, nil
+}
+
+// BlogURL returns the public URL for a blog subdomain.
+func (c *Config) BlogURL(sub string) string {
+ return "http://" + sub + "." + c.HostWithPort()
+}
+
+// RootURL returns the public URL of the management site.
+func (c *Config) RootURL() string {
+ return "http://" + c.HostWithPort()
+}
+
+func (c *Config) HostWithPort() string {
+ if c.PublicPort != "" {
+ return c.BaseDomain + ":" + c.PublicPort
+ }
+ return c.BaseDomain
+}
+
+func env(key, def string) string {
+ if v, ok := os.LookupEnv(key); ok {
+ return v
+ }
+ return def
+}
+
+func envBool(key string, def bool) bool {
+ v, ok := os.LookupEnv(key)
+ if !ok {
+ return def
+ }
+ switch strings.ToLower(v) {
+ case "1", "true", "yes", "on":
+ return true
+ }
+ return false
+}