feat: public status page endpoint with per-address rate limit
This commit is contained in:
@@ -263,6 +263,14 @@ func serve() {
|
||||
})
|
||||
|
||||
r := gin.New()
|
||||
// Without this gin trusts every proxy and ClientIP() is whatever the
|
||||
// caller wrote in X-Forwarded-For. That was survivable while ClientIP()
|
||||
// only produced audit strings; the public status limiter makes it load
|
||||
// bearing. Empty means trust nobody, which is correct for a direct
|
||||
// exposure and wrong behind a proxy — hence the explicit setting.
|
||||
if err := r.SetTrustedProxies(trustedProxies()); err != nil {
|
||||
log.Fatalf("trusted proxies: %v", err)
|
||||
}
|
||||
r.Use(gin.Recovery())
|
||||
r.Use(gin.LoggerWithConfig(gin.LoggerConfig{SkipPaths: []string{"/api/console/tunnel"}}))
|
||||
r.Use(corsMiddleware())
|
||||
@@ -318,6 +326,25 @@ func corsMiddleware() gin.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// trustedProxies reads TRUSTED_PROXIES, a comma-separated list of CIDRs or
|
||||
// addresses. Unset means trust none: ClientIP() is then the peer address,
|
||||
// which is right for a direct exposure and means every request behind an
|
||||
// un-configured proxy shares one address for rate limiting. That is a visible
|
||||
// failure (one client limited) rather than an invisible one (no limit at all).
|
||||
func trustedProxies() []string {
|
||||
v := strings.TrimSpace(os.Getenv("TRUSTED_PROXIES"))
|
||||
if v == "" {
|
||||
return nil
|
||||
}
|
||||
out := []string{}
|
||||
for _, p := range strings.Split(v, ",") {
|
||||
if p = strings.TrimSpace(p); p != "" {
|
||||
out = append(out, p)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func getEnv(key, fallback string) string {
|
||||
if v := os.Getenv(key); v != "" {
|
||||
return v
|
||||
|
||||
Reference in New Issue
Block a user