security: fix rate-limit bypass, payment amount check, stats leak, owner-dir collision, video panic guard

- clientIP: stop trusting client-supplied X-Forwarded-For; use gin ClientIP
  with trusted proxies limited to private docker networks
- payment: verify notify money matches order amount; remove hardcoded
  gateway default, fail loudly when api_base is unset
- stats: public endpoint now serves aggregates only; recent files (owner
  names) moved to admin-only /stats/recent
- auth: reject signups whose username/email-local collides with another
  user's media directory namespace
- v1: recover panics in background video jobs, refund + mark failed
This commit is contained in:
dokploy-bot
2026-09-19 22:13:08 +08:00
parent 34f808e7e3
commit 42208c0753
8 changed files with 107 additions and 12 deletions
+14
View File
@@ -37,6 +37,16 @@ func New(cfg *config.Config, auth *service.AuthService, handlers Handlers) *gin.
}
engine := gin.New()
// Only the in-stack reverse proxies (traefik → frontend nginx, all on
// private docker networks) may supply forwarding headers; ClientIP then
// resolves the real client instead of a spoofable X-Forwarded-For.
_ = engine.SetTrustedProxies([]string{
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
"127.0.0.0/8",
"::1/128",
})
engine.Use(gin.Recovery())
engine.Use(middleware.RequestID())
engine.Use(cors.New(cors.Config{
@@ -64,6 +74,8 @@ func New(cfg *config.Config, auth *service.AuthService, handlers Handlers) *gin.
publicAdmin.GET("/site", handlers.Site.Public)
publicAdmin.GET("/showcase", handlers.Showcase.List)
publicAdmin.GET("/managed-models", handlers.AdminRead.Models)
// Aggregates only (counts/sizes/latency) — the recent-files list with
// owner names is admin-only, see /stats/recent below.
publicAdmin.GET("/stats", handlers.AdminRead.Stats)
publicAdmin.GET("/video-presets", handlers.UserGen.VideoPresets)
publicAdmin.GET("/catalog", handlers.UserGen.Catalog)
@@ -106,6 +118,8 @@ func New(cfg *config.Config, auth *service.AuthService, handlers Handlers) *gin.
authed.Use(middleware.RequireAdminSession(auth, cfg))
{
authed.GET("/dashboard", handlers.AdminRead.Dashboard)
// Recent generated files include owner-directory names — admin only.
authed.GET("/stats/recent", handlers.AdminRead.StatsRecent)
authed.GET("/users", handlers.AdminRead.Users)
authed.GET("/invites", handlers.AdminRead.Invites)
authed.POST("/users", handlers.AdminWrite.CreateUser)