aboutsummaryrefslogtreecommitdiffstats
path: root/internal/config/config.go
diff options
context:
space:
mode:
authorgrm <grm@eyesin.space>2026-09-18 13:47:49 +0300
committergrm <grm@eyesin.space>2026-09-18 13:47:49 +0300
commit3eeaa6d9a33f9294ade64c8ff26144fba86a379e (patch)
tree1c4bf44884ea59f7e3d9ca12008846f08bf72d16 /internal/config/config.go
parent254733b0566830a46e5a44c2d3127f57bfaceb65 (diff)
downloadblogspace-3eeaa6d9a33f9294ade64c8ff26144fba86a379e.tar.gz
blogspace-3eeaa6d9a33f9294ade64c8ff26144fba86a379e.tar.bz2
blogspace-3eeaa6d9a33f9294ade64c8ff26144fba86a379e.zip
Security: Add HTTPS and TRUST_PROXY settings
The app only ever speaks plain HTTP, so it could not know the site was served over TLS: generated links were http:// (the /webadmin bounce from a blog host sent the login page over http), the session cookie was never Secure and nothing sent HSTS. HTTPS=true fixes all three; ClearSessionCookie now uses the same attributes as the set, since a browser only replaces a cookie whose Secure flag matches. TRUST_PROXY=true makes the client address the last X-Forwarded-For entry — the one our proxy appended — so throttling and the log see real addresses instead of the proxy's; earlier entries are whatever the client sent and are ignored. Production startup warns when HTTPS is off. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
Diffstat (limited to 'internal/config/config.go')
-rw-r--r--internal/config/config.go20
1 files changed, 18 insertions, 2 deletions
diff --git a/internal/config/config.go b/internal/config/config.go
index a239aa2..c231860 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -19,6 +19,12 @@ type Config struct {
SuperadminPassword string
MaxUploadBytes int64 // default per-file limit; the superadmin can override it per blog
Dev bool // reload templates/static from disk
+ // HTTPS says the proxy in front terminates TLS: generated links are
+ // https://, the session cookie is Secure and HSTS is sent.
+ HTTPS bool
+ // TrustProxy says X-Forwarded-For was written by our own proxy, so its
+ // last entry is the client address (for throttling and the log).
+ TrustProxy bool
}
func Load() (*Config, error) {
@@ -31,6 +37,8 @@ func Load() (*Config, error) {
SuperadminUsername: env("SUPERADMIN_USERNAME", "admin"),
SuperadminPassword: env("SUPERADMIN_PASSWORD", ""),
Dev: envBool("DEV", false),
+ HTTPS: envBool("HTTPS", false),
+ TrustProxy: envBool("TRUST_PROXY", false),
}
mb, err := strconv.Atoi(env("MAX_UPLOAD_MB", "10"))
if err != nil || mb <= 0 {
@@ -62,12 +70,20 @@ func (c *Config) BlogURL(sub string) string {
if sub == RootSubdomain {
return c.RootURL()
}
- return "http://" + sub + "." + c.HostWithPort()
+ return c.Scheme() + "://" + sub + "." + c.HostWithPort()
}
// RootURL returns the public URL of the management site.
func (c *Config) RootURL() string {
- return "http://" + c.HostWithPort()
+ return c.Scheme() + "://" + c.HostWithPort()
+}
+
+// Scheme is the one the public reaches the site by.
+func (c *Config) Scheme() string {
+ if c.HTTPS {
+ return "https"
+ }
+ return "http"
}
func (c *Config) HostWithPort() string {