mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-29 05:56:38 +08:00
94 lines
2.8 KiB
Go
94 lines
2.8 KiB
Go
// Copyright 2026 Arctel.net
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package cap
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/Rain-kl/Wavelet/internal/common/response"
|
|
pkgcap "github.com/Rain-kl/Wavelet/pkg/cap"
|
|
"github.com/Rain-kl/Wavelet/pkg/logger"
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
// ChallengeResponse is a local type alias for the pkg/cap.ChallengeResponse struct
|
|
type ChallengeResponse = pkgcap.ChallengeResponse
|
|
|
|
type challengeRequest struct {
|
|
Scope string `json:"scope" form:"scope"`
|
|
}
|
|
|
|
type redeemRequest struct {
|
|
Token string `json:"token" binding:"required"`
|
|
Solutions []int `json:"solutions" binding:"required"`
|
|
Scope string `json:"scope" form:"scope"`
|
|
}
|
|
|
|
// Challenge 生成 PoW 人机验证难题
|
|
// @Summary 生成人机验证难题
|
|
// @Description 客户端获取 PoW 难题和签名的 JWT Token,并在后台计算。
|
|
// @Tags cap
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body challengeRequest false "可选范围限制参数"
|
|
// @Success 200 {object} response.Any{data=cap.ChallengeResponse} "成功返回 PoW 难题"
|
|
// @Failure 500 {object} response.Any "内部服务错误"
|
|
// @Router /api/cap/challenge [post]
|
|
func Challenge(c *gin.Context) {
|
|
var req challengeRequest
|
|
_ = c.ShouldBind(&req) // 允许不传 body,默认使用 login scope
|
|
|
|
if req.Scope == "" {
|
|
req.Scope = "login"
|
|
}
|
|
|
|
mgr := GetDefaultManager()
|
|
resp, err := mgr.Generate(c.Request.Context(), req.Scope)
|
|
if err != nil {
|
|
logger.ErrorF(c.Request.Context(), "Generate cap challenge failed: %v", err)
|
|
response.AbortInternal(c, "生成验证难题失败,请稍后再试")
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, response.OK(resp))
|
|
}
|
|
|
|
// Redeem 提交 PoW 解答并兑换一次性凭证 Token
|
|
// @Summary 校验人机验证解答
|
|
// @Description 提交 PoW 解答进行核销,成功后返回一次性 X-Cap-Token 凭证
|
|
// @Tags cap
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param request body redeemRequest true "难题 Token 与解答 solutions 数组"
|
|
// @Success 200 {object} response.Any{data=cap.RedeemResponse} "核销成功,返回 X-Cap-Token"
|
|
// @Failure 400 {object} response.Any "参数错误或核销失败"
|
|
// @Failure 500 {object} response.Any "内部服务错误"
|
|
// @Router /api/cap/redeem [post]
|
|
func Redeem(c *gin.Context) {
|
|
var req redeemRequest
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
response.AbortBadRequest(c, "无效的参数")
|
|
return
|
|
}
|
|
|
|
if req.Scope == "" {
|
|
req.Scope = "login"
|
|
}
|
|
|
|
mgr := GetDefaultManager()
|
|
resp, err := mgr.Redeem(c.Request.Context(), req.Token, req.Solutions, req.Scope)
|
|
if err != nil {
|
|
logger.ErrorF(c.Request.Context(), "Redeem cap solutions failed: %v", err)
|
|
response.AbortInternal(c, "校验验证解答失败,请稍后再试")
|
|
return
|
|
}
|
|
|
|
if !resp.Success {
|
|
response.AbortBadRequest(c, resp.Error)
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusOK, response.OK(resp))
|
|
}
|