fix(security): trusted-proxy-scoped login rate limit

This commit is contained in:
2026-09-07 12:44:47 +08:00
parent f7c27272ba
commit 6adbab44c3
5 changed files with 71 additions and 21 deletions
+33 -20
View File
@@ -5,20 +5,22 @@ import (
"os"
"path/filepath"
"strconv"
"strings"
"time"
)
type Config struct {
Addr string
DatabaseURL string
RedisURL string
JWTSecret []byte
AdminUser string
AdminPassword string
BooksDir string
CacheDir string
ScanInterval time.Duration
UploadMaxMB int64
Addr string
DatabaseURL string
RedisURL string
JWTSecret []byte
AdminUser string
AdminPassword string
BooksDir string
CacheDir string
ScanInterval time.Duration
UploadMaxMB int64
TrustedProxies []string
}
func Load() (*Config, error) {
@@ -28,6 +30,16 @@ func Load() (*Config, error) {
}
return def
}
envList := func(k, def string) []string {
v := env(k, def)
out := make([]string, 0, len(strings.Split(v, ",")))
for _, s := range strings.Split(v, ",") {
if s = strings.TrimSpace(s); s != "" {
out = append(out, s)
}
}
return out
}
scanSec, err := strconv.Atoi(env("SCAN_INTERVAL_SEC", "60"))
if err != nil {
return nil, fmt.Errorf("SCAN_INTERVAL_SEC: %w", err)
@@ -49,15 +61,16 @@ func Load() (*Config, error) {
return dir
}
return &Config{
Addr: env("ADDR", ":8080"),
DatabaseURL: env("DATABASE_URL", ""),
RedisURL: env("REDIS_URL", ""),
JWTSecret: []byte(secret),
AdminUser: env("ADMIN_USER", ""),
AdminPassword: env("ADMIN_PASSWORD", ""),
BooksDir: resolveDir(env("BOOKS_DIR", "/data/books")),
CacheDir: resolveDir(env("CACHE_DIR", "/data/cache")),
ScanInterval: time.Duration(scanSec) * time.Second,
UploadMaxMB: uploadMB,
Addr: env("ADDR", ":8080"),
DatabaseURL: env("DATABASE_URL", ""),
RedisURL: env("REDIS_URL", ""),
JWTSecret: []byte(secret),
AdminUser: env("ADMIN_USER", ""),
AdminPassword: env("ADMIN_PASSWORD", ""),
BooksDir: resolveDir(env("BOOKS_DIR", "/data/books")),
CacheDir: resolveDir(env("CACHE_DIR", "/data/cache")),
ScanInterval: time.Duration(scanSec) * time.Second,
UploadMaxMB: uploadMB,
TrustedProxies: envList("TRUSTED_PROXY_CIDRS", "172.16.0.0/12"),
}, nil
}
+12
View File
@@ -22,6 +22,7 @@ func TestLoad(t *testing.T) {
}
t.Setenv("SCAN_INTERVAL_SEC", "30")
t.Setenv("DATABASE_URL", "postgres://x")
t.Setenv("TRUSTED_PROXY_CIDRS", "")
c, err := Load()
if err != nil {
t.Fatal(err)
@@ -34,4 +35,15 @@ func TestLoad(t *testing.T) {
if c.ScanInterval != 30*time.Second || c.BooksDir != wantBooks || c.Addr != ":8080" {
t.Fatalf("%+v", c)
}
if len(c.TrustedProxies) != 1 || c.TrustedProxies[0] != "172.16.0.0/12" {
t.Fatalf("trusted proxies default: %+v", c.TrustedProxies)
}
t.Setenv("TRUSTED_PROXY_CIDRS", "10.0.0.0/8, 1.2.3.4")
c, err = Load()
if err != nil {
t.Fatal(err)
}
if len(c.TrustedProxies) != 2 || c.TrustedProxies[0] != "10.0.0.0/8" || c.TrustedProxies[1] != "1.2.3.4" {
t.Fatalf("trusted proxies override: %+v", c.TrustedProxies)
}
}