diff --git a/apis/admin/order.api b/apis/admin/order.api index 0d49074..87fa80d 100644 --- a/apis/admin/order.api +++ b/apis/admin/order.api @@ -14,14 +14,14 @@ type ( CreateOrderRequest { UserId int64 `json:"user_id" validate:"required"` Type uint8 `json:"type" validate:"required"` - Quantity int64 `json:"quantity,omitempty"` - Price int64 `json:"price" validate:"required"` - Amount int64 `json:"amount" validate:"required"` - Discount int64 `json:"discount,omitempty"` + Quantity int64 `json:"quantity,omitempty" validate:"omitempty,lte=1000"` + Price int64 `json:"price" validate:"required,gte=0,lte=2000000000"` + Amount int64 `json:"amount" validate:"required,gte=0,lte=2147483647"` + Discount int64 `json:"discount,omitempty" validate:"omitempty,gte=0,lte=2000000000"` Coupon string `json:"coupon,omitempty"` - CouponDiscount int64 `json:"coupon_discount,omitempty"` - Commission int64 `json:"commission"` - FeeAmount int64 `json:"fee_amount" validate:"required"` + CouponDiscount int64 `json:"coupon_discount,omitempty" validate:"omitempty,gte=0,lte=2000000000"` + Commission int64 `json:"commission" validate:"gte=0,lte=2000000000"` + FeeAmount int64 `json:"fee_amount" validate:"required,gte=0,lte=2000000000"` PaymentId int64 `json:"payment_id" validate:"required"` TradeNo string `json:"trade_no,omitempty"` Status uint8 `json:"status,omitempty"` diff --git a/apis/types.api b/apis/types.api index 5f174be..f3e0f15 100644 --- a/apis/types.api +++ b/apis/types.api @@ -580,7 +580,7 @@ type ( //public order PurchaseOrderRequest { SubscribeId int64 `json:"subscribe_id"` - Quantity int64 `json:"quantity" validate:"required,gt=0"` + Quantity int64 `json:"quantity" validate:"required,gt=0,lte=1000"` Payment int64 `json:"payment,omitempty"` Coupon string `json:"coupon,omitempty"` } @@ -598,7 +598,7 @@ type ( } RenewalOrderRequest { UserSubscribeID int64 `json:"user_subscribe_id"` - Quantity int64 `json:"quantity"` + Quantity int64 `json:"quantity" validate:"lte=1000"` Payment int64 `json:"payment"` Coupon string `json:"coupon,omitempty"` } @@ -613,7 +613,7 @@ type ( OrderNo string `json:"order_no"` } RechargeOrderRequest { - Amount int64 `json:"amount"` + Amount int64 `json:"amount" validate:"required,gt=0,lte=2000000000"` Payment int64 `json:"payment"` } RechargeOrderResponse { diff --git a/internal/handler/routes.go b/internal/handler/routes.go index 6a942a7..16654d5 100644 --- a/internal/handler/routes.go +++ b/internal/handler/routes.go @@ -888,10 +888,10 @@ func RegisterHandlers(router *gin.Engine, serverCtx *svc.ServiceContext) { serverGroupRouter.GET("/user", server.GetServerUserListHandler(serverCtx)) } - serverV2GroupRouter := router.Group("/v2/server") + serverGroupRouter := router.Group("/v2/server") { // Get Server Protocol Config - serverV2GroupRouter.GET("/:server_id", server.QueryServerProtocolConfigHandler(serverCtx)) + serverGroupRouter.GET("/:server_id", server.QueryServerProtocolConfigHandler(serverCtx)) } } diff --git a/internal/logic/public/order/constant.go b/internal/logic/public/order/constant.go index ca1c44a..cc3683a 100644 --- a/internal/logic/public/order/constant.go +++ b/internal/logic/public/order/constant.go @@ -6,4 +6,9 @@ const ( StripeAlipay = "stripe_alipay" StripeWeChatPay = "stripe_wechat_pay" Balance = "balance" + + // MaxOrderAmount Order amount limits + MaxOrderAmount = 2147483647 // int32 max value (2.1 billion) + MaxRechargeAmount = 2000000000 // 2 billion, slightly lower for safety + MaxQuantity = 1000 // Maximum quantity per order ) diff --git a/internal/logic/public/order/purchaseLogic.go b/internal/logic/public/order/purchaseLogic.go index cbc960f..91bc834 100644 --- a/internal/logic/public/order/purchaseLogic.go +++ b/internal/logic/public/order/purchaseLogic.go @@ -58,6 +58,12 @@ func (l *PurchaseLogic) Purchase(req *types.PurchaseOrderRequest) (resp *types.P req.Quantity = 1 } + // Validate quantity limit + if req.Quantity > MaxQuantity { + l.Errorw("[Purchase] Quantity exceeds maximum limit", logger.Field("quantity", req.Quantity), logger.Field("max", MaxQuantity)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "quantity exceeds maximum limit of %d", MaxQuantity) + } + // find user subscription userSub, err := l.svcCtx.UserModel.QueryUserSubscribe(l.ctx, u.Id) if err != nil { @@ -110,6 +116,17 @@ func (l *PurchaseLogic) Purchase(req *types.PurchaseOrderRequest) (resp *types.P // discount amount amount := int64(float64(price) * discount) discountAmount := price - amount + + // Validate amount to prevent overflow + if amount > MaxOrderAmount { + l.Errorw("[Purchase] Order amount exceeds maximum limit", + logger.Field("amount", amount), + logger.Field("max", MaxOrderAmount), + logger.Field("user_id", u.Id), + logger.Field("subscribe_id", req.SubscribeId)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "order amount exceeds maximum limit") + } + var coupon int64 = 0 // Calculate the coupon deduction if req.Coupon != "" { @@ -167,6 +184,15 @@ func (l *PurchaseLogic) Purchase(req *types.PurchaseOrderRequest) (resp *types.P if amount > 0 { feeAmount = calculateFee(amount, payment) amount += feeAmount + + // Final validation after adding fee + if amount > MaxOrderAmount { + l.Errorw("[Purchase] Final order amount exceeds maximum limit after fee", + logger.Field("amount", amount), + logger.Field("max", MaxOrderAmount), + logger.Field("user_id", u.Id)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "order amount exceeds maximum limit") + } } // query user is new purchase or renewal isNew, err := l.svcCtx.OrderModel.IsUserEligibleForNewOrder(l.ctx, u.Id) diff --git a/internal/logic/public/order/rechargeLogic.go b/internal/logic/public/order/rechargeLogic.go index 04ff41c..a27053c 100644 --- a/internal/logic/public/order/rechargeLogic.go +++ b/internal/logic/public/order/rechargeLogic.go @@ -40,6 +40,21 @@ func (l *RechargeLogic) Recharge(req *types.RechargeOrderRequest) (resp *types.R logger.Error("current user is not found in context") return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") } + + // Validate recharge amount + if req.Amount <= 0 { + l.Errorw("[Recharge] Invalid recharge amount", logger.Field("amount", req.Amount), logger.Field("user_id", u.Id)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "recharge amount must be greater than 0") + } + + if req.Amount > MaxRechargeAmount { + l.Errorw("[Recharge] Recharge amount exceeds maximum limit", + logger.Field("amount", req.Amount), + logger.Field("max", MaxRechargeAmount), + logger.Field("user_id", u.Id)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "recharge amount exceeds maximum limit") + } + // find payment method payment, err := l.svcCtx.PaymentModel.FindOne(l.ctx, req.Payment) if err != nil { @@ -48,6 +63,17 @@ func (l *RechargeLogic) Recharge(req *types.RechargeOrderRequest) (resp *types.R } // Calculate the handling fee feeAmount := calculateFee(req.Amount, payment) + totalAmount := req.Amount + feeAmount + + // Validate total amount after adding fee + if totalAmount > MaxOrderAmount { + l.Errorw("[Recharge] Total amount exceeds maximum limit after fee", + logger.Field("amount", totalAmount), + logger.Field("max", MaxOrderAmount), + logger.Field("user_id", u.Id)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "total amount exceeds maximum limit") + } + // query user is new purchase or renewal isNew, err := l.svcCtx.OrderModel.IsUserEligibleForNewOrder(l.ctx, u.Id) if err != nil { @@ -59,7 +85,7 @@ func (l *RechargeLogic) Recharge(req *types.RechargeOrderRequest) (resp *types.R OrderNo: tool.GenerateTradeNo(), Type: 4, Price: req.Amount, - Amount: req.Amount + feeAmount, + Amount: totalAmount, FeeAmount: feeAmount, PaymentId: payment.Id, Method: payment.Platform, diff --git a/internal/logic/public/order/renewalLogic.go b/internal/logic/public/order/renewalLogic.go index c78824f..e384413 100644 --- a/internal/logic/public/order/renewalLogic.go +++ b/internal/logic/public/order/renewalLogic.go @@ -50,6 +50,12 @@ func (l *RenewalLogic) Renewal(req *types.RenewalOrderRequest) (resp *types.Rene req.Quantity = 1 } + // Validate quantity limit + if req.Quantity > MaxQuantity { + l.Errorw("[Renewal] Quantity exceeds maximum limit", logger.Field("quantity", req.Quantity), logger.Field("max", MaxQuantity)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "quantity exceeds maximum limit of %d", MaxQuantity) + } + orderNo := tool.GenerateTradeNo() // find user subscribe userSubscribe, err := l.svcCtx.UserModel.FindOneUserSubscribe(l.ctx, req.UserSubscribeID) @@ -75,6 +81,17 @@ func (l *RenewalLogic) Renewal(req *types.RenewalOrderRequest) (resp *types.Rene price := sub.UnitPrice * req.Quantity amount := int64(float64(price) * discount) discountAmount := price - amount + + // Validate amount to prevent overflow + if amount > MaxOrderAmount { + l.Errorw("[Renewal] Order amount exceeds maximum limit", + logger.Field("amount", amount), + logger.Field("max", MaxOrderAmount), + logger.Field("user_id", u.Id), + logger.Field("subscribe_id", sub.Id)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "order amount exceeds maximum limit") + } + var coupon int64 = 0 if req.Coupon != "" { couponInfo, err := l.svcCtx.CouponModel.FindOneByCode(l.ctx, req.Coupon) @@ -134,6 +151,15 @@ func (l *RenewalLogic) Renewal(req *types.RenewalOrderRequest) (resp *types.Rene amount += feeAmount + // Final validation after adding fee + if amount > MaxOrderAmount { + l.Errorw("[Renewal] Final order amount exceeds maximum limit after fee", + logger.Field("amount", amount), + logger.Field("max", MaxOrderAmount), + logger.Field("user_id", u.Id)) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidParams), "order amount exceeds maximum limit") + } + // create order orderInfo := order.Order{ UserId: u.Id, diff --git a/internal/types/types.go b/internal/types/types.go index 97042bd..45c46c9 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -323,14 +323,14 @@ type CreateNodeRequest struct { type CreateOrderRequest struct { UserId int64 `json:"user_id" validate:"required"` Type uint8 `json:"type" validate:"required"` - Quantity int64 `json:"quantity,omitempty"` - Price int64 `json:"price" validate:"required"` - Amount int64 `json:"amount" validate:"required"` - Discount int64 `json:"discount,omitempty"` + Quantity int64 `json:"quantity,omitempty" validate:"omitempty,lte=1000"` + Price int64 `json:"price" validate:"required,gte=0,lte=2000000000"` + Amount int64 `json:"amount" validate:"required,gte=0,lte=2147483647"` + Discount int64 `json:"discount,omitempty" validate:"omitempty,gte=0,lte=2000000000"` Coupon string `json:"coupon,omitempty"` - CouponDiscount int64 `json:"coupon_discount,omitempty"` - Commission int64 `json:"commission"` - FeeAmount int64 `json:"fee_amount" validate:"required"` + CouponDiscount int64 `json:"coupon_discount,omitempty" validate:"omitempty,gte=0,lte=2000000000"` + Commission int64 `json:"commission" validate:"gte=0,lte=2000000000"` + FeeAmount int64 `json:"fee_amount" validate:"required,gte=0,lte=2000000000"` PaymentId int64 `json:"payment_id" validate:"required"` TradeNo string `json:"trade_no,omitempty"` Status uint8 `json:"status,omitempty"` @@ -1548,7 +1548,7 @@ type PubilcVerifyCodeConfig struct { type PurchaseOrderRequest struct { SubscribeId int64 `json:"subscribe_id"` - Quantity int64 `json:"quantity" validate:"required,gt=0"` + Quantity int64 `json:"quantity" validate:"required,gt=0,lte=1000"` Payment int64 `json:"payment,omitempty"` Coupon string `json:"coupon,omitempty"` } @@ -1760,7 +1760,7 @@ type QuotaTask struct { } type RechargeOrderRequest struct { - Amount int64 `json:"amount"` + Amount int64 `json:"amount" validate:"required,gt=0,lte=2000000000"` Payment int64 `json:"payment"` } @@ -1790,7 +1790,7 @@ type RegisterLog struct { type RenewalOrderRequest struct { UserSubscribeID int64 `json:"user_subscribe_id"` - Quantity int64 `json:"quantity"` + Quantity int64 `json:"quantity" validate:"lte=1000"` Payment int64 `json:"payment"` Coupon string `json:"coupon,omitempty"` }