github-webhook-handler 0.5.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.travis.yml ADDED
@@ -0,0 +1,14 @@
1
+ sudo: false
2
+ language: node_js
3
+ node_js:
4
+ - 8
5
+ - 10
6
+ - 12
7
+ - lts/*
8
+ - current
9
+ branches:
10
+ only:
11
+ - master
12
+ notifications:
13
+ email:
14
+ - rod@vagg.org
package/README.md CHANGED
@@ -1,12 +1,19 @@
1
1
  # github-webhook-handler
2
2
 
3
- [![NPM](https://nodei.co/npm/github-webhook-handler.png?downloads=true&downloadRank=true)](https://nodei.co/npm/github-webhook-handler/)
4
- [![NPM](https://nodei.co/npm-dl/github-webhook-handler.png?months=6&height=3)](https://nodei.co/npm/github-webhook-handler/)
3
+ [![Build Status](https://travis-ci.org/rvagg/github-webhook-handler.svg?branch=master)](https://travis-ci.org/rvagg/github-webhook-handler)
4
+
5
+ [![NPM](https://nodei.co/npm/github-webhook-handler.svg)](https://nodei.co/npm/github-webhook-handler/)
5
6
 
6
7
  GitHub allows you to register **[Webhooks](https://developer.github.com/webhooks/)** for your repositories. Each time an event occurs on your repository, whether it be pushing code, filling issues or creating pull requests, the webhook address you register can be configured to be pinged with details.
7
8
 
8
9
  This library is a small handler (or "middleware" if you must) for Node.js web servers that handles all the logic of receiving and verifying webhook requests from GitHub.
9
10
 
11
+ ## Tips
12
+
13
+ In Github Webhooks settings, Content type must be `application/json`.
14
+
15
+ `application/x-www-form-urlencoded` won't work at present.
16
+
10
17
  ## Example
11
18
 
12
19
  ```js
@@ -40,12 +47,15 @@ handler.on('issues', function (event) {
40
47
  })
41
48
  ```
42
49
 
50
+ for multiple handlers, please see [multiple-handlers-issue](https://github.com/rvagg/github-webhook-handler/pull/22#issuecomment-274301907).
51
+
43
52
  ## API
44
53
 
45
54
  github-webhook-handler exports a single function, use this function to *create* a webhook handler by passing in an *options* object. Your options object should contain:
46
55
 
47
56
  * `"path"`: the complete case sensitive path/route to match when looking at `req.url` for incoming requests. Any request not matching this path will cause the callback function to the handler to be called (sometimes called the `next` handler).
48
57
  * `"secret"`: this is a hash key used for creating the SHA-1 HMAC signature of the JSON blob sent by GitHub. You should register the same secret key with GitHub. Any request not delivering a `X-Hub-Signature` that matches the signature generated using this key against the blob will be rejected and cause an `'error'` event (also the callback will be called with an `Error` object).
58
+ * `"events"`: an optional array of whitelisted event types (see: *events.json*). If defined, any incoming request whose `X-Github-Event` can't be found in the whitelist will be rejected. If only a single event type is acceptable, this option can also be a string.
49
59
 
50
60
  The resulting **handler** function acts like a common "middleware" handler that you can insert into a processing chain. It takes `request`, `response`, and `callback` arguments. The `callback` is not called if the request is successfully handled, otherwise it is called either with an `Error` or no arguments.
51
61
 
@@ -66,4 +76,4 @@ Additionally, there is a special `'*'` even you can listen to in order to receiv
66
76
 
67
77
  ## License
68
78
 
69
- **github-webhook-handler** is Copyright (c) 2014 Rod Vagg [@rvagg](https://twitter.com/rvagg) and licensed under the MIT License. All rights not explicitly granted in the MIT License are reserved. See the included [LICENSE.md](./LICENSE.md) file for more details.
79
+ **github-webhook-handler** is Copyright (c) 2014 Rod Vagg and licensed under the MIT License. All rights not explicitly granted in the MIT License are reserved. See the included [LICENSE.md](./LICENSE.md) file for more details.
package/events.json CHANGED
@@ -10,13 +10,15 @@
10
10
  "issue_comment": "Any time an Issue is commented on",
11
11
  "issues": "Any time an Issue is opened or closed",
12
12
  "member": "Any time a User is added as a collaborator to a non-Organization Repository",
13
+ "membership": "Any time a User is added or removed from a team. Organization hooks only.",
13
14
  "page_build": "Any time a Pages site is built or results in a failed build",
14
15
  "public": "Any time a Repository changes from private to public",
15
16
  "pull_request_review_comment": "Any time a Commit is commented on while inside a Pull Request review (the Files Changed tab)",
16
17
  "pull_request": "Any time a Pull Request is opened, closed, or synchronized (updated due to a new push in the branch that the pull request is tracking)",
17
18
  "push": "Any git push to a Repository. This is the default event",
18
19
  "release": "Any time a Release is published in the Repository",
20
+ "repository": "Any time a Repository is created. Organization hooks only.",
19
21
  "status": "Any time a Repository has a status update from the API",
20
22
  "team_add": "Any time a team is added or modified on a Repository",
21
23
  "watchAny": "time a User watches the Repository"
22
- }
24
+ }
@@ -0,0 +1,18 @@
1
+ ///<reference types="node" />
2
+
3
+ import { IncomingMessage, ServerResponse } from "http";
4
+ import { EventEmitter } from "events";
5
+
6
+ interface CreateHandlerOptions {
7
+ path: string;
8
+ secret: string;
9
+ events?: string | string[];
10
+ }
11
+
12
+ interface handler extends EventEmitter {
13
+ (req: IncomingMessage, res: ServerResponse, callback: (err: Error) => void): void;
14
+ }
15
+
16
+ declare function createHandler(options: CreateHandlerOptions|CreateHandlerOptions[]): handler;
17
+
18
+ export = createHandler;
@@ -1,69 +1,124 @@
1
- const EventEmitter = require('events').EventEmitter
2
- , inherits = require('util').inherits
3
- , crypto = require('crypto')
4
- , bl = require('bl')
5
- , bufferEq = require('buffer-equal-constant-time')
1
+ const EventEmitter = require('events')
2
+ const crypto = require('crypto')
3
+ const bl = require('bl')
6
4
 
5
+ function findHandler (url, arr) {
6
+ if (!Array.isArray(arr)) {
7
+ return arr
8
+ }
7
9
 
8
- function signBlob (key, blob) {
9
- return 'sha1=' + crypto.createHmac('sha1', key).update(blob).digest('hex')
10
- }
10
+ let ret = arr[0]
11
+ for (let i = 0; i < arr.length; i++) {
12
+ if (url === arr[i].path) {
13
+ ret = arr[i]
14
+ }
15
+ }
11
16
 
17
+ return ret
18
+ }
12
19
 
13
- function create (options) {
14
- if (typeof options != 'object')
20
+ function checkType (options) {
21
+ if (typeof options !== 'object') {
15
22
  throw new TypeError('must provide an options object')
23
+ }
16
24
 
17
- if (typeof options.path != 'string')
25
+ if (typeof options.path !== 'string') {
18
26
  throw new TypeError('must provide a \'path\' option')
27
+ }
19
28
 
20
- if (typeof options.secret != 'string')
29
+ if (typeof options.secret !== 'string') {
21
30
  throw new TypeError('must provide a \'secret\' option')
31
+ }
32
+ }
33
+
34
+ function create (initOptions) {
35
+ let options
36
+ // validate type of options
37
+ if (Array.isArray(initOptions)) {
38
+ for (let i = 0; i < initOptions.length; i++) {
39
+ checkType(initOptions[i])
40
+ }
41
+ } else {
42
+ checkType(initOptions)
43
+ }
22
44
 
23
- // make it an EventEmitter, sort of
24
- handler.__proto__ = EventEmitter.prototype
45
+ // make it an EventEmitter
46
+ Object.setPrototypeOf(handler, EventEmitter.prototype)
25
47
  EventEmitter.call(handler)
26
48
 
49
+ handler.sign = sign
50
+ handler.verify = verify
51
+
27
52
  return handler
28
53
 
54
+ function sign (data) {
55
+ return `sha1=${crypto.createHmac('sha1', options.secret).update(data).digest('hex')}`
56
+ }
57
+
58
+ function verify (signature, data) {
59
+ const sig = Buffer.from(signature)
60
+ const signed = Buffer.from(sign(data))
61
+ if (sig.length !== signed.length) {
62
+ return false
63
+ }
64
+ return crypto.timingSafeEqual(sig, signed)
65
+ }
29
66
 
30
67
  function handler (req, res, callback) {
31
- if (req.url.split('?').shift() !== options.path)
68
+ let events
69
+
70
+ options = findHandler(req.url, initOptions)
71
+
72
+ if (typeof options.events === 'string' && options.events !== '*') {
73
+ events = [options.events]
74
+ } else if (Array.isArray(options.events) && options.events.indexOf('*') === -1) {
75
+ events = options.events
76
+ }
77
+
78
+ if (req.url !== options.path || req.method !== 'POST') {
32
79
  return callback()
80
+ }
33
81
 
34
82
  function hasError (msg) {
35
83
  res.writeHead(400, { 'content-type': 'application/json' })
36
84
  res.end(JSON.stringify({ error: msg }))
37
85
 
38
- var err = new Error(msg)
86
+ const err = new Error(msg)
39
87
 
40
88
  handler.emit('error', err, req)
41
89
  callback(err)
42
90
  }
43
91
 
44
- var sig = req.headers['x-hub-signature']
45
- , event = req.headers['x-github-event']
46
- , id = req.headers['x-github-delivery']
92
+ const sig = req.headers['x-hub-signature']
93
+ const event = req.headers['x-github-event']
94
+ const id = req.headers['x-github-delivery']
47
95
 
48
- if (!sig)
96
+ if (!sig) {
49
97
  return hasError('No X-Hub-Signature found on request')
98
+ }
50
99
 
51
- if (!event)
100
+ if (!event) {
52
101
  return hasError('No X-Github-Event found on request')
102
+ }
53
103
 
54
- if (!id)
104
+ if (!id) {
55
105
  return hasError('No X-Github-Delivery found on request')
106
+ }
56
107
 
57
- req.pipe(bl(function (err, data) {
108
+ if (events && events.indexOf(event) === -1) {
109
+ return hasError('X-Github-Event is not acceptable')
110
+ }
111
+
112
+ req.pipe(bl((err, data) => {
58
113
  if (err) {
59
114
  return hasError(err.message)
60
115
  }
61
116
 
62
- var obj
63
- var computedSig = new Buffer(signBlob(options.secret, data))
117
+ let obj
64
118
 
65
- if (!bufferEq(new Buffer(sig), computedSig))
119
+ if (!verify(sig, data)) {
66
120
  return hasError('X-Hub-Signature does not match blob signature')
121
+ }
67
122
 
68
123
  try {
69
124
  obj = JSON.parse(data.toString())
@@ -74,13 +129,14 @@ function create (options) {
74
129
  res.writeHead(200, { 'content-type': 'application/json' })
75
130
  res.end('{"ok":true}')
76
131
 
77
- var emitData = {
78
- event : event
79
- , id : id
80
- , payload : obj
81
- , protocol: req.protocol
82
- , host : req.headers['host']
83
- , url : req.url
132
+ const emitData = {
133
+ event: event,
134
+ id: id,
135
+ payload: obj,
136
+ protocol: req.protocol,
137
+ host: req.headers.host,
138
+ url: req.url,
139
+ path: options.path
84
140
  }
85
141
 
86
142
  handler.emit(event, emitData)
@@ -89,5 +145,4 @@ function create (options) {
89
145
  }
90
146
  }
91
147
 
92
-
93
148
  module.exports = create
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "github-webhook-handler",
3
- "version": "0.5.1",
3
+ "version": "1.0.0",
4
4
  "description": "Web handler / middleware for processing GitHub Webhooks",
5
5
  "main": "github-webhook-handler.js",
6
+ "types": "github-webhook-handler.d.ts",
6
7
  "scripts": {
7
- "test": "node test.js"
8
+ "lint": "standard *.js",
9
+ "test": "npm run lint && node test.js"
8
10
  },
9
11
  "keywords": [
10
12
  "github",
@@ -17,11 +19,13 @@
17
19
  },
18
20
  "license": "MIT",
19
21
  "dependencies": {
20
- "bl": "~1.1.2",
21
- "buffer-equal-constant-time": "~1.0.1"
22
+ "bl": "~4.0.0"
22
23
  },
23
24
  "devDependencies": {
24
- "tape": "~4.6.0",
25
- "through2": "~2.0.1"
25
+ "@types/node": "*",
26
+ "run-series": "~1.1.8",
27
+ "standard": "~14.3.1",
28
+ "tape": "~4.11.0",
29
+ "through2": "~3.0.1"
26
30
  }
27
31
  }
package/test.js CHANGED
@@ -1,44 +1,41 @@
1
- const test = require('tape')
2
- , crypto = require('crypto')
3
- , handler = require('./')
4
- , through2 = require('through2')
5
-
1
+ const test = require('tape')
2
+ const crypto = require('crypto')
3
+ const handler = require('./')
4
+ const through2 = require('through2')
5
+ const series = require('run-series')
6
6
 
7
7
  function signBlob (key, blob) {
8
- return 'sha1=' +
9
- crypto.createHmac('sha1', key).update(blob).digest('hex')
8
+ return `sha1=${crypto.createHmac('sha1', key).update(blob).digest('hex')}`
10
9
  }
11
10
 
12
-
13
- function mkReq (url) {
14
- var req = through2()
11
+ function mkReq (url, method) {
12
+ const req = through2()
13
+ req.method = method || 'POST'
15
14
  req.url = url
16
15
  req.headers = {
17
- 'x-hub-signature' : 'bogus'
18
- , 'x-github-event' : 'bogus'
19
- , 'x-github-delivery' : 'bogus'
16
+ 'x-hub-signature': 'bogus',
17
+ 'x-github-event': 'bogus',
18
+ 'x-github-delivery': 'bogus'
20
19
  }
21
20
  return req
22
21
  }
23
22
 
24
-
25
23
  function mkRes () {
26
- var res = {
27
- writeHead : function (statusCode, headers) {
28
- res.$statusCode = statusCode
29
- res.$headers = headers
30
- }
31
-
32
- , end : function (content) {
33
- res.$end = content
34
- }
24
+ const res = {
25
+ writeHead: function (statusCode, headers) {
26
+ res.$statusCode = statusCode
27
+ res.$headers = headers
28
+ },
29
+
30
+ end: function (content) {
31
+ res.$end = content
32
+ }
35
33
  }
36
34
 
37
35
  return res
38
36
  }
39
37
 
40
-
41
- test('handler without full options throws', function (t) {
38
+ test('handler without full options throws', (t) => {
42
39
  t.plan(4)
43
40
 
44
41
  t.equal(typeof handler, 'function', 'handler exports a function')
@@ -50,44 +47,81 @@ test('handler without full options throws', function (t) {
50
47
  t.throws(handler.bind(null, { path: '/' }), /must provide a 'secret' option/, 'throws if no secret option')
51
48
  })
52
49
 
50
+ test('handler without full options throws in array', (t) => {
51
+ t.plan(2)
53
52
 
54
- test('handler ignores invalid urls', function (t) {
55
- var options = { path: '/some/url', secret: 'bogus' }
56
- , h = handler(options)
53
+ t.throws(handler.bind(null, [{}]), /must provide a 'path' option/, 'throws if no path option')
54
+
55
+ t.throws(handler.bind(null, [{ path: '/' }]), /must provide a 'secret' option/, 'throws if no secret option')
56
+ })
57
+
58
+ test('handler ignores invalid urls', (t) => {
59
+ const options = { path: '/some/url', secret: 'bogus' }
60
+ const h = handler(options)
57
61
 
58
62
  t.plan(6)
59
63
 
60
- h(mkReq('/'), mkRes(), function (err) {
64
+ h(mkReq('/'), mkRes(), (err) => {
61
65
  t.error(err)
62
66
  t.ok(true, 'request was ignored')
63
67
  })
64
68
 
65
69
  // near match
66
- h(mkReq('/some/url/'), mkRes(), function (err) {
70
+ h(mkReq('/some/url/'), mkRes(), (err) => {
67
71
  t.error(err)
68
72
  t.ok(true, 'request was ignored')
69
73
  })
70
74
 
71
75
  // partial match
72
- h(mkReq('/some'), mkRes(), function (err) {
76
+ h(mkReq('/some'), mkRes(), (err) => {
77
+ t.error(err)
78
+ t.ok(true, 'request was ignored')
79
+ })
80
+ })
81
+
82
+ test('handler ingores non-POST requests', (t) => {
83
+ const options = { path: '/some/url', secret: 'bogus' }
84
+ const h = handler(options)
85
+
86
+ t.plan(4)
87
+
88
+ h(mkReq('/some/url', 'GET'), mkRes(), (err) => {
89
+ t.error(err)
90
+ t.ok(true, 'request was ignored')
91
+ })
92
+
93
+ h(mkReq('/some/url?test=param', 'GET'), mkRes(), (err) => {
73
94
  t.error(err)
74
95
  t.ok(true, 'request was ignored')
75
96
  })
76
97
  })
77
98
 
99
+ test('handler accepts valid urls', (t) => {
100
+ const options = { path: '/some/url', secret: 'bogus' }
101
+ const h = handler(options)
78
102
 
79
- test('handler accepts valid urls', function (t) {
80
- var options = { path: '/some/url', secret: 'bogus' }
81
- , h = handler(options)
103
+ t.plan(1)
104
+
105
+ h(mkReq('/some/url'), mkRes(), (err) => {
106
+ t.error(err)
107
+ t.fail(false, 'should not call')
108
+ })
109
+
110
+ setTimeout(t.ok.bind(t, true, 'done'))
111
+ })
112
+
113
+ test('handler accepts valid urls in Array', (t) => {
114
+ const options = [{ path: '/some/url', secret: 'bogus' }, { path: '/someOther/url', secret: 'bogus' }]
115
+ const h = handler(options)
82
116
 
83
117
  t.plan(1)
84
118
 
85
- h(mkReq('/some/url'), mkRes(), function (err) {
119
+ h(mkReq('/some/url'), mkRes(), (err) => {
86
120
  t.error(err)
87
121
  t.fail(false, 'should not call')
88
122
  })
89
123
 
90
- h(mkReq('/some/url?test=param'), mkRes(), function (err) {
124
+ h(mkReq('/someOther/url'), mkRes(), (err) => {
91
125
  t.error(err)
92
126
  t.fail(false, 'should not call')
93
127
  })
@@ -95,18 +129,75 @@ test('handler accepts valid urls', function (t) {
95
129
  setTimeout(t.ok.bind(t, true, 'done'))
96
130
  })
97
131
 
132
+ test('handler can reject events', (t) => {
133
+ const acceptableEvents = {
134
+ undefined: undefined,
135
+ 'a string equal to the event': 'bogus',
136
+ 'a string equal to *': '*',
137
+ 'an array containing the event': ['bogus'],
138
+ 'an array containing *': ['not-bogus', '*']
139
+ }
140
+ const unacceptableEvents = {
141
+ 'a string not equal to the event or *': 'not-bogus',
142
+ 'an array not containing the event or *': ['not-bogus']
143
+ }
144
+ const acceptable = Object.keys(acceptableEvents)
145
+ const unacceptable = Object.keys(unacceptableEvents)
146
+ const acceptableTests = acceptable.map((events) => {
147
+ return acceptableReq.bind(null, events)
148
+ })
149
+ const unacceptableTests = unacceptable.map((events) => {
150
+ return unacceptableReq.bind(null, events)
151
+ })
152
+
153
+ t.plan(acceptable.length + unacceptable.length)
154
+ series(acceptableTests.concat(unacceptableTests))
155
+
156
+ function acceptableReq (events, callback) {
157
+ const h = handler({
158
+ path: '/some/url',
159
+ secret: 'bogus',
160
+ events: acceptableEvents[events]
161
+ })
162
+
163
+ h(mkReq('/some/url'), mkRes(), (err) => {
164
+ t.error(err)
165
+ t.fail(false, 'should not call')
166
+ })
167
+
168
+ setTimeout(() => {
169
+ t.ok(true, 'accepted because options.events was ' + events)
170
+ callback()
171
+ })
172
+ }
173
+
174
+ function unacceptableReq (events, callback) {
175
+ const h = handler({
176
+ path: '/some/url',
177
+ secret: 'bogus',
178
+ events: unacceptableEvents[events]
179
+ })
180
+
181
+ h.on('error', () => {})
182
+
183
+ h(mkReq('/some/url'), mkRes(), (err) => {
184
+ t.ok(err, 'rejected because options.events was ' + events)
185
+ callback()
186
+ })
187
+ }
188
+ })
98
189
 
99
190
  // because we don't inherit in a traditional way
100
- test('handler is an EventEmitter', function (t) {
191
+ test('handler is an EventEmitter', (t) => {
101
192
  t.plan(5)
102
193
 
103
- var h = handler({ path: '/', secret: 'bogus' })
194
+ const h = handler({ path: '/', secret: 'bogus' })
104
195
 
105
196
  t.equal(typeof h.on, 'function', 'has h.on()')
106
197
  t.equal(typeof h.emit, 'function', 'has h.emit()')
107
198
  t.equal(typeof h.removeListener, 'function', 'has h.removeListener()')
108
199
 
109
- h.on('ping', function (pong) {
200
+ h.on('ping', (pong) => {
110
201
  t.equal(pong, 'pong', 'got event')
111
202
  })
112
203
 
@@ -115,85 +206,110 @@ test('handler is an EventEmitter', function (t) {
115
206
  t.throws(h.emit.bind(h, 'error', new Error('threw an error')), /threw an error/, 'acts like an EE')
116
207
  })
117
208
 
118
-
119
- test('handler accepts a signed blob', function (t) {
209
+ test('handler accepts a signed blob', (t) => {
120
210
  t.plan(4)
121
211
 
122
- var obj = { some: 'github', object: 'with', properties: true }
123
- , json = JSON.stringify(obj)
124
- , h = handler({ path: '/', secret: 'bogus' })
125
- , req = mkReq('/')
126
- , res = mkRes()
212
+ const obj = { some: 'github', object: 'with', properties: true }
213
+ const json = JSON.stringify(obj)
214
+ const h = handler({ path: '/', secret: 'bogus' })
215
+ const req = mkReq('/')
216
+ const res = mkRes()
127
217
 
128
218
  req.headers['x-hub-signature'] = signBlob('bogus', json)
129
- req.headers['x-github-event'] = 'push'
219
+ req.headers['x-github-event'] = 'push'
130
220
 
131
- h.on('push', function (event) {
132
- t.deepEqual(event, { event: 'push', id: 'bogus', payload: obj, url: '/', host: undefined, protocol: undefined })
221
+ h.on('push', (event) => {
222
+ t.deepEqual(event, { event: 'push', id: 'bogus', payload: obj, url: '/', host: undefined, protocol: undefined, path: '/' })
133
223
  t.equal(res.$statusCode, 200, 'correct status code')
134
224
  t.deepEqual(res.$headers, { 'content-type': 'application/json' })
135
225
  t.equal(res.$end, '{"ok":true}', 'got correct content')
136
226
  })
137
227
 
138
- h(req, res, function (err) {
228
+ h(req, res, (err) => {
139
229
  t.error(err)
140
230
  t.fail(true, 'should not get here!')
141
231
  })
142
232
 
143
- process.nextTick(function () {
233
+ process.nextTick(() => {
144
234
  req.end(json)
145
235
  })
146
236
  })
147
237
 
238
+ test('handler accepts multi blob in Array', (t) => {
239
+ t.plan(4)
240
+
241
+ const obj = { some: 'github', object: 'with', properties: true }
242
+ const json = JSON.stringify(obj)
243
+ const h = handler([{ path: '/', secret: 'bogus' }, { path: '/some/url', secret: 'bogus' }])
244
+ const req = mkReq('/some/url')
245
+ const res = mkRes()
246
+ req.headers['x-hub-signature'] = signBlob('bogus', json)
247
+ req.headers['x-github-event'] = 'push'
248
+
249
+ h.on('push', (event) => {
250
+ t.deepEqual(event, { event: 'push', id: 'bogus', payload: obj, url: '/some/url', host: undefined, protocol: undefined, path: '/some/url' })
251
+ t.equal(res.$statusCode, 200, 'correct status code')
252
+ t.deepEqual(res.$headers, { 'content-type': 'application/json' })
253
+ t.equal(res.$end, '{"ok":true}', 'got correct content')
254
+ })
255
+
256
+ h(req, res, (err) => {
257
+ t.error(err)
258
+ t.fail(true, 'should not get here!')
259
+ })
148
260
 
149
- test('handler accepts a signed blob with alt event', function (t) {
261
+ process.nextTick(() => {
262
+ req.end(json)
263
+ })
264
+ })
265
+
266
+ test('handler accepts a signed blob with alt event', (t) => {
150
267
  t.plan(4)
151
268
 
152
- var obj = { some: 'github', object: 'with', properties: true }
153
- , json = JSON.stringify(obj)
154
- , h = handler({ path: '/', secret: 'bogus' })
155
- , req = mkReq('/')
156
- , res = mkRes()
269
+ const obj = { some: 'github', object: 'with', properties: true }
270
+ const json = JSON.stringify(obj)
271
+ const h = handler({ path: '/', secret: 'bogus' })
272
+ const req = mkReq('/')
273
+ const res = mkRes()
157
274
 
158
275
  req.headers['x-hub-signature'] = signBlob('bogus', json)
159
- req.headers['x-github-event'] = 'issue'
276
+ req.headers['x-github-event'] = 'issue'
160
277
 
161
- h.on('push', function (event) {
278
+ h.on('push', (event) => {
162
279
  t.fail(true, 'should not get here!')
163
280
  })
164
281
 
165
- h.on('issue', function (event) {
166
- t.deepEqual(event, { event: 'issue', id: 'bogus', payload: obj, url: '/', host: undefined, protocol: undefined })
282
+ h.on('issue', (event) => {
283
+ t.deepEqual(event, { event: 'issue', id: 'bogus', payload: obj, url: '/', host: undefined, protocol: undefined, path: '/' })
167
284
  t.equal(res.$statusCode, 200, 'correct status code')
168
285
  t.deepEqual(res.$headers, { 'content-type': 'application/json' })
169
286
  t.equal(res.$end, '{"ok":true}', 'got correct content')
170
287
  })
171
288
 
172
- h(req, res, function (err) {
289
+ h(req, res, (err) => {
173
290
  t.error(err)
174
291
  t.fail(true, 'should not get here!')
175
292
  })
176
293
 
177
- process.nextTick(function () {
294
+ process.nextTick(() => {
178
295
  req.end(json)
179
296
  })
180
297
  })
181
298
 
182
-
183
- test('handler rejects a badly signed blob', function (t) {
299
+ test('handler rejects a badly signed blob', (t) => {
184
300
  t.plan(6)
185
301
 
186
- var obj = { some: 'github', object: 'with', properties: true }
187
- , json = JSON.stringify(obj)
188
- , h = handler({ path: '/', secret: 'bogus' })
189
- , req = mkReq('/')
190
- , res = mkRes()
302
+ const obj = { some: 'github', object: 'with', properties: true }
303
+ const json = JSON.stringify(obj)
304
+ const h = handler({ path: '/', secret: 'bogus' })
305
+ const req = mkReq('/')
306
+ const res = mkRes()
191
307
 
192
308
  req.headers['x-hub-signature'] = signBlob('bogus', json)
193
309
  // break signage by a tiny bit
194
310
  req.headers['x-hub-signature'] = '0' + req.headers['x-hub-signature'].substring(1)
195
311
 
196
- h.on('error', function (err, _req) {
312
+ h.on('error', (err, _req) => {
197
313
  t.ok(err, 'got an error')
198
314
  t.strictEqual(_req, req, 'was given original request object')
199
315
  t.equal(res.$statusCode, 400, 'correct status code')
@@ -201,56 +317,54 @@ test('handler rejects a badly signed blob', function (t) {
201
317
  t.equal(res.$end, '{"error":"X-Hub-Signature does not match blob signature"}', 'got correct content')
202
318
  })
203
319
 
204
- h.on('push', function (event) {
320
+ h.on('push', (event) => {
205
321
  t.fail(true, 'should not get here!')
206
322
  })
207
323
 
208
- h(req, res, function (err) {
324
+ h(req, res, (err) => {
209
325
  t.ok(err, 'got error on callback')
210
326
  })
211
327
 
212
- process.nextTick(function () {
328
+ process.nextTick(() => {
213
329
  req.end(json)
214
330
  })
215
331
  })
216
332
 
217
- test('handler responds on a bl error', function (t) {
333
+ test('handler responds on a bl error', (t) => {
218
334
  t.plan(4)
219
335
 
220
- var obj = { some: 'github', object: 'with', properties: true }
221
- , json = JSON.stringify(obj)
222
- , h = handler({ path: '/', secret: 'bogus' })
223
- , req = mkReq('/')
224
- , res = mkRes()
336
+ const obj = { some: 'github', object: 'with', properties: true }
337
+ const json = JSON.stringify(obj)
338
+ const h = handler({ path: '/', secret: 'bogus' })
339
+ const req = mkReq('/')
340
+ const res = mkRes()
225
341
 
226
342
  req.headers['x-hub-signature'] = signBlob('bogus', json)
227
- req.headers['x-github-event'] = 'issue'
343
+ req.headers['x-github-event'] = 'issue'
228
344
 
229
- h.on('push', function (event) {
345
+ h.on('push', (event) => {
230
346
  t.fail(true, 'should not get here!')
231
347
  })
232
348
 
233
- h.on('issue', function (event) {
349
+ h.on('issue', (event) => {
234
350
  t.fail(true, 'should never get here!')
235
351
  })
236
352
 
237
- h.on('error', function(err) {
353
+ h.on('error', (err) => {
238
354
  t.ok(err, 'got an error')
239
355
  t.equal(res.$statusCode, 400, 'correct status code')
240
- });
356
+ })
241
357
 
242
- h(req, res, function (err) {
358
+ h(req, res, (err) => {
243
359
  t.ok(err)
244
360
  })
245
361
 
246
- var end = res.end
247
- res.end = function () {
362
+ res.end = () => {
248
363
  t.equal(res.$statusCode, 400, 'correct status code')
249
364
  }
250
365
 
251
366
  req.write('{')
252
- process.nextTick(function() {
367
+ process.nextTick(() => {
253
368
  req.emit('error', new Error('simulated explosion'))
254
- });
255
-
369
+ })
256
370
  })
package/.jshintrc DELETED
@@ -1,59 +0,0 @@
1
- {
2
- "predef": [ ]
3
- , "bitwise": false
4
- , "camelcase": false
5
- , "curly": false
6
- , "eqeqeq": false
7
- , "forin": false
8
- , "immed": false
9
- , "latedef": false
10
- , "noarg": true
11
- , "noempty": true
12
- , "nonew": true
13
- , "plusplus": false
14
- , "quotmark": true
15
- , "regexp": false
16
- , "undef": true
17
- , "unused": true
18
- , "strict": false
19
- , "trailing": true
20
- , "maxlen": 120
21
- , "asi": true
22
- , "boss": true
23
- , "debug": true
24
- , "eqnull": true
25
- , "esnext": true
26
- , "evil": true
27
- , "expr": true
28
- , "funcscope": false
29
- , "globalstrict": false
30
- , "iterator": false
31
- , "lastsemic": true
32
- , "laxbreak": true
33
- , "laxcomma": true
34
- , "loopfunc": true
35
- , "multistr": false
36
- , "onecase": false
37
- , "proto": false
38
- , "regexdash": false
39
- , "scripturl": true
40
- , "smarttabs": false
41
- , "shadow": false
42
- , "sub": true
43
- , "supernew": false
44
- , "validthis": true
45
- , "browser": true
46
- , "couch": false
47
- , "devel": false
48
- , "dojo": false
49
- , "mootools": false
50
- , "node": true
51
- , "nonstandard": true
52
- , "prototypejs": false
53
- , "rhino": false
54
- , "worker": true
55
- , "wsh": false
56
- , "nomen": false
57
- , "onevar": false
58
- , "passfail": false
59
- }
package/.npmignore DELETED
@@ -1 +0,0 @@
1
- node_modules