缩略图懒生成 + 评论登录限流:时间线不再拉原图

- 新增 /uploads/thumb/{key}?w=:首访从存储端读一次原图,标准库盒均值缩放后
  落盘 data/.thumbnail_cache(按内容哈希命名,天然失效);失败写 .failed 冷却
  一小时,非图片/超大一律 302 回原图,前端无感。原图路由改用 ServeContent,
  补上视频拖动进度条所需的 Range 支持
- 前端 thumbURL/thumbifyHtml 接入两套 UI 的时间线配图、长文封面与短文正文,
  并补 loading=lazy;详情页与灯箱仍用原图。/api/site 改为
  {settings, uploads_public_base},让前端识别哪些直链属于自家存储
- 后台登录的滑动窗口限速器抽成 internal/ratelimit 共享包(调用面不变),
  新增:读者登录失败按 IP 20 次/10 分钟、评论写入按读者 5 条/分钟
  (站主豁免,且只计成功写入)
This commit is contained in:
Sakurasan
2026-09-28 13:34:19 +08:00
parent b6342a622d
commit 6108aca34c
17 changed files with 822 additions and 71 deletions
+3 -3
View File
@@ -138,7 +138,7 @@ func (a *API) login(w http.ResponseWriter, r *http.Request) {
return
}
key := sourceKey(r)
if a.limiter().blocked(key) {
if a.limiter().Blocked(key) {
httpx.Error(w, http.StatusTooManyRequests, "失败次数过多,请 10 分钟后再试")
return
}
@@ -150,11 +150,11 @@ func (a *API) login(w http.ResponseWriter, r *http.Request) {
userOK := subtle.ConstantTimeCompare([]byte(in.Username), []byte(a.Cfg.AdminUser)) == 1
passOK := subtle.ConstantTimeCompare([]byte(in.Password), []byte(a.Cfg.AdminPass)) == 1
if !userOK || !passOK {
a.limiter().fail(key)
a.limiter().Add(key)
httpx.Unauthorized(w)
return
}
a.limiter().reset(key)
a.limiter().Reset(key)
token, exp := a.Sessions.Issue(a.Cfg.AdminUser)
http.SetCookie(w, &http.Cookie{
Name: cookieName,