-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathindex.js
102 lines (82 loc) · 2.58 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
'use strict';
/**
* Module dependencies
*/
const EventEmitter = require('events').EventEmitter;
const crypto = require('crypto');
const bufferEq = require('buffer-equal-constant-time');
/**
* Helper functions
*/
function signData(secret, data) {
return 'sha1=' + crypto.createHmac('sha1', secret).update(data).digest('hex');
}
function verifySignature(secret, data, signature, signData) {
return bufferEq(new Buffer(signature), new Buffer(signData(secret, data)));
}
const GithubWebhook = function(options) {
if (typeof options !== 'object') {
throw new TypeError('must provide an options object');
}
if (typeof options.path !== 'string') {
throw new TypeError('must provide a \'path\' option');
}
options.secret = options.secret || '';
options.deliveryHeader = options.deliveryHeader || 'x-github-delivery';
options.eventHeader = options.eventHeader || 'x-github-event';
options.signatureHeader = options.signatureHeader || 'x-hub-signature';
options.signData = options.signData || signData;
// Make handler able to emit events
Object.assign(githookHandler, EventEmitter.prototype);
EventEmitter.call(githookHandler);
return githookHandler;
function githookHandler(req, res, next) {
if (req.method !== 'POST' || req.url.split('?').shift() !== options.path) {
return next();
}
function reportError(message) {
// respond error to sender
res.status(400).send({
error: message
});
// emit error
githookHandler.emit('error', new Error(message), req, res);
}
// check header fields
let id = req.headers[options.deliveryHeader];
if (!id) {
return reportError('No id found in the request');
}
let event = req.headers[options.eventHeader];
if (!event) {
return reportError('No event found in the request');
}
let sign = req.headers[options.signatureHeader] || '';
if (options.secret && !sign) {
return reportError('No signature found in the request');
}
if (!req.body) {
return reportError('Make sure body-parser is used');
}
// verify signature (if any)
if (options.secret && !verifySignature(options.secret, JSON.stringify(req.body), sign, options.signData)) {
return reportError('Failed to verify signature');
}
// parse payload
let payloadData = req.body;
const repo = payloadData.repository && payloadData.repository.name;
// emit events
githookHandler.emit('*', event, repo, payloadData);
githookHandler.emit(event, repo, payloadData);
if (repo) {
githookHandler.emit(repo, event, payloadData);
}
res.status(200).send({
success: true
});
}
};
/**
* Module exports
*/
module.exports = GithubWebhook;