feat: SSR 右栏签到/抽奖条与安全回跳

EOF

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-29 15:55:32 +08:00
parent 959a2c3a2e
commit c4faba81b3
8 changed files with 182 additions and 12 deletions

View File

@@ -226,11 +226,22 @@ func (d Deps) ProfileAvatarPost(c *gin.Context) {
// ProfileCheckInPost 每日签到PRG
func (d Deps) ProfileCheckInPost(c *gin.Context) {
ctx := d.ctx(c)
redir := safePointsRedirect(c.PostForm("redirect"))
if !ctx.CheckCSRF() {
if redir != "/profile" {
ctx.SetFlash("无效请求,请重试")
ctx.Redirect(redir)
return
}
d.renderProfile(ctx, "无效请求,请重试")
return
}
if d.Points == nil {
if redir != "/profile" {
ctx.SetFlash("积分服务未就绪")
ctx.Redirect(redir)
return
}
d.renderProfile(ctx, "积分服务未就绪")
return
}
@@ -238,24 +249,40 @@ func (d Deps) ProfileCheckInPost(c *gin.Context) {
if err != nil {
if errors.Is(err, services.ErrAlreadyCheckedIn) {
ctx.SetFlash("今日已签到")
ctx.Redirect("/profile")
ctx.Redirect(redir)
return
}
if redir != "/profile" {
ctx.SetFlash(err.Error())
ctx.Redirect(redir)
return
}
d.renderProfile(ctx, err.Error())
return
}
ctx.SetFlash(fmt.Sprintf("签到成功:连续 %d 天,获得 %d 积分", st.Streak, st.TodayPoints))
ctx.Redirect("/profile")
ctx.Redirect(redir)
}
// ProfileLotteryPost 每日抽奖PRG
func (d Deps) ProfileLotteryPost(c *gin.Context) {
ctx := d.ctx(c)
redir := safePointsRedirect(c.PostForm("redirect"))
if !ctx.CheckCSRF() {
if redir != "/profile" {
ctx.SetFlash("无效请求,请重试")
ctx.Redirect(redir)
return
}
d.renderProfile(ctx, "无效请求,请重试")
return
}
if d.Points == nil {
if redir != "/profile" {
ctx.SetFlash("积分服务未就绪")
ctx.Redirect(redir)
return
}
d.renderProfile(ctx, "积分服务未就绪")
return
}
@@ -263,7 +290,12 @@ func (d Deps) ProfileLotteryPost(c *gin.Context) {
if err != nil {
if errors.Is(err, services.ErrAlreadyLottery) {
ctx.SetFlash("今日已抽奖")
ctx.Redirect("/profile")
ctx.Redirect(redir)
return
}
if redir != "/profile" {
ctx.SetFlash(err.Error())
ctx.Redirect(redir)
return
}
d.renderProfile(ctx, err.Error())
@@ -274,5 +306,23 @@ func (d Deps) ProfileLotteryPost(c *gin.Context) {
} else {
ctx.SetFlash("抽奖结果:未中奖,明天再来")
}
ctx.Redirect("/profile")
ctx.Redirect(redir)
}
// safePointsRedirect 签到/抽奖 PRG 回跳:仅允许 /、/board/…、/post/…;空或非法则 /profile
func safePointsRedirect(raw string) string {
raw = strings.TrimSpace(raw)
if raw == "" || strings.Contains(raw, "://") || strings.HasPrefix(raw, "//") || strings.Contains(raw, "..") {
return "/profile"
}
if raw == "/" {
return raw
}
if strings.HasPrefix(raw, "/board/") || strings.HasPrefix(raw, "/post/") {
if strings.ContainsAny(raw, "?#") {
return "/profile"
}
return raw
}
return "/profile"
}