diff options
| author | grm <grm@eyesin.space> | 2026-09-18 13:47:49 +0300 |
|---|---|---|
| committer | grm <grm@eyesin.space> | 2026-09-18 13:47:49 +0300 |
| commit | 3eeaa6d9a33f9294ade64c8ff26144fba86a379e (patch) | |
| tree | 1c4bf44884ea59f7e3d9ca12008846f08bf72d16 /internal/config | |
| parent | 254733b0566830a46e5a44c2d3127f57bfaceb65 (diff) | |
| download | blogspace-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')
| -rw-r--r-- | internal/config/config.go | 20 |
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 { |
