old_contents: /**
   * Copyright: (c) 2016 Max Klein
   * License: MIT
   */
  
  const http = require('http');
  const crypto = require('crypto');
  
  const config = require('./config');
  
  function verifySignature(payload, signature, secret) {
  	const equalsIndex = signature.indexOf('=');
  	if(equalsIndex === -1) {
  		return false;
  	}
  	const algorithm = signature.slice(0, equalsIndex);
  	const receivedDigest = Buffer.from(signature.slice(equalsIndex + 1));
  	const calculatedDigest = crypto.createHmac(algorithm, secret).update(payload).digest();
  	return crypto.timingSafeEquals(calculatedDigest, digest);
  }
  
  function readBody(req) {
  	return new Promise(function (resolve, reject) {
  		const chunks = [];
  		req.on('data', function (chunk) {
  			chunks.push(chunk);
  		});
  		req.on('end', function () {
  			const body = Buffer.concat(chunks).toString();
  			resolve(body);
  		});
  		req.on('error', function (err) {
  			reject(err);
  		});
  	});
  }
  
  class HttpError extends Error {
  	constructor(statusCode, message) {
  		super(http.STATUS_CODES[statusCode] + message ? ': ' + message : '');
  		Object.defineProperties(this, {
  			name: {
  				value: this.constructor.name,
  				enumerable: false
  			},
  			httpStatus: {
  				value: statusCode,
  				enumerable: false
  			}
  		});
  	}
  }
  
  async function handleRequest(req, res) {
  	if(req.method !== 'POST') {
  		throw new HttpError(404);
  	}
  
  	const headers = req.headers;
  	const eventName = headers['x-github-event'];
  	const signature = headers['x-hub-signature'];
  
  	const body = await readBody(req);
  	if(!verifySignature(body, signature, config.secret)) {
  		throw new HttpError(400, 'Signature does not match');
  	}
  
  	const payload = JSON.parse(body);
  	if(eventName === 'push') {
  		console.log('Push to %s', payload.repository.name);
  	} else if(eventName === 'ping') {
  		console.log('Ping from %s', payload.repository.name);
  	} else {
  		throw new HttpError(400, 'Invalid event');
  	}
  }
  
  const server = http.createServer(function (req, res) {
  	let ret;
  	try {
  		ret = handleRequest(req, res);
  	} catch(err) {
  		ret = Promise.reject(err);
  	}
  	Promise.resolve(ret)
  		.then(function () {
  			res.end();
  		}, function (err) {
  			console.error(err);
  
  			res.statusCode = err.httpStatus || 500;
  			res.end();
  		});
  }).listen(config.port);
  
new_contents: /**
   * Copyright: (c) 2016 Max Klein
   * License: MIT
   */
  
  const http = require('http');
  const crypto = require('crypto');
  
  const config = require('./config');
  
  function verifySignature(payload, signature, secret) {
  	const equalsIndex = signature.indexOf('=');
  	if(equalsIndex === -1) {
  		return false;
  	}
  	const algorithm = signature.slice(0, equalsIndex);
  	const receivedDigest = Buffer.from(signature.slice(equalsIndex + 1));
  	const hmac = crypto.createHmac(algorithm, secret)
  	hmac.update(payload);
  	const calculatedDigest = hmac.digest();
  	return crypto.timingSafeEquals(calculatedDigest, digest);
  }
  
  function readBody(req) {
  	return new Promise(function (resolve, reject) {
  		const chunks = [];
  		req.on('data', function (chunk) {
  			chunks.push(chunk);
  		});
  		req.on('end', function () {
  			const body = Buffer.concat(chunks).toString();
  			resolve(body);
  		});
  		req.on('error', function (err) {
  			reject(err);
  		});
  	});
  }
  
  class HttpError extends Error {
  	constructor(statusCode, message) {
  		super(http.STATUS_CODES[statusCode] + message ? ': ' + message : '');
  		Object.defineProperties(this, {
  			name: {
  				value: this.constructor.name,
  				enumerable: false
  			},
  			httpStatus: {
  				value: statusCode,
  				enumerable: false
  			}
  		});
  	}
  }
  
  async function handleRequest(req, res) {
  	if(req.method !== 'POST') {
  		throw new HttpError(404);
  	}
  
  	const headers = req.headers;
  	const eventName = headers['x-github-event'];
  	const signature = headers['x-hub-signature'];
  
  	const body = await readBody(req);
  	if(!verifySignature(body, signature, config.secret)) {
  		throw new HttpError(400, 'Signature does not match');
  	}
  
  	const payload = JSON.parse(body);
  	if(eventName === 'push') {
  		console.log('Push to %s', payload.repository.name);
  	} else if(eventName === 'ping') {
  		console.log('Ping from %s', payload.repository.name);
  	} else {
  		throw new HttpError(400, 'Invalid event');
  	}
  }
  
  const server = http.createServer(function (req, res) {
  	let ret;
  	try {
  		ret = handleRequest(req, res);
  	} catch(err) {
  		ret = Promise.reject(err);
  	}
  	Promise.resolve(ret)
  		.then(function () {
  			res.end();
  		}, function (err) {
  			console.error(err);
  
  			res.statusCode = err.httpStatus || 500;
  			res.end();
  		});
  }).listen(config.port);
  
subject: Use crypto API correctly