Skip to content

Commit 58c8fb5

Browse files
刘放rvagg
刘放
authored andcommitted
feat: support multi match rules by passing options in Array type
1 parent ce36ecb commit 58c8fb5

File tree

4 files changed

+99
-10
lines changed

4 files changed

+99
-10
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
node_modules
2+
.history
3+
.vscode

github-webhook-handler.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,6 @@ interface handler extends EventEmitter {
1313
(req: IncomingMessage, res: ServerResponse, callback: (err: Error) => void): void;
1414
}
1515

16-
declare function createHandler(options: CreateHandlerOptions): handler;
16+
declare function createHandler(options: CreateHandlerOptions|CreateHandlerOptions[]): handler;
1717

1818
export = createHandler;

github-webhook-handler.js

+34-7
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,18 @@ const EventEmitter = require('events').EventEmitter
33
, crypto = require('crypto')
44
, bl = require('bl')
55

6-
function create (options) {
6+
function findHandler (url, arr) {
7+
if (!Array.isArray(arr))
8+
return arr
9+
var ret = arr[0]
10+
for (var i = 0; i < arr.length; i++) {
11+
if (url.split('?')[0] === arr[i].path)
12+
ret = arr[i]
13+
}
14+
return ret
15+
}
16+
17+
function checkType (options) {
718
if (typeof options != 'object')
819
throw new TypeError('must provide an options object')
920

@@ -12,14 +23,19 @@ function create (options) {
1223

1324
if (typeof options.secret != 'string')
1425
throw new TypeError('must provide a \'secret\' option')
26+
}
1527

16-
var events
17-
18-
if (typeof options.events == 'string' && options.events != '*')
19-
events = [ options.events ]
28+
function create (initOptions) {
2029

21-
else if (Array.isArray(options.events) && options.events.indexOf('*') == -1)
22-
events = options.events
30+
var options
31+
//validate type of options
32+
if (Array.isArray(initOptions)) {
33+
initOptions.forEach(function(item){
34+
checkType(item)
35+
})
36+
} else {
37+
checkType(initOptions)
38+
}
2339

2440
// make it an EventEmitter, sort of
2541
handler.__proto__ = EventEmitter.prototype
@@ -40,6 +56,16 @@ function create (options) {
4056
}
4157

4258
function handler (req, res, callback) {
59+
var events
60+
61+
options = findHandler(req.url, initOptions)
62+
63+
if (typeof options.events == 'string' && options.events != '*')
64+
events = [ options.events ]
65+
66+
else if (Array.isArray(options.events) && options.events.indexOf('*') == -1)
67+
events = options.events
68+
4369
if (req.url.split('?').shift() !== options.path || req.method !== 'POST')
4470
return callback()
4571

@@ -95,6 +121,7 @@ function create (options) {
95121
, protocol: req.protocol
96122
, host : req.headers['host']
97123
, url : req.url
124+
, path : options.path
98125
}
99126

100127
handler.emit(event, emitData)

test.js

+62-2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,14 @@ test('handler without full options throws', function (t) {
5252
t.throws(handler.bind(null, { path: '/' }), /must provide a 'secret' option/, 'throws if no secret option')
5353
})
5454

55+
test('handler without full options throws in array', function (t) {
56+
t.plan(2)
57+
58+
t.throws(handler.bind(null, [{}]), /must provide a 'path' option/, 'throws if no path option')
59+
60+
t.throws(handler.bind(null, [{ path: '/' }]), /must provide a 'secret' option/, 'throws if no secret option')
61+
})
62+
5563

5664
test('handler ignores invalid urls', function (t) {
5765
var options = { path: '/some/url', secret: 'bogus' }
@@ -113,6 +121,30 @@ test('handler accepts valid urls', function (t) {
113121
setTimeout(t.ok.bind(t, true, 'done'))
114122
})
115123

124+
test('handler accepts valid urls in Array', function (t) {
125+
var options = [{ path: '/some/url', secret: 'bogus' },{ path: '/someOther/url', secret: 'bogus' }]
126+
, h = handler(options)
127+
128+
t.plan(1)
129+
130+
h(mkReq('/some/url'), mkRes(), function (err) {
131+
t.error(err)
132+
t.fail(false, 'should not call')
133+
})
134+
135+
h(mkReq('/someOther/url'), mkRes(), function (err) {
136+
t.error(err)
137+
t.fail(false, 'should not call')
138+
})
139+
140+
h(mkReq('/some/url?test=param'), mkRes(), function (err) {
141+
t.error(err)
142+
t.fail(false, 'should not call')
143+
})
144+
145+
setTimeout(t.ok.bind(t, true, 'done'))
146+
})
147+
116148

117149
test('handler can reject events', function (t) {
118150
var acceptableEvents = {
@@ -206,7 +238,35 @@ test('handler accepts a signed blob', function (t) {
206238
req.headers['x-github-event'] = 'push'
207239

208240
h.on('push', function (event) {
209-
t.deepEqual(event, { event: 'push', id: 'bogus', payload: obj, url: '/', host: undefined, protocol: undefined })
241+
t.deepEqual(event, { event: 'push', id: 'bogus', payload: obj, url: '/', host: undefined, protocol: undefined, path: '/' })
242+
t.equal(res.$statusCode, 200, 'correct status code')
243+
t.deepEqual(res.$headers, { 'content-type': 'application/json' })
244+
t.equal(res.$end, '{"ok":true}', 'got correct content')
245+
})
246+
247+
h(req, res, function (err) {
248+
t.error(err)
249+
t.fail(true, 'should not get here!')
250+
})
251+
252+
process.nextTick(function () {
253+
req.end(json)
254+
})
255+
})
256+
257+
test('handler accepts multi blob in Array', function (t) {
258+
t.plan(4)
259+
260+
var obj = { some: 'github', object: 'with', properties: true }
261+
, json = JSON.stringify(obj)
262+
, h = handler([{ path: '/', secret: 'bogus' },{ path: '/some/url', secret: 'bogus'}])
263+
, req = mkReq('/some/url')
264+
, res = mkRes()
265+
req.headers['x-hub-signature'] = signBlob('bogus', json)
266+
req.headers['x-github-event'] = 'push'
267+
268+
h.on('push', function (event) {
269+
t.deepEqual(event, { event: 'push', id: 'bogus', payload: obj, url: '/some/url', host: undefined, protocol: undefined, path: '/some/url' })
210270
t.equal(res.$statusCode, 200, 'correct status code')
211271
t.deepEqual(res.$headers, { 'content-type': 'application/json' })
212272
t.equal(res.$end, '{"ok":true}', 'got correct content')
@@ -240,7 +300,7 @@ test('handler accepts a signed blob with alt event', function (t) {
240300
})
241301

242302
h.on('issue', function (event) {
243-
t.deepEqual(event, { event: 'issue', id: 'bogus', payload: obj, url: '/', host: undefined, protocol: undefined })
303+
t.deepEqual(event, { event: 'issue', id: 'bogus', payload: obj, url: '/', host: undefined, protocol: undefined, path: '/' })
244304
t.equal(res.$statusCode, 200, 'correct status code')
245305
t.deepEqual(res.$headers, { 'content-type': 'application/json' })
246306
t.equal(res.$end, '{"ok":true}', 'got correct content')

0 commit comments

Comments
 (0)