-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathstripehooks.go
128 lines (106 loc) · 2.98 KB
/
stripehooks.go
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
116
117
118
119
120
121
122
123
124
125
126
127
128
package stripehooks
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"github.com/stripe/stripe-go/v74"
"github.com/stripe/stripe-go/v74/webhook"
)
// Manager is the struct that holds the event handlers
type Manager struct {
verify bool // if true, verify the signature of the event
endpointSecret string
handlers map[EventType]HandlerFunc
}
// HandlerFunc is the function signature for the event handler
type HandlerFunc func(*stripe.Event) error
// Option is the function signature for the Manager options
type Option func(*Manager)
// WithVerify sets the verify option
func WithVerify(endpointSecret string) Option {
if endpointSecret == "" {
panic("endpointSecret cannot be empty in WithVerify")
}
return func(m *Manager) {
m.verify = true
m.endpointSecret = endpointSecret
}
}
// New returns a new Manager
func New(options ...Option) *Manager {
m := Manager{
handlers: make(map[EventType]HandlerFunc),
}
for _, option := range options {
option(&m)
}
return &m
}
// Event registers a handler for the given event type
func (m *Manager) Handle(eventType EventType, fn HandlerFunc) {
if m.handlers == nil {
m.handlers = make(map[EventType]HandlerFunc)
m.handlers[eventType] = fn
return
}
m.handlers[eventType] = fn
}
// ProcessEvent processes the event
func (m *Manager) ProcessEvent(payload []byte, signatureHeader string) error {
var event stripe.Event
var err error
if m.verify {
event, err = webhook.ConstructEvent(payload, signatureHeader, m.endpointSecret)
if err != nil {
return fmt.Errorf("error verifying webhook signature: %v", err)
}
} else {
if err := json.Unmarshal(payload, &event); err != nil {
return fmt.Errorf("error unmarshalling event: %v", err)
}
}
fn, ok := m.handlers[EventType(event.Type)]
if !ok {
return nil
}
if err := fn(&event); err != nil {
return fmt.Errorf("error handling event: %v", err)
}
return nil
}
// HttpHandler returns an http.HandlerFunc
func (m *Manager) HttpHandler(errFn func(err error)) http.HandlerFunc {
if errFn != nil {
// if errFn is nil, set it to a no-op function
errFn = func(err error) {}
}
return func(w http.ResponseWriter, r *http.Request) {
payload, err := io.ReadAll(r.Body)
if err != nil {
httpErrorHandler(w, fmt.Errorf("error reading request body: %v", err))
errFn(err)
return
}
signatureHeader := r.Header.Get("Stripe-Signature")
if err := m.ProcessEvent(payload, signatureHeader); err != nil {
httpErrorHandler(w, fmt.Errorf("error processing event: %v", err))
errFn(err)
return
}
w.WriteHeader(http.StatusOK)
if _, err := w.Write([]byte("OK")); err != nil {
httpErrorHandler(w, fmt.Errorf("error writing response: %v", err))
errFn(err)
return
}
}
}
// httpErrorHandler handles the error and writes it to the response
func httpErrorHandler(w http.ResponseWriter, err error) {
w.WriteHeader(http.StatusInternalServerError)
if _, err := w.Write([]byte(err.Error())); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err)
}
}