Skip to content

Instantly share code, notes, and snippets.

@kevinswiber
Created May 21, 2020 17:01
Show Gist options
  • Save kevinswiber/9b7c601b64f025a20e55968901b09cc0 to your computer and use it in GitHub Desktop.
Save kevinswiber/9b7c601b64f025a20e55968901b09cc0 to your computer and use it in GitHub Desktop.
Twitch Webhook
const crypto = require('crypto');
const http = require('http');
const server = http.createServer(async (req, res) => {
if (req.method === 'GET') {
return handleSubscriptionVerification(req, res);
} else if (req.method === 'POST') {
return await handleEventNotification(req, res);
}
res.statusCode = 400;
res.end();
})
server.on('listening', () => {
log(`=> Twitch Webhook Server running on ${JSON.stringify(server.address())}`);
});
server.listen(process.env.PORT || 3000);
const handleSubscriptionVerification = (req, res) => {
const parsed = new URL(req.url, `http://${req.headers.host}`);
const mode = parsed.searchParams.get('hub.mode');
const challenge = parsed.searchParams.get('hub.challenge');
log(`=> Receiving subscription verification, { mode: "${mode}", challenge: "${challenge}" }`);
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end(challenge);
}
const handleEventNotification = async (req, res) => {
console.log(req.url);
console.log(req.headers);
req.setEncoding('utf8');
let input = '';
for await (const chunk of req) {
input += chunk
}
const secret = '<secret>';
const signatureHeader = req.headers['x-hub-signature'] || '';
const [algorithm, signature] = signatureHeader.split('=');
if (algorithm !== 'sha256' || !signature) {
log(`=> Event notification, invalid hub signature!`);
res.statusCode = 400;
res.end();
return;
}
const digest = crypto.createHmac('sha256', secret)
.update(input)
.digest('hex');
if (signature !== digest) {
log(`=> Event notification, invalid hub signature or secret!`);
res.statusCode = 400;
res.end();
return;
}
inputJSON = JSON.parse(input);
console.log(inputJSON);
if (inputJSON && inputJSON.data && inputJSON.data.length) {
log(`Stream is live, { title: "${inputJSON.data[0].title}" }`);
} else {
log('Stream has ended.');
}
res.statusCode = 204;
res.end();
};
const log = (msg) => {
console.log(new Date(), `=> ${msg}`);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment