-
Notifications
You must be signed in to change notification settings - Fork 2
/
app.js
220 lines (193 loc) · 6.39 KB
/
app.js
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
/**
* Copyright 2021-present, Facebook, Inc. All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*
*/
"use strict";
// Import dependencies and set up http server
const express = require("express"),
{ urlencoded, json } = require("body-parser"),
crypto = require("crypto"),
path = require("path"),
Receive = require("./services/receive"),
GraphApi = require("./services/graph-api"),
User = require("./services/user"),
config = require("./services/config"),
i18n = require("./i18n.config"),
app = express();
// Object to store known users.
var users = {};
// Parse application/x-www-form-urlencoded
app.use(
urlencoded({
extended: true
})
);
// Parse application/json. Verify that callback came from Facebook
app.use(json({ verify: verifyRequestSignature }));
// Serving static files in Express
app.use(express.static(path.join(path.resolve(), "public")));
// Find the URL we're serving from
app.all("*", function(req, res, next) {
// "x-forwarded-proto" will have https even when tunnelling to local
const reqProtocol = req.get("x-forwarded-proto")
? req.get("x-forwarded-proto").split(",")[0]
: req.get("protocol");
const reqAppUrl = reqProtocol + "://" + req.get("host");
if (config.appUrl != reqAppUrl) {
config.appUrl = reqAppUrl;
console.log(`Updated appUrl to ${config.appUrl}`);
}
next();
});
// Respond with index file when a GET request is made to the homepage
app.get("/", function(_req, res) {
res.sendFile(path.join(__dirname, "public/index.html"));
});
// Add support for GET requests to our webhook
// Used to verify the webhook
app.get("/webhook", (req, res) => {
// Parse the query params
console.log("Got /webhook");
let mode = req.query["hub.mode"];
let token = req.query["hub.verify_token"];
let challenge = req.query["hub.challenge"];
// Check if a token and mode is in the query string of the request
if (mode && token) {
// Checks the mode and token sent is correct
if (mode === "subscribe" && token === config.verifyToken) {
// Responds with the challenge token from the request
console.log("WEBHOOK_VERIFIED");
res.status(200).send(challenge);
} else {
// Responds with '403 Forbidden' if verify tokens do not match
res.sendStatus(403);
}
} else {
console.warn("Got /webhook but without needed parameters.");
}
});
// Add support for POST requests to our webhook
// Called whenever messages occur in the conversation.
app.post("/webhook", (req, res) => {
let body = req.body;
console.log(`\u{1F7EA} Received webhook:`);
console.dir(body, { depth: null });
// Check if this is an event from a page subscription
if (body.object === "instagram") {
// Return a '200 OK' response to all requests
res.status(200).send("EVENT_RECEIVED");
// Iterate over each entry - there may be multiple if batched
body.entry.forEach(async function(entry) {
// Handle Page Changes event
if ("changes" in entry) {
let receiveMessage = new Receive();
if (entry.changes[0].field === "comments") {
let change = entry.changes[0].value;
if (entry.changes[0].value) console.log("Got a comments event");
return receiveMessage.handlePrivateReply("comment_id", change.id);
}
}
if (!("messaging" in entry)) {
console.warn("No messaging field in entry. Possibly a webhook test.");
return;
}
// Iterate over webhook events - there may be multiple
entry.messaging.forEach(async function(webhookEvent) {
// Discard uninteresting events
if (
"message" in webhookEvent &&
webhookEvent.message.is_echo === true
) {
console.log("Got an echo");
return;
}
// Get the sender IGSID
let senderIgsid = webhookEvent.sender.id;
if (!(senderIgsid in users)) {
// First time seeing this user
let user = new User(senderIgsid);
let userProfile = await GraphApi.getUserProfile(senderIgsid);
if (userProfile) {
user.setProfile(userProfile);
users[senderIgsid] = user;
console.log(`Created new user profile`);
console.dir(user);
}
}
let receiveMessage = new Receive(users[senderIgsid], webhookEvent);
return receiveMessage.handleMessage();
});
});
} else if (body.object === "page") {
// Catch if the event came from Messenger webhook instead of Instagram
console.warn(
`Received Messenger "page" object instead of "instagram" message webhook.`
);
res.sendStatus(404);
} else {
// Return a '404 Not Found' if event is not recognized
console.warn(`Unrecognized POST to webhook.`);
res.sendStatus(404);
}
});
// Verify that the callback came from Facebook.
function verifyRequestSignature(req, res, buf) {
const signature = req.headers["x-hub-signature"];
if (!signature) {
console.warn(`Couldn't find "x-hub-signature" in headers.`);
} else {
const elements = signature.split("=");
const signatureHash = elements[1];
const expectedHash = crypto
.createHmac("sha1", config.appSecret)
.update(buf)
.digest("hex");
if (signatureHash != expectedHash) {
throw new Error(
"Couldn't validate the request signature. Confirm your App Secret."
);
}
}
}
async function main() {
// Check if all environment variables are set
config.checkEnvVariables();
// Set configured locale
if (config.locale) {
i18n.setLocale(config.locale);
}
const iceBreakers = [
// {
// question: i18n.__("menu.support"),
// payload: "CARE_SALES"
// },
// {
// question: i18n.__("menu.order"),
// payload: "SEARCH_ORDER"
// },
// {
// question: i18n.__("menu.help"),
// payload: "CARE_HELP"
// },
// {
// question: i18n.__("menu.suggestion"),
// payload: "CURATION"
// }
{
question: i18n.__("menu.start"),
payload: "GET_CHECKLIST"
},
];
// Set our Icebreakers upon launch
await GraphApi.setIcebreakers(iceBreakers);
// Set our page subscriptions
await GraphApi.setPageSubscriptions();
// Listen for requests :)
var listener = app.listen(config.port, function() {
console.log(`The app is listening on port ${listener.address().port}`);
});
}
main();