-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcontext_webhook_helpers.go
More file actions
115 lines (102 loc) · 2.73 KB
/
context_webhook_helpers.go
File metadata and controls
115 lines (102 loc) · 2.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Package gin 提供基于 Gin 的增强上下文与相关组件。
package gin
import (
"bytes"
"io"
"strings"
)
const rawBodyCacheKey = "__darkit_raw_body"
var (
defaultWebhookEventIDHeaders = []string{
"X-Webhook-Id",
"Webhook-Id",
"X-Event-ID",
"Event-Id",
"X-GitHub-Delivery",
"X-Shopify-Webhook-Id",
"Svix-Id",
}
defaultWebhookSignatureHeaders = []string{
"X-Signature",
"X-Hub-Signature-256",
"X-Hub-Signature",
"Stripe-Signature",
"X-Shopify-Hmac-Sha256",
"Svix-Signature",
}
defaultWebhookTimestampHeaders = []string{
"X-Timestamp",
"X-Signature-Timestamp",
"Webhook-Timestamp",
"Svix-Timestamp",
}
)
// RawBody 读取并缓存原始请求体,便于验签或重复绑定。
func (c *Context) RawBody() ([]byte, error) {
if c == nil || c.Request == nil {
return nil, nil
}
if cached, exists := c.Get(rawBodyCacheKey); exists {
if body, ok := cached.([]byte); ok {
return append([]byte(nil), body...), nil
}
}
if c.Request.Body == nil {
return nil, nil
}
body, err := io.ReadAll(c.Request.Body)
if err != nil {
return nil, err
}
c.Request.Body = io.NopCloser(bytes.NewReader(body))
c.Set(rawBodyCacheKey, append([]byte(nil), body...))
return append([]byte(nil), body...), nil
}
// MustRawBody 读取原始请求体,失败时直接 panic。
func (c *Context) MustRawBody() []byte {
body, err := c.RawBody()
if err != nil {
panic(err)
}
return body
}
// RawBodyString 以字符串形式返回原始请求体。
func (c *Context) RawBodyString() (string, error) {
body, err := c.RawBody()
if err != nil {
return "", err
}
return string(body), nil
}
// WebhookEventID 按常见头优先级提取 webhook 事件 ID。
func (c *Context) WebhookEventID(headers ...string) string {
return c.headerByPriority(defaultWebhookEventIDHeaders, headers...)
}
// WebhookSignature 按常见头优先级提取 webhook 签名值。
func (c *Context) WebhookSignature(headers ...string) string {
return c.headerByPriority(defaultWebhookSignatureHeaders, headers...)
}
// WebhookTimestamp 按常见头优先级提取 webhook 时间戳。
func (c *Context) WebhookTimestamp(headers ...string) string {
return c.headerByPriority(defaultWebhookTimestampHeaders, headers...)
}
func (c *Context) headerByPriority(defaults []string, custom ...string) string {
headerNames := append([]string(nil), custom...)
headerNames = append(headerNames, defaults...)
seen := make(map[string]struct{}, len(headerNames))
for _, name := range headerNames {
trimmed := strings.TrimSpace(name)
if trimmed == "" {
continue
}
key := strings.ToLower(trimmed)
if _, exists := seen[key]; exists {
continue
}
seen[key] = struct{}{}
if value := c.GetHeader(trimmed); value != "" {
return value
}
}
return ""
}