JavaScript Webhook ReceiverΒΆ

Download webhook.js

/*
 * Debugging webhook receiver endpoint.
 *
 * $ openssl req -x509 -newkey rsa:4096 -keyout sslkey.pem -out sslcert.pem -nodes -subj '/CN=localhost'
 * $ node webhook.js SECRET sslkey.pem sslcert.pem
 *
 * To test using api key "SECRET":
 * $ curl -k -v --header "X-Signature: 3q8QXTAGaey18yL8FWTqdVlbMr6hcuNvM4tefa0o9nA=" --data '{}' https://localhost:8443/sent
 */

var https = require('https');
var fs = require('fs');
var crypto = require('crypto');
const PORT = 8443; 

function handleRequest(request, response){
    console.log("Request %s", request.url);

    var body = [];
    request.on('data', function (chunk) {
        body.push(chunk);
    })
    .on('end', function () {
        body = Buffer.concat(body);
        console.log("Body: %s", body.toString());
        var signature = request.headers["x-signature"];
        if (!signature) {
            console.warn("No signature supplied, forbidden");
            response.writeHead(403);
            response.end();
            return;
        }
        var hmac = crypto.createHmac('sha256', apiKey);
        hmac.update(body);
        var computedSignature = hmac.digest('base64');
        if (signature != computedSignature) {
            console.warn("Signature does not match, forbidden (%s != %s)", signature, computedSignature);
            response.writeHead(403);
            response.end();
            return;
        }
        console.log("Signature validated");
        response.writeHead(204);
        response.end();
    });
}

if (process.argv.length <= 4) {
    console.error("Usage: node webhook.js <api-key> <sslkey-path> <sslcert-path>");
    process.exit(1);
}
var apiKey = process.argv[2];

const options = {
    key: fs.readFileSync(process.argv[3]),
    cert: fs.readFileSync(process.argv[4])
};
var server = https.createServer(options, handleRequest);
server.listen(PORT, function(){
    console.log("Server listening on port %s api key %s", PORT, apiKey);
});