openid-client 2.4.2 → 2.5.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/CHANGELOG.md +44 -0
- package/README.md +11 -4
- package/lib/client.js +34 -8
- package/lib/helpers/consts.js +2 -0
- package/lib/issuer.js +38 -18
- package/lib/passport_strategy.js +6 -6
- package/lib/util/random.js +5 -0
- package/package.json +9 -14
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,50 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
# [2.5.0](https://github.com/panva/node-openid-client/compare/v2.4.5...v2.5.0) (2019-04-29)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* key lookup cache is now working as intended ([90d2f2a](https://github.com/panva/node-openid-client/commit/90d2f2a)), closes [#162](https://github.com/panva/node-openid-client/issues/162)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* add support for azure ad v2 multitenant apps ([24486dd](https://github.com/panva/node-openid-client/commit/24486dd)), closes [/github.com/panva/node-openid-client/pull/148#issuecomment-483348258](https://github.com//github.com/panva/node-openid-client/pull/148/issues/issuecomment-483348258) [#148](https://github.com/panva/node-openid-client/issues/148)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
<a name="2.4.5"></a>
|
|
20
|
+
## [2.4.5](https://github.com/panva/node-openid-client/compare/v2.4.4...v2.4.5) (2018-11-05)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
* upgrade min node-jose version to fix its performance in node ([e682dfc](https://github.com/panva/node-openid-client/commit/e682dfc))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
<a name="2.4.4"></a>
|
|
30
|
+
## [2.4.4](https://github.com/panva/node-openid-client/compare/v2.4.3...v2.4.4) (2018-10-18)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
### Bug Fixes
|
|
34
|
+
|
|
35
|
+
* strategy code_verifier length, removed uuid dependency ([60d0cb8...ea4a8fd](https://github.com/panva/node-openid-client/compare/60d0cb8...ea4a8fd)), closes [#131](https://github.com/panva/node-openid-client/issues/131)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
<a name="2.4.3"></a>
|
|
40
|
+
## [2.4.3](https://github.com/panva/node-openid-client/compare/v2.4.2...v2.4.3) (2018-10-10)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
### Bug Fixes
|
|
44
|
+
|
|
45
|
+
* assign Discovery 1.0 defaults when discovering with .well-known ([74b593e](https://github.com/panva/node-openid-client/commit/74b593e))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
5
49
|
<a name="2.4.2"></a>
|
|
6
50
|
## [2.4.2](https://github.com/panva/node-openid-client/compare/v2.4.1...v2.4.2) (2018-09-27)
|
|
7
51
|
|
package/README.md
CHANGED
|
@@ -57,7 +57,7 @@ versions, if you utilize these consider using the tilde ~ operator in your packa
|
|
|
57
57
|
breaking changes may be introduced as part of these specification updates.
|
|
58
58
|
|
|
59
59
|
## Certification
|
|
60
|
-
[<img width="184" height="96" align="right" src="https://cdn.
|
|
60
|
+
[<img width="184" height="96" align="right" src="https://cdn.jsdelivr.net/gh/panva/node-openid-client@38cf016b0837e6d4116de3780b28d222d5780bc9/OpenID_Certified.png" alt="OpenID Certification">][openid-certified-link]
|
|
61
61
|
Filip Skokan has [certified][openid-certified-link] that [openid-client][npm-url]
|
|
62
62
|
conforms to the RP Basic, RP Implicit, RP Hybrid, RP Config, RP Dynamic and RP Form Post profiles
|
|
63
63
|
of the OpenID Connect™ protocol.
|
|
@@ -69,6 +69,12 @@ of the OpenID Connect™ protocol.
|
|
|
69
69
|
|
|
70
70
|
[<img width="65" height="65" align="left" src="https://avatars.githubusercontent.com/u/2824157?s=75&v=4" alt="auth0-logo">][sponsor-auth0] If you want to quickly add OpenID Connect authentication to Node.js apps, feel free to check out Auth0's Node.js SDK and free plan at [auth0.com/overview][sponsor-auth0].<br><br>
|
|
71
71
|
|
|
72
|
+
<h2>Support</h2>
|
|
73
|
+
|
|
74
|
+
[<img src="https://c5.patreon.com/external/logo/become_a_patron_button@2x.png" width="160" align="right">][support-patreon]
|
|
75
|
+
If you or your business use openid-client, please consider becoming a [Patron][support-patreon] so I can continue maintaining it and adding new features carefree. You may also donate one-time via [PayPal][support-paypal].
|
|
76
|
+
[<img src="https://cdn.jsdelivr.net/gh/gregoiresgt/payment-icons@183140a5ff8f39b5a19d59ebeb2c77f03c3a24d3/Assets/Payment/PayPal/Paypal@2x.png" width="100" align="right">][support-paypal]
|
|
77
|
+
|
|
72
78
|
|
|
73
79
|
## Get started
|
|
74
80
|
On the off-chance you want to manage multiple clients for multiple issuers you need to first get
|
|
@@ -153,8 +159,8 @@ client.authorizationCallback('https://client.example.com/callback', request.quer
|
|
|
153
159
|
});
|
|
154
160
|
```
|
|
155
161
|
|
|
156
|
-
Aside from `state` and `response_type`, checks for `nonce` (implicit and hybrid responses)
|
|
157
|
-
`max_age` are implemented. `id_token` signature and claims validation does not need to be requested,
|
|
162
|
+
Aside from `state` and `response_type`, checks for `nonce` (implicit and hybrid responses),
|
|
163
|
+
`max_age`, and `code_verifier` (for use with PKCE) are implemented. `id_token` signature and claims validation does not need to be requested,
|
|
158
164
|
it is done automatically.
|
|
159
165
|
|
|
160
166
|
### OP Errors - OpenIdConnectError
|
|
@@ -558,7 +564,8 @@ Issuer.useRequest();
|
|
|
558
564
|
[request-library]: https://github.com/request/request
|
|
559
565
|
[signed-userinfo]: https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse
|
|
560
566
|
[openid-certified-link]: https://openid.net/certification/
|
|
561
|
-
[openid-certified-logo]: https://cdn.rawgit.com/panva/node-openid-client/master/OpenID_Certified.png
|
|
562
567
|
[passport-url]: http://passportjs.org
|
|
563
568
|
[npm-url]: https://www.npmjs.com/package/openid-client
|
|
564
569
|
[sponsor-auth0]: https://auth0.com/overview?utm_source=GHsponsor&utm_medium=GHsponsor&utm_campaign=openid-client&utm_content=auth
|
|
570
|
+
[support-patreon]: https://www.patreon.com/panva
|
|
571
|
+
[support-paypal]: https://www.paypal.me/panva
|
package/lib/client.js
CHANGED
|
@@ -6,7 +6,6 @@ const querystring = require('querystring');
|
|
|
6
6
|
const url = require('url');
|
|
7
7
|
|
|
8
8
|
const jose = require('node-jose');
|
|
9
|
-
const uuid = require('uuid/v4');
|
|
10
9
|
const base64url = require('base64url');
|
|
11
10
|
const _ = require('lodash');
|
|
12
11
|
const tokenHash = require('oidc-token-hash');
|
|
@@ -19,6 +18,7 @@ const now = require('./util/unix_timestamp');
|
|
|
19
18
|
const { CALLBACK_PROPERTIES, CLIENT_DEFAULTS, JWT_CONTENT } = require('./helpers/consts');
|
|
20
19
|
const issuerRegistry = require('./issuer_registry');
|
|
21
20
|
const forEach = require('./util/for_each');
|
|
21
|
+
const random = require('./util/random');
|
|
22
22
|
|
|
23
23
|
const errorHandler = errorHandlerFactory();
|
|
24
24
|
const bearerErrorHandler = errorHandlerFactory({ bearerEndpoint: true });
|
|
@@ -200,12 +200,15 @@ function assertIssuerConfiguration(issuer, endpoint) {
|
|
|
200
200
|
assert(issuer[endpoint], `${endpoint} must be configured on the issuer`);
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
class
|
|
203
|
+
class BaseClient {}
|
|
204
|
+
|
|
205
|
+
module.exports = (issuer, aadIssValidation = false) => class Client extends BaseClient {
|
|
204
206
|
/**
|
|
205
207
|
* @name constructor
|
|
206
208
|
* @api public
|
|
207
209
|
*/
|
|
208
210
|
constructor(metadata = {}, keystore) {
|
|
211
|
+
super();
|
|
209
212
|
const properties = Object.assign({}, CLIENT_DEFAULTS, metadata);
|
|
210
213
|
|
|
211
214
|
if (!metadata.token_endpoint_auth_method) { // if no explicit value was provided
|
|
@@ -570,7 +573,12 @@ class Client {
|
|
|
570
573
|
}
|
|
571
574
|
|
|
572
575
|
if (payload.iss !== undefined) {
|
|
573
|
-
|
|
576
|
+
if (aadIssValidation) {
|
|
577
|
+
const azureADv2Issuer = this.issuer.issuer.replace('{tenantid}', payload.tid);
|
|
578
|
+
assert.equal(payload.iss, azureADv2Issuer, 'unexpected iss value');
|
|
579
|
+
} else {
|
|
580
|
+
assert.equal(payload.iss, this.issuer.issuer, 'unexpected iss value');
|
|
581
|
+
}
|
|
574
582
|
}
|
|
575
583
|
|
|
576
584
|
if (payload.iat !== undefined) {
|
|
@@ -715,8 +723,9 @@ class Client {
|
|
|
715
723
|
}
|
|
716
724
|
}
|
|
717
725
|
|
|
718
|
-
|
|
719
|
-
|
|
726
|
+
return this.httpClient[verb](
|
|
727
|
+
this.issuer.userinfo_endpoint, this.issuer.httpOptions(httpOptions)
|
|
728
|
+
)
|
|
720
729
|
.then(expectResponseWithBody(200))
|
|
721
730
|
.then((response) => {
|
|
722
731
|
if (JWT_CONTENT.exec(response.headers['content-type'])) {
|
|
@@ -951,7 +960,7 @@ class Client {
|
|
|
951
960
|
return this.createSign(endpoint).then(sign => sign.update(JSON.stringify({
|
|
952
961
|
iat: timestamp,
|
|
953
962
|
exp: timestamp + 60,
|
|
954
|
-
jti:
|
|
963
|
+
jti: random(),
|
|
955
964
|
iss: this.client_id,
|
|
956
965
|
sub: this.client_id,
|
|
957
966
|
aud: this.issuer[`${endpoint}_endpoint`],
|
|
@@ -1109,6 +1118,23 @@ class Client {
|
|
|
1109
1118
|
static get httpClient() {
|
|
1110
1119
|
return this.issuer.httpClient;
|
|
1111
1120
|
}
|
|
1112
|
-
}
|
|
1113
1121
|
|
|
1114
|
-
|
|
1122
|
+
/**
|
|
1123
|
+
* @name issuer
|
|
1124
|
+
* @api public
|
|
1125
|
+
*/
|
|
1126
|
+
static get issuer() {
|
|
1127
|
+
return issuer;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
|
|
1131
|
+
/**
|
|
1132
|
+
* @name issuer
|
|
1133
|
+
* @api public
|
|
1134
|
+
*/
|
|
1135
|
+
get issuer() { // eslint-disable-line class-methods-use-this
|
|
1136
|
+
return issuer;
|
|
1137
|
+
}
|
|
1138
|
+
};
|
|
1139
|
+
|
|
1140
|
+
module.exports.BaseClient = BaseClient;
|
package/lib/helpers/consts.js
CHANGED
|
@@ -6,6 +6,7 @@ const OIDC_DISCOVERY = '/.well-known/openid-configuration';
|
|
|
6
6
|
const OAUTH2_DISCOVERY = '/.well-known/oauth-authorization-server';
|
|
7
7
|
const WEBFINGER = '/.well-known/webfinger';
|
|
8
8
|
const REL = 'http://openid.net/specs/connect/1.0/issuer';
|
|
9
|
+
const AAD_MULTITENANT_DISCOVERY = `https://login.microsoftonline.com/common/v2.0${OIDC_DISCOVERY}`;
|
|
9
10
|
|
|
10
11
|
const CLIENT_DEFAULTS = {
|
|
11
12
|
application_type: 'web',
|
|
@@ -49,6 +50,7 @@ const DEFAULT_HTTP_OPTIONS = {
|
|
|
49
50
|
const JWT_CONTENT = /^application\/jwt/;
|
|
50
51
|
|
|
51
52
|
module.exports = {
|
|
53
|
+
AAD_MULTITENANT_DISCOVERY,
|
|
52
54
|
CALLBACK_PROPERTIES,
|
|
53
55
|
CLIENT_DEFAULTS,
|
|
54
56
|
DEFAULT_HTTP_OPTIONS,
|
package/lib/issuer.js
CHANGED
|
@@ -6,17 +6,19 @@ const jose = require('node-jose');
|
|
|
6
6
|
const _ = require('lodash');
|
|
7
7
|
const pAny = require('p-any');
|
|
8
8
|
const LRU = require('lru-cache');
|
|
9
|
+
const objectHash = require('object-hash');
|
|
9
10
|
|
|
10
11
|
const http = require('./helpers/http');
|
|
11
12
|
const httpRequest = require('./helpers/http_request');
|
|
12
13
|
const errorHandler = require('./helpers/error_handler')();
|
|
13
|
-
const
|
|
14
|
+
const getClient = require('./client');
|
|
14
15
|
const registry = require('./issuer_registry');
|
|
15
16
|
const expectResponseWithBody = require('./helpers/expect_response');
|
|
16
17
|
const webfingerNormalize = require('./util/webfinger_normalize');
|
|
17
18
|
const forEach = require('./util/for_each');
|
|
18
19
|
const {
|
|
19
|
-
DEFAULT_HTTP_OPTIONS, ISSUER_DEFAULTS, OIDC_DISCOVERY,
|
|
20
|
+
DEFAULT_HTTP_OPTIONS, ISSUER_DEFAULTS, OIDC_DISCOVERY,
|
|
21
|
+
OAUTH2_DISCOVERY, WEBFINGER, REL, AAD_MULTITENANT_DISCOVERY,
|
|
20
22
|
} = require('./helpers/consts');
|
|
21
23
|
|
|
22
24
|
const privateProps = new WeakMap();
|
|
@@ -29,12 +31,17 @@ function instance(ctx) {
|
|
|
29
31
|
return privateProps.get(ctx);
|
|
30
32
|
}
|
|
31
33
|
|
|
34
|
+
const AAD_MULTITENANT = Symbol('AAD_MULTITENANT');
|
|
35
|
+
|
|
32
36
|
class Issuer {
|
|
33
37
|
/**
|
|
34
38
|
* @name constructor
|
|
35
39
|
* @api public
|
|
36
40
|
*/
|
|
37
41
|
constructor(meta = {}) {
|
|
42
|
+
const aadIssValidation = meta[AAD_MULTITENANT];
|
|
43
|
+
delete meta[AAD_MULTITENANT];
|
|
44
|
+
|
|
38
45
|
['introspection', 'revocation'].forEach((endpoint) => {
|
|
39
46
|
// e.g. defaults introspection_endpoint to token_introspection_endpoint value
|
|
40
47
|
if (
|
|
@@ -74,18 +81,8 @@ class Issuer {
|
|
|
74
81
|
|
|
75
82
|
registry.set(this.issuer, this);
|
|
76
83
|
|
|
77
|
-
const self = this;
|
|
78
|
-
|
|
79
84
|
Object.defineProperty(this, 'Client', {
|
|
80
|
-
value:
|
|
81
|
-
static get issuer() {
|
|
82
|
-
return self;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
get issuer() {
|
|
86
|
-
return this.constructor.issuer;
|
|
87
|
-
}
|
|
88
|
-
},
|
|
85
|
+
value: getClient(this, aadIssValidation),
|
|
89
86
|
});
|
|
90
87
|
}
|
|
91
88
|
|
|
@@ -127,11 +124,24 @@ class Issuer {
|
|
|
127
124
|
* @name key
|
|
128
125
|
* @api private
|
|
129
126
|
*/
|
|
130
|
-
key(
|
|
127
|
+
key({
|
|
128
|
+
kid, kty, alg, use, key_ops: ops,
|
|
129
|
+
}, allowMulti = false) {
|
|
131
130
|
const { cache } = instance(this);
|
|
132
131
|
|
|
132
|
+
const def = {
|
|
133
|
+
kid, kty, alg, use, key_ops: ops,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const defHash = objectHash(def, {
|
|
137
|
+
algorithm: 'sha256',
|
|
138
|
+
ignoreUnknown: true,
|
|
139
|
+
unorderedArrays: true,
|
|
140
|
+
unorderedSets: true,
|
|
141
|
+
});
|
|
142
|
+
|
|
133
143
|
// refresh keystore on every unknown key but also only upto once every minute
|
|
134
|
-
const freshJwksUri = cache.get(
|
|
144
|
+
const freshJwksUri = cache.get(defHash) || cache.get('throttle');
|
|
135
145
|
|
|
136
146
|
return this.keystore(!freshJwksUri)
|
|
137
147
|
.then(store => store.all(def))
|
|
@@ -139,7 +149,7 @@ class Issuer {
|
|
|
139
149
|
assert(keys.length, 'no valid key found');
|
|
140
150
|
if (!allowMulti) {
|
|
141
151
|
assert.equal(keys.length, 1, 'multiple matching keys, kid must be provided');
|
|
142
|
-
cache.set(
|
|
152
|
+
cache.set(defHash, true);
|
|
143
153
|
}
|
|
144
154
|
return keys[0];
|
|
145
155
|
});
|
|
@@ -196,7 +206,12 @@ class Issuer {
|
|
|
196
206
|
if (parsed.pathname.includes('/.well-known/')) {
|
|
197
207
|
return this.httpClient.get(uri, this.httpOptions())
|
|
198
208
|
.then(expectResponseWithBody(200))
|
|
199
|
-
.then(
|
|
209
|
+
.then(({ body }) => new Issuer(Object.assign(
|
|
210
|
+
{},
|
|
211
|
+
ISSUER_DEFAULTS,
|
|
212
|
+
JSON.parse(body),
|
|
213
|
+
{ [AAD_MULTITENANT]: uri === AAD_MULTITENANT_DISCOVERY }
|
|
214
|
+
)))
|
|
200
215
|
.catch(errorHandler.bind(this));
|
|
201
216
|
}
|
|
202
217
|
|
|
@@ -216,7 +231,12 @@ class Issuer {
|
|
|
216
231
|
const wellKnownUri = url.format(Object.assign({}, parsed, { pathname }));
|
|
217
232
|
return this.httpClient.get(wellKnownUri, this.httpOptions())
|
|
218
233
|
.then(expectResponseWithBody(200))
|
|
219
|
-
.then(
|
|
234
|
+
.then(({ body }) => new Issuer(Object.assign(
|
|
235
|
+
{},
|
|
236
|
+
ISSUER_DEFAULTS,
|
|
237
|
+
JSON.parse(body),
|
|
238
|
+
{ [AAD_MULTITENANT]: wellKnownUri === AAD_MULTITENANT_DISCOVERY }
|
|
239
|
+
)));
|
|
220
240
|
}))
|
|
221
241
|
.catch((err) => {
|
|
222
242
|
if (err instanceof pAny.AggregateError) {
|
package/lib/passport_strategy.js
CHANGED
|
@@ -6,11 +6,11 @@ const url = require('url');
|
|
|
6
6
|
const assert = require('assert');
|
|
7
7
|
|
|
8
8
|
const base64url = require('base64url');
|
|
9
|
-
const uuid = require('uuid/v4');
|
|
10
9
|
const _ = require('lodash');
|
|
11
10
|
|
|
12
11
|
const OpenIdConnectError = require('./open_id_connect_error');
|
|
13
|
-
const
|
|
12
|
+
const { BaseClient } = require('./client');
|
|
13
|
+
const random = require('./util/random');
|
|
14
14
|
|
|
15
15
|
function verified(err, user, info = {}) {
|
|
16
16
|
if (err) {
|
|
@@ -33,7 +33,7 @@ function OpenIDConnectStrategy({
|
|
|
33
33
|
sessionKey,
|
|
34
34
|
usePKCE = false,
|
|
35
35
|
} = {}, verify) {
|
|
36
|
-
assert(client instanceof
|
|
36
|
+
assert(client instanceof BaseClient, 'client must be an instance of openid-client Client');
|
|
37
37
|
assert.equal(typeof verify, 'function', 'verify must be a function');
|
|
38
38
|
|
|
39
39
|
assert(client.issuer && client.issuer.issuer, 'client must have an issuer with an identifier');
|
|
@@ -81,17 +81,17 @@ OpenIDConnectStrategy.prototype.authenticate = function authenticate(req, option
|
|
|
81
81
|
if (_.isEmpty(reqParams)) {
|
|
82
82
|
// provide options object with extra authentication parameters
|
|
83
83
|
const params = _.defaults({}, options, this._params, {
|
|
84
|
-
state:
|
|
84
|
+
state: random(),
|
|
85
85
|
});
|
|
86
86
|
|
|
87
87
|
if (!params.nonce && params.response_type.includes('id_token')) {
|
|
88
|
-
params.nonce =
|
|
88
|
+
params.nonce = random();
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
req.session[sessionKey] = _.pick(params, 'nonce', 'state', 'max_age', 'response_type');
|
|
92
92
|
|
|
93
93
|
if (this._usePKCE) {
|
|
94
|
-
const verifier =
|
|
94
|
+
const verifier = random();
|
|
95
95
|
req.session[sessionKey].code_verifier = verifier;
|
|
96
96
|
|
|
97
97
|
switch (this._usePKCE) { // eslint-disable-line default-case
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openid-client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "OpenID Connect Relying Party (RP, Client) implementation for Node.js servers, supports passportjs",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"auth",
|
|
@@ -42,11 +42,11 @@
|
|
|
42
42
|
"base64url": "^3.0.0",
|
|
43
43
|
"got": "^8.3.2",
|
|
44
44
|
"lodash": "^4.17.11",
|
|
45
|
-
"lru-cache": "^
|
|
46
|
-
"node-jose": "^1.
|
|
45
|
+
"lru-cache": "^5.1.1",
|
|
46
|
+
"node-jose": "^1.1.0",
|
|
47
|
+
"object-hash": "^1.3.1",
|
|
47
48
|
"oidc-token-hash": "^3.0.1",
|
|
48
|
-
"p-any": "^1.1.0"
|
|
49
|
-
"uuid": "^3.3.2"
|
|
49
|
+
"p-any": "^1.1.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@commitlint/cli": "^7.1.2",
|
|
@@ -55,18 +55,13 @@
|
|
|
55
55
|
"eslint": "^5.6.0",
|
|
56
56
|
"eslint-config-airbnb-base": "^13.1.0",
|
|
57
57
|
"eslint-plugin-import": "^2.14.0",
|
|
58
|
-
"husky": "^1.0
|
|
59
|
-
"
|
|
60
|
-
"koa-body": "^4.0.4",
|
|
61
|
-
"koa-ejs": "^4.1.2",
|
|
62
|
-
"koa-router": "^7.4.0",
|
|
63
|
-
"koa-session": "^5.9.0",
|
|
64
|
-
"mocha": "^5.2.0",
|
|
58
|
+
"husky": "^2.1.0",
|
|
59
|
+
"mocha": "^6.1.4",
|
|
65
60
|
"nock": "^10.0.0",
|
|
66
|
-
"nyc": "^
|
|
61
|
+
"nyc": "^14.0.0",
|
|
67
62
|
"readable-mock-req": "^0.2.2",
|
|
68
63
|
"request": "^2.88.0",
|
|
69
|
-
"sinon": "^
|
|
64
|
+
"sinon": "^7.0.0",
|
|
70
65
|
"timekeeper": "^2.1.2"
|
|
71
66
|
},
|
|
72
67
|
"engines": {
|