const crypto = require('crypto')
const express = require('express');
const app = express();
const port = 443;
const axios = require('axios')
const TWITCH_MESSAGE_ID = 'Twitch-Eventsub-Message-Id'.toLowerCase();
const TWITCH_MESSAGE_TIMESTAMP = 'Twitch-Eventsub-Message-Timestamp'.toLowerCase();
const TWITCH_MESSAGE_SIGNATURE = 'Twitch-Eventsub-Message-Signature'.toLowerCase();
const MESSAGE_TYPE = 'Twitch-Eventsub-Message-Type'.toLowerCase();
const MESSAGE_TYPE_VERIFICATION = 'webhook_callback_verification';
const MESSAGE_TYPE_NOTIFICATION = 'notification';
const MESSAGE_TYPE_REVOCATION = 'revocation';
const HMAC_PREFIX = 'sha256=';
const clientSecret = "********";
const clientID = "********";
const options = {
url: 'https://id.twitch.tv/oauth2/token',
headers: {
'Content-Type': 'application/json'
},
method: 'POST',
body: JSON.stringify({
client_id: clientID,
client_secret: clientSecret,
grant_type: 'client_credentials',
})
}
app.use(express.raw({
type: 'application/json'
}))
app.post('/eventsub', (req, res) => {
let secret = getSecret();
let message = getHmacMessage(req);
let hmac = HMAC_PREFIX + getHmac(secret, message);
if (true === verifyMessage(hmac, req.headers[TWITCH_MESSAGE_SIGNATURE])) {
console.log("signatures match");
let notification = JSON.parse(req.body);
if (MESSAGE_TYPE_NOTIFICATION === req.headers[MESSAGE_TYPE]) {
console.log(`Event type: ${notification.subscription.type}`);
console.log(JSON.stringify(notification.event, null, 4));
res.sendStatus(204);
}
else if (MESSAGE_TYPE_VERIFICATION === req.headers[MESSAGE_TYPE]) {
res.set('Content-Type', 'text/plain').status(200).send(notification.challenge);
}
else if (MESSAGE_TYPE_REVOCATION === req.headers[MESSAGE_TYPE]) {
res.sendStatus(204);
console.log(`${notification.subscription.type} notifications revoked!`);
console.log(`reason: ${notification.subscription.status}`);
console.log(`condition: ${JSON.stringify(notification.subscription.condition, null, 4)}`);
}
else {
res.sendStatus(204);
console.log(`Unknown message type: ${req.headers[MESSAGE_TYPE]}`);
}
}
else {
console.log('403');
res.sendStatus(403);
}
fetch(options.url, options)
.then(response => response.json())
.then(data => {
console.log(data)
axios({
method: "POST",
url: "https://api.twitch.tv/helix/eventsub/subscriptions",
headers: {
"Content-Type": "application/json",
'Client-Id': "********",
'Authorization': `Bearer ${data.access_token}`
},
data: {
"type": "stream.online",
"version" : "1",
"condition" : {
"broadcaster_user_id": "38746172"
},
"transport": {
"method": "webhook",
"callback": "http://localhost:443/eventsub",
"secret" : "clientSecret"
}
}
})
.then((res) => {
console.log(res.data)
})
.catch((error) => {
{
console.log(error)
}
});
})
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
})
function getSecret() {
return 'a02v9ped9xqd3l0lg4ktu6p5mxzt9v';
}
function getHmacMessage(request) {
return (request.headers[TWITCH_MESSAGE_ID] +
request.headers[TWITCH_MESSAGE_TIMESTAMP] +
request.body);
}
function getHmac(secret, message) {
return crypto.createHmac('sha256', secret)
.update(message)
.digest('hex');
}
function verifyMessage(hmac, verifySignature) {
return crypto.timingSafeEqual(Buffer.from(hmac), Buffer.from(verifySignature));
}