Files
affiliate_dash/backend/internal/service/delivery_link.go
T
yml2213 2264851d5d 拆分 service 与前端大文件,修复 CORS 配置与格式问题
- 后端 internal/service 按职责拆分:
  fulfillment.go(1397→527)拆出 wallet/timeout/data/order/query/dashboard/shipnotify
  delivery.go(1124→801)拆出 upstream/link/state/helpers
  merchant.go(855→251)拆出 member/product/api_client/catalog/helpers
- 前端 MerchantCenter.tsx(1327→606)拆出 merchantCenterTabs/merchantCenterUtils
- docker-compose backend 透传 CORS_ALLOWED_ORIGINS
- CORS 白名单实现(config/router/README/.env.example 配套)
- 修复 gofmt 与文件尾部多余空行
2026-08-05 13:32:11 +08:00

75 lines
2.4 KiB
Go

package service
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"affiliate_dash/internal/model"
)
func (s *DeliveryService) authorizeDeliveryLink(order *model.FulfillmentOrder, auth DeliveryLinkAuth) error {
if order == nil {
return newDeliveryHTTPError(http.StatusNotFound, "订单不存在")
}
if auth.Exp <= 0 || strings.TrimSpace(auth.Sign) == "" {
return newDeliveryHTTPError(http.StatusForbidden, "链接参数缺失")
}
if order.DeliveryLinkRevokedAt != nil {
return newDeliveryHTTPError(http.StatusForbidden, "发货链接已作废")
}
if order.DeliveryLinkExpiresAt == nil {
return newDeliveryHTTPError(http.StatusForbidden, "发货链接未生成")
}
expiresAt := order.DeliveryLinkExpiresAt.UTC().Truncate(time.Second)
linkExpires := time.Unix(auth.Exp, 0).UTC()
if !linkExpires.Equal(expiresAt) {
return newDeliveryHTTPError(http.StatusForbidden, "发货链接已失效")
}
if time.Now().UTC().After(linkExpires) {
return newDeliveryHTTPError(http.StatusForbidden, "发货链接已过期")
}
expected := s.signDeliveryLink(order.OrderNo, auth.Exp)
if !hmac.Equal([]byte(strings.ToLower(strings.TrimSpace(auth.Sign))), []byte(expected)) {
return newDeliveryHTTPError(http.StatusForbidden, "发货链接签名无效")
}
return nil
}
func (s *DeliveryService) buildDeliveryLinkResult(orderNo string, expiresAt time.Time, requestBaseURL string) *DeliveryLinkResult {
expiresAt = expiresAt.UTC()
exp := expiresAt.Unix()
sign := s.signDeliveryLink(orderNo, exp)
return &DeliveryLinkResult{
OrderNo: orderNo,
DeliveryURL: s.buildDeliveryURL(orderNo, exp, sign, requestBaseURL),
ExpiresAt: expiresAt,
Exp: exp,
Sign: sign,
}
}
func (s *DeliveryService) buildDeliveryURL(orderNo string, exp int64, sign, requestBaseURL string) string {
path := fmt.Sprintf("/delivery/%s/%s?exp=%d&sign=%s", url.PathEscape(s.channel), url.PathEscape(orderNo), exp, url.QueryEscape(sign))
base := strings.TrimRight(s.linkBaseURL, "/")
if base == "" {
base = strings.TrimRight(requestBaseURL, "/")
}
if base == "" {
return path
}
return base + path
}
func (s *DeliveryService) signDeliveryLink(orderNo string, exp int64) string {
mac := hmac.New(sha256.New, []byte(s.linkSecret))
_, _ = mac.Write([]byte(orderNo + "|" + strconv.FormatInt(exp, 10)))
return hex.EncodeToString(mac.Sum(nil))
}