Skip to content

Instantly share code, notes, and snippets.

@stripethree
Created November 1, 2016 17:48
Show Gist options
  • Save stripethree/e22d6d9a095bddca0ba76d60e2ffe798 to your computer and use it in GitHub Desktop.
Save stripethree/e22d6d9a095bddca0ba76d60e2ffe798 to your computer and use it in GitHub Desktop.
/*
Example Facebook Messenger app that pulls the user's public profile and echoes back any messages sent
with the user's first and last name.
So if I sent the bot "Good morning!" it will reply to me with "Echoing message from Jeff Israel: Good morning!"
*/
const bodyParser = require('body-parser');
const crypto = require('crypto');
const express = require('express');
const reqPromise = require('request-promise');
const facebookHookUrl = '/webhook';
const graphApiUrl = 'https://graph.facebook.com/v2.6';
const FB_ACCESS_TOKEN = process.env.MESSENGER_PAGE_ACCESS_TOKEN;
const FB_APP_SECRET = process.env.MESSENGER_APP_SECRET;
const FB_VERIFY_TOKEN = process.env.MESSENGER_VALIDATION_TOKEN;
const app = express();
function sendPayload(recipientId, payload) {
const msgJson = {
message: payload,
recipient: { id: recipientId }
};
const options = {
json: msgJson,
method: 'POST',
qs: { access_token: FB_ACCESS_TOKEN },
url: graphApiUrl + '/me/messages'
};
reqPromise(options)
.then((jsonString) => {
// TODO: parse the jsonString and act on returned data if needed
console.log(jsonString);
})
.catch((err) => {
// TODO: better error handling
throw err;
});
}
function sendMessage(senderId, text) {
const messageData = { text: text };
sendPayload(senderId, messageData);
}
function verifyRequestSignature(req, res, buf) {
var signature = req.headers['x-hub-signature'];
// I would probably not would log the FB_APP_SECRET in a non-dev env...
if (!signature) {
console.error('Couldn\'t validate the signature with app secret:' + FB_APP_SECRET);
} else {
const elements = signature.split('=');
const signatureHash = elements[1];
const expectedHash = crypto.createHmac('sha1', FB_APP_SECRET)
.update(buf)
.digest('hex');
if (signatureHash !== expectedHash) {
throw new Error('Couldn\'t validate the request signature: ' + FB_APP_SECRET);
}
}
}
app.use(bodyParser.json());
app.use(bodyParser.json({ verify: verifyRequestSignature }));
app.use(bodyParser.urlencoded({ extended: true }));
// nice to have as a simple check that the app is running in addition to the initial logs
app.get('/', (req, res) => {
res.send('Hello.');
});
// Facebook Messenger verification
app.get(facebookHookUrl, (req, res) => {
console.log(FB_VERIFY_TOKEN);
if (req.query['hub.verify_token'] === FB_VERIFY_TOKEN) {
res.send(req.query['hub.challenge']);
}
res.send('Error, wrong token');
});
app.post(facebookHookUrl, (req, res) => {
const data = req.body;
if (data.object === 'page') {
data.entry.forEach(function (pageEntry) {
pageEntry.messaging.forEach(function (messagingEvent) {
if (messagingEvent.message) {
// we've got a messaging event!
if (messagingEvent.message.is_echo) {
// https://developers.facebook.com/docs/messenger-platform/webhook-reference/message-echo
// these are messages sent by the page back to the user
console.log('Is there an echo in here?');
} else if (messagingEvent.message && messagingEvent.message.text) {
// setup options for call to Graph API for public profile
const options = {
qs: {
access_token: FB_ACCESS_TOKEN,
fields: 'first_name,last_name,profile_pic,locale,timezone,gender'
},
url: `${graphApiUrl}/${messagingEvent.sender.id}`
};
// call the Graph API!
reqPromise(options)
.then((jsonString) => {
const jsonObj = JSON.parse(jsonString);
const message = `Echoing message from ${jsonObj.first_name} ${jsonObj.last_name}: ${messagingEvent.message.text}`;
sendMessage(messagingEvent.sender.id, message);
})
.catch((err) => {
throw err;
});
}
}
});
});
}
res.sendStatus(200);
});
app.set('port', process.env.PORT || 3000);
app.listen(app.get('port'), function (err) {
if (err) throw err;
console.log('Server running on port ' + app.get('port'));
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment