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)) }