-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathwebhook.go
149 lines (130 loc) · 3.76 KB
/
webhook.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package messengerbot
import (
"crypto/hmac"
"crypto/sha1"
"encoding/json"
"fmt"
log "github.com/Sirupsen/logrus"
"io/ioutil"
"net/http"
)
type rawEvent struct {
Object string `json:"object"`
Entries []*MessageEvent `json:"entry"`
}
type Event struct {
Id json.Number `json:"id"`
Time json.Number `json:"time"`
}
type MessageEvent struct {
Event
Messaging []struct {
MessageOpts
Message *ReceivedMessage `json:"message,omitempty"`
Delivery *Delivery `json:"delivery,omitempty"`
Postback *Postback `json:"postback,omitempty"`
Optin *Optin `json:"optin,empty"`
} `json:"messaging"`
}
type ReceivedMessage struct {
Message
Id string `json:"mid"`
Seq int `json:"seq"`
Attachments []Attachment `json:"attachments"`
}
type Delivery struct {
MessageIds []string `json:"mids"`
Watermark int64 `json:"watermark"`
Seq int `json:"seq"`
}
type Postback struct {
Payload string `json:"payload"`
}
type Optin struct {
Ref string `json:"ref"`
}
type MessageOpts struct {
Sender struct {
ID string `json:"id"`
} `json:"sender"`
Recipient struct {
ID string `json:"id"`
} `json:"recipient"`
Timestamp int64 `json:"timestamp"`
}
type MessageReceivedHandler func(*MessengerBot, Event, MessageOpts, ReceivedMessage)
type MessageDeliveredHandler func(*MessengerBot, Event, MessageOpts, Delivery)
type PostbackHandler func(*MessengerBot, Event, MessageOpts, Postback)
type AuthenticationHandler func(*MessengerBot, Event, MessageOpts, *Optin)
// Handler is the main HTTP handler for the Messenger service.
// It must be attached to some web server in order to receive messages
func (bot *MessengerBot) Handler(rw http.ResponseWriter, req *http.Request) {
if req.Method == "GET" {
query := req.URL.Query()
if query.Get("hub.verify_token") != bot.VerifyToken {
rw.WriteHeader(http.StatusUnauthorized)
return
}
rw.WriteHeader(http.StatusOK)
rw.Write([]byte(query.Get("hub.challenge")))
} else if req.Method == "POST" {
bot.handlePOST(rw, req)
} else {
rw.WriteHeader(http.StatusMethodNotAllowed)
}
}
func (bot *MessengerBot) handlePOST(rw http.ResponseWriter, req *http.Request) {
read, err := ioutil.ReadAll(req.Body)
if err != nil {
log.Error(err)
rw.WriteHeader(http.StatusBadRequest)
return
}
//Message integrity check
if bot.AppSecret != "" {
if !checkIntegrity(bot.AppSecret, read, req.Header.Get("x-hub-signature")[5:]) {
log.Error("Failed x-hub-signature integrity check")
rw.WriteHeader(http.StatusBadRequest)
return
}
}
event := &rawEvent{}
err = json.Unmarshal(read, event)
if err != nil {
log.Error("Couldn't parse fb json:" + err.Error())
rw.WriteHeader(http.StatusBadRequest)
return
}
for _, entry := range event.Entries {
for _, message := range entry.Messaging {
if message.Delivery != nil {
if bot.MessageDelivered != nil {
go bot.MessageDelivered(bot, entry.Event, message.MessageOpts, *message.Delivery)
}
} else if message.Message != nil {
if bot.MessageReceived != nil {
go bot.MessageReceived(bot, entry.Event, message.MessageOpts, *message.Message)
}
} else if message.Postback != nil {
if bot.Postback != nil {
go bot.Postback(bot, entry.Event, message.MessageOpts, *message.Postback)
}
} else if bot.Authentication != nil {
go bot.Authentication(bot, entry.Event, message.MessageOpts, message.Optin)
}
}
}
rw.WriteHeader(http.StatusOK)
rw.Write([]byte(`{"status":"ok"}`))
}
func checkIntegrity(appSecret string, bytes []byte, expectedSignature string) bool {
mac := hmac.New(sha1.New, []byte(appSecret))
if fmt.Sprintf("%x", mac.Sum(bytes)) != expectedSignature {
return false
}
return true
}
func (r *ReceivedMessage) IsHaveAttachment() bool {
if len(r.Attachments) == 0 {return false}
return true
}