mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-28 11:16:37 +08:00
fix(auth/images): long-lived Emby token, unthrottle refresh, serve library posters
Three regressions reported on third-party clients and the web UI: - Third-party clients (Emby/Jellyfin) dropped login / could not play / could not refresh the library, roughly hourly. The Emby AuthenticateByName response returned the 60-minute access token, but Emby clients have no refresh mechanism and reuse the AccessToken until logout. Issue a long-lived (30d) token for the Emby compat layer via AuthService.IssueEmbyToken so device sessions persist. - Web could be thrown back to login under load: /auth/refresh was inside the IP rate-limited /auth group, so multiple users/tabs behind one reverse-proxy/NAT IP exhausted the budget and refresh failed -> logout. Only login/register are rate-limited now (raised to 30/min for shared IPs); refresh is excluded (already protected by a one-time refresh token). - Posters/images stopped displaying on the web home and other pages (refresh did not help). The SSRF/path hardening (a) blocked the image proxy whenever a hostname *resolved* to a private IP, which happens under GFW DNS poisoning of public CDNs like image.tmdb.org, and (b) restricted local image reads to data/cache/movies/tv/anime dirs only, dropping sidecar posters stored under arbitrary per-library roots to a placeholder. isPrivateHost now only blocks literal private/loopback IPs (real SSRF vectors) and ImageProxy also allows reads under configured library roots. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -25,18 +25,24 @@ func Register(r *gin.Engine, cfg *config.Config, log *zap.Logger, svc *service.C
|
||||
// Telegram Bot webhook — called by Telegram servers, no auth.
|
||||
api.POST("/telegram/webhook", telegramWebhookHandler(svc))
|
||||
|
||||
// Rate limiter for auth endpoints: 10 attempts per minute per IP.
|
||||
authLimiter := middleware.NewRateLimiter(10, 1*time.Minute)
|
||||
// Rate limiter for credential endpoints (login/register): brute-force
|
||||
// protection. 30/min per IP tolerates many users behind a single NAT
|
||||
// or reverse-proxy IP while still throttling password guessing.
|
||||
authLimiter := middleware.NewRateLimiter(30, 1*time.Minute)
|
||||
|
||||
// Public auth.
|
||||
auth := api.Group("/auth")
|
||||
auth.Use(middleware.RateLimit(authLimiter))
|
||||
{
|
||||
auth.POST("/login", loginHandler(svc))
|
||||
auth.POST("/register", registerHandler(svc))
|
||||
auth.POST("/login", middleware.RateLimit(authLimiter), loginHandler(svc))
|
||||
auth.POST("/register", middleware.RateLimit(authLimiter), registerHandler(svc))
|
||||
// /auth/refresh 用 RefreshHandler.RefreshToken:它从 body 读
|
||||
// refresh_token 并签发新 access/refresh 对。旧的 refreshHandler
|
||||
// 依赖 AuthRequired 中间件,永远 401,因此弃用。
|
||||
//
|
||||
// 刷新端点【不】做 IP 限流:刷新本身就是防止掉登录的机制,且已
|
||||
// 由一次性轮换的 refresh token 强校验。若按 IP 限流,多个用户/
|
||||
// 标签页共用一个反代 IP 时会把正常刷新打成 429,反而导致频繁
|
||||
// 掉登录。
|
||||
refreshHd := NewRefreshHandler(svc, log)
|
||||
auth.POST("/refresh", refreshHd.RefreshToken)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user