feat: publish sanitized custom.97 source
This commit is contained in:
1022 files changed
+69903
-19207
No files matched your search
@@ -0,0 +1,84 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/subtle"
|
||||
"math"
|
||||
"net/http"
|
||||
"net/mail"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/QuantumNous/new-api/common"
|
||||
"github.com/QuantumNous/new-api/model"
|
||||
"github.com/QuantumNous/new-api/setting/operation_setting"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/shopspring/decimal"
|
||||
)
|
||||
|
||||
// BotBalanceQuery is a dedicated read-only API; its key grants no dashboard access.
|
||||
func BotBalanceQuery(c *gin.Context) {
|
||||
c.Header("Cache-Control", "no-store")
|
||||
key := os.Getenv("BOT_BALANCE_KEY")
|
||||
raw, bearer := strings.CutPrefix(c.GetHeader("Authorization"), "Bearer ")
|
||||
expected, supplied := sha256.Sum256([]byte(key)), sha256.Sum256([]byte(raw))
|
||||
if len(key) < 32 || !bearer || subtle.ConstantTimeCompare(expected[:], supplied[:]) != 1 {
|
||||
c.JSON(http.StatusUnauthorized, gin.H{"success": false, "code": "unauthorized"})
|
||||
return
|
||||
}
|
||||
c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, 8192)
|
||||
var request struct {
|
||||
Email string `json:"email"`
|
||||
IDs []int `json:"ids"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"success": false, "code": "invalid_request"})
|
||||
return
|
||||
}
|
||||
email := model.NormalizeEmail(request.Email)
|
||||
if (email == "") == (len(request.IDs) == 0) || len(request.IDs) > 100 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"success": false, "code": "invalid_request"})
|
||||
return
|
||||
}
|
||||
if email != "" {
|
||||
parsed, err := mail.ParseAddress(email)
|
||||
if err != nil || parsed.Address != email || len(email) > 50 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"success": false, "code": "invalid_email"})
|
||||
return
|
||||
}
|
||||
}
|
||||
for _, id := range request.IDs {
|
||||
if id <= 0 {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"success": false, "code": "invalid_request"})
|
||||
return
|
||||
}
|
||||
}
|
||||
accounts, err := model.FindBotBalanceAccounts(email, request.IDs)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusServiceUnavailable, gin.H{"success": false, "code": "query_failed"})
|
||||
return
|
||||
}
|
||||
if email != "" && len(accounts) != 1 {
|
||||
code := "not_found"
|
||||
if len(accounts) > 1 {
|
||||
code = "ambiguous_email"
|
||||
}
|
||||
c.JSON(http.StatusConflict, gin.H{"success": false, "code": code})
|
||||
return
|
||||
}
|
||||
unit, rate := common.QuotaPerUnit, operation_setting.USDExchangeRate
|
||||
if unit <= 0 || rate <= 0 || math.IsNaN(unit) || math.IsNaN(rate) || math.IsInf(unit, 0) || math.IsInf(rate, 0) {
|
||||
c.JSON(http.StatusServiceUnavailable, gin.H{"success": false, "code": "invalid_currency"})
|
||||
return
|
||||
}
|
||||
items := make([]gin.H, 0, len(accounts))
|
||||
for _, account := range accounts {
|
||||
active := account.Status == common.UserStatusEnabled
|
||||
item := gin.H{"id": account.ID, "active": active}
|
||||
if active {
|
||||
item["balance_cny"] = decimal.NewFromInt(int64(account.Quota)).Mul(decimal.NewFromFloat(rate)).DivRound(decimal.NewFromFloat(unit), 18).String()
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": items})
|
||||
}
|
||||
Reference in new issue
Block a user