package httpapi import ( "bytes" "context" "crypto/hmac" "crypto/sha256" "encoding/hex" "encoding/json" "errors" "io" "log/slog" "net/http" "strconv" "strings" "time" "data-terminal-cloud/internal/diagnostics" ) const ( HeaderPlatformTimestamp = "X-Platform-Timestamp" HeaderPlatformSignature = "X-Platform-Signature" ) type PlatformHealthProcessor interface { IngestPlatformHealth(context.Context, diagnostics.PlatformHealthInput, []byte, time.Time) (diagnostics.PlatformHealthReceipt, error) } func PlatformHealthCallbackHandler(secret []byte, maxSkew time.Duration, processor PlatformHealthProcessor) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { r.Body = http.MaxBytesReader(w, r.Body, 64*1024) rawBody, err := io.ReadAll(r.Body) if err != nil { WriteError(w, r, http.StatusBadRequest, "INVALID_PLATFORM_HEALTH_REPORT", "服务器健康报告无法读取") return } now := time.Now().UTC() if !verifyPlatformHealthSignature(secret, r.Header.Get(HeaderPlatformTimestamp), r.Header.Get(HeaderPlatformSignature), rawBody, now, maxSkew) { WriteError(w, r, http.StatusUnauthorized, "PLATFORM_HEALTH_AUTHENTICATION_FAILED", "服务器健康报告身份验证失败") return } decoder := json.NewDecoder(bytes.NewReader(rawBody)) decoder.DisallowUnknownFields() var input diagnostics.PlatformHealthInput if err = decoder.Decode(&input); err != nil || ensureJSONEOF(decoder) != nil { WriteError(w, r, http.StatusBadRequest, "INVALID_PLATFORM_HEALTH_REPORT", "服务器健康报告字段不正确") return } receipt, err := processor.IngestPlatformHealth(r.Context(), input, rawBody, now) if err != nil { if errors.Is(err, diagnostics.ErrInvalid) { WriteError(w, r, http.StatusBadRequest, "INVALID_PLATFORM_HEALTH_REPORT", "服务器健康报告字段不正确") return } slog.ErrorContext(r.Context(), "platform health callback processing failed", "error", err) WriteAPIError(w, r, http.StatusServiceUnavailable, Error{Code: "PLATFORM_HEALTH_UNAVAILABLE", Message: "服务器健康报告暂时无法处理", Retryable: true}) return } status := http.StatusCreated if receipt.Duplicate { status = http.StatusOK } w.Header().Set("Cache-Control", "no-store") WriteJSON(w, r, status, receipt) }) } func verifyPlatformHealthSignature(secret []byte, timestamp, signature string, body []byte, now time.Time, maxSkew time.Duration) bool { if len(secret) < 32 || maxSkew <= 0 || timestamp == "" || !strings.HasPrefix(signature, "sha256=") { return false } epoch, err := strconv.ParseInt(timestamp, 10, 64) if err != nil || absDuration(now.Sub(time.Unix(epoch, 0))) > maxSkew { return false } provided, err := hex.DecodeString(strings.TrimPrefix(signature, "sha256=")) if err != nil { return false } mac := hmac.New(sha256.New, secret) _, _ = mac.Write([]byte(timestamp)) _, _ = mac.Write([]byte(".")) _, _ = mac.Write(body) return hmac.Equal(provided, mac.Sum(nil)) } func absDuration(value time.Duration) time.Duration { if value < 0 { return -value } return value }