fix(billing): validate quantity parameters and harden quota calculations

Bound user-supplied count/duration parameters at request validation,
route ratio multipliers through guarded setters, and use saturating
int conversions in all quota math paths.
This commit is contained in:
CaIon
2026-07-07 00:21:06 +08:00
parent 45f0484dc1
commit d0bd8aac74
17 changed files with 293 additions and 19 deletions
+6
View File
@@ -54,6 +54,12 @@ func oaiImage2AliImageRequest(info *relaycommon.RelayInfo, request dto.ImageRequ
}
}
// Parameters may come from Extra["parameters"], bypassing the standard
// top-level n validation; enforce the same bound before it becomes a
// billing multiplier.
if imageRequest.Parameters.N < 0 || imageRequest.Parameters.N > dto.MaxImageN {
return nil, fmt.Errorf("parameters.n must be an integer between 1 and %d", dto.MaxImageN)
}
if imageRequest.Parameters.N != 0 {
info.PriceData.AddOtherRatio("n", float64(imageRequest.Parameters.N))
}
+3 -1
View File
@@ -456,8 +456,10 @@ func (a *TaskAdaptor) EstimateBilling(c *gin.Context, info *relaycommon.RelayInf
return nil
}
// metadata can override Duration past standard request validation;
// cap it because it is used as a billing multiplier.
otherRatios := map[string]float64{
"seconds": float64(aliReq.Parameters.Duration),
"seconds": float64(min(aliReq.Parameters.Duration, relaycommon.MaxTaskDurationSeconds)),
}
ratios, err := ProcessAliOtherRatios(aliReq)
if err != nil {
+7 -3
View File
@@ -3,6 +3,8 @@ package gemini
import (
"strconv"
"strings"
relaycommon "github.com/QuantumNous/new-api/relay/common"
)
// ParseVeoDurationSeconds extracts durationSeconds from metadata.
@@ -46,19 +48,21 @@ func ParseVeoResolution(metadata map[string]any) string {
// ResolveVeoDuration returns the effective duration in seconds.
// Priority: metadata["durationSeconds"] > stdDuration > stdSeconds > default (8).
// The result is capped because it is used as a billing multiplier and the
// metadata path bypasses standard request validation.
func ResolveVeoDuration(metadata map[string]any, stdDuration int, stdSeconds string) int {
if metadata != nil {
if _, exists := metadata["durationSeconds"]; exists {
if d := ParseVeoDurationSeconds(metadata); d > 0 {
return d
return min(d, relaycommon.MaxTaskDurationSeconds)
}
}
}
if stdDuration > 0 {
return stdDuration
return min(stdDuration, relaycommon.MaxTaskDurationSeconds)
}
if s, err := strconv.Atoi(stdSeconds); err == nil && s > 0 {
return s
return min(s, relaycommon.MaxTaskDurationSeconds)
}
return 8
}