Files
2026-05-13 12:19:36 +08:00

96 lines
2.7 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package handlers
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"time"
"github.com/gin-gonic/gin"
"sproutgate-backend/internal/storage"
)
const turnstileVerifyURL = "https://challenges.cloudflare.com/turnstile/v0/siteverify"
type turnstileVerifyResp struct {
Success bool `json:"success"`
}
// verifyTurnstileToken 向 Cloudflare 验证 Turnstile token失败返回用户可见错误。
func verifyTurnstileToken(ctx context.Context, secretKey, token, remoteIP string) error {
if strings.TrimSpace(token) == "" {
return fmt.Errorf("请完成人机验证")
}
form := url.Values{}
form.Set("secret", secretKey)
form.Set("response", token)
if remoteIP != "" {
form.Set("remoteip", remoteIP)
}
client := &http.Client{Timeout: 8 * time.Second}
resp, err := client.PostForm(turnstileVerifyURL, form)
if err != nil {
return fmt.Errorf("人机验证服务暂时不可用,请稍后重试")
}
defer resp.Body.Close()
var result turnstileVerifyResp
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return fmt.Errorf("人机验证响应解析失败")
}
if !result.Success {
return fmt.Errorf("人机验证未通过,请重试")
}
return nil
}
// GetAdminTurnstile
// @Summary Turnstile 配置(脱敏)
// @Tags admin
// @Produce json
// @Security AdminToken
// @Success 200 {object} map[string]interface{}
// @Failure 401 {object} map[string]interface{}
// @Router /api/admin/turnstile [get]
func (h *Handler) GetAdminTurnstile(c *gin.Context) {
cfg := h.store.GetTurnstileConfig()
c.JSON(http.StatusOK, gin.H{
"enabled": cfg.Enabled,
"siteKey": strings.TrimSpace(cfg.SiteKey),
"secretKeySet": strings.TrimSpace(cfg.SecretKey) != "",
})
}
// PutAdminTurnstile
// @Summary 更新 Turnstile 配置
// @Tags admin
// @Accept json
// @Produce json
// @Security AdminToken
// @Param body body PutAdminTurnstileRequest true "siteKey、secretKey"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} map[string]interface{}
// @Failure 401 {object} map[string]interface{}
// @Failure 500 {object} map[string]interface{}
// @Router /api/admin/turnstile [put]
func (h *Handler) PutAdminTurnstile(c *gin.Context) {
var req PutAdminTurnstileRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request"})
return
}
in := storage.TurnstileConfig{
Enabled: req.Enabled,
SiteKey: strings.TrimSpace(req.SiteKey),
SecretKey: strings.TrimSpace(req.SecretKey),
}
if err := h.store.UpdateTurnstileConfig(in); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to save turnstile config"})
return
}
h.GetAdminTurnstile(c)
}