box-node-sdk 1.35.0 → 1.37.2
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 +37 -2
- package/README.md +1 -1
- package/lib/api-request-manager.d.ts +38 -0
- package/lib/api-request-manager.js +48 -55
- package/lib/api-request-manager.js.map +1 -0
- package/lib/api-request.d.ts +141 -0
- package/lib/api-request.js +202 -281
- package/lib/api-request.js.map +1 -0
- package/lib/box-client.d.ts +269 -0
- package/lib/box-client.js +551 -713
- package/lib/box-client.js.map +1 -0
- package/lib/box-node-sdk.d.ts +216 -0
- package/lib/box-node-sdk.js +317 -352
- package/lib/box-node-sdk.js.map +1 -0
- package/lib/chunked-uploader.d.ts +129 -0
- package/lib/chunked-uploader.js +287 -358
- package/lib/chunked-uploader.js.map +1 -0
- package/lib/enterprise-event-stream.d.ts +82 -0
- package/lib/enterprise-event-stream.js +189 -203
- package/lib/enterprise-event-stream.js.map +1 -0
- package/lib/event-stream.d.ts +92 -0
- package/lib/event-stream.js +274 -302
- package/lib/event-stream.js.map +1 -0
- package/lib/managers/collaboration-allowlist.d.ts +137 -0
- package/lib/managers/collaboration-allowlist.js +200 -0
- package/lib/managers/collaboration-allowlist.js.map +1 -0
- package/lib/managers/collaboration-whitelist.d.ts +3 -0
- package/lib/managers/collaboration-whitelist.js +8 -222
- package/lib/managers/collaboration-whitelist.js.map +1 -0
- package/lib/managers/collaborations.d.ts +166 -0
- package/lib/managers/collaborations.js +225 -258
- package/lib/managers/collaborations.js.map +1 -0
- package/lib/managers/collections.d.ts +42 -0
- package/lib/managers/collections.js +45 -50
- package/lib/managers/collections.js.map +1 -0
- package/lib/managers/comments.d.ts +103 -0
- package/lib/managers/comments.js +158 -173
- package/lib/managers/comments.js.map +1 -0
- package/lib/managers/device-pins.d.ts +52 -0
- package/lib/managers/device-pins.js +75 -88
- package/lib/managers/device-pins.js.map +1 -0
- package/lib/managers/enterprise.d.ts +162 -0
- package/lib/managers/enterprise.js +168 -199
- package/lib/managers/enterprise.js.map +1 -0
- package/lib/managers/events.d.ts +177 -0
- package/lib/managers/events.js +230 -254
- package/lib/managers/events.js.map +1 -0
- package/lib/managers/files.d.ts +772 -0
- package/lib/managers/files.js +1400 -1602
- package/lib/managers/files.js.map +1 -0
- package/lib/managers/folders.d.ts +347 -0
- package/lib/managers/folders.js +551 -567
- package/lib/managers/folders.js.map +1 -0
- package/lib/managers/groups.d.ts +202 -0
- package/lib/managers/groups.js +238 -287
- package/lib/managers/groups.js.map +1 -0
- package/lib/managers/legal-hold-policies.d.ts +190 -0
- package/lib/managers/legal-hold-policies.js +228 -272
- package/lib/managers/legal-hold-policies.js.map +1 -0
- package/lib/managers/metadata.d.ts +228 -0
- package/lib/managers/metadata.js +265 -328
- package/lib/managers/metadata.js.map +1 -0
- package/lib/managers/recent-items.d.ts +38 -0
- package/lib/managers/recent-items.js +32 -39
- package/lib/managers/recent-items.js.map +1 -0
- package/lib/managers/retention-policies.d.ts +213 -0
- package/lib/managers/retention-policies.js +235 -281
- package/lib/managers/retention-policies.js.map +1 -0
- package/lib/managers/search.d.ts +82 -0
- package/lib/managers/search.js +68 -88
- package/lib/managers/search.js.map +1 -0
- package/lib/managers/shared-items.d.ts +33 -0
- package/lib/managers/shared-items.js +54 -62
- package/lib/managers/shared-items.js.map +1 -0
- package/lib/managers/storage-policies.d.ts +86 -0
- package/lib/managers/storage-policies.js +108 -142
- package/lib/managers/storage-policies.js.map +1 -0
- package/lib/managers/tasks.d.ts +161 -0
- package/lib/managers/tasks.js +219 -260
- package/lib/managers/tasks.js.map +1 -0
- package/lib/managers/terms-of-service.d.ts +161 -0
- package/lib/managers/terms-of-service.js +250 -273
- package/lib/managers/terms-of-service.js.map +1 -0
- package/lib/managers/trash.d.ts +30 -0
- package/lib/managers/trash.js +30 -41
- package/lib/managers/trash.js.map +1 -0
- package/lib/managers/users.d.ts +131 -0
- package/lib/managers/users.js +160 -203
- package/lib/managers/users.js.map +1 -0
- package/lib/managers/web-links.d.ts +127 -0
- package/lib/managers/web-links.js +183 -209
- package/lib/managers/web-links.js.map +1 -0
- package/lib/managers/webhooks.d.ts +166 -0
- package/lib/managers/webhooks.js +312 -305
- package/lib/managers/webhooks.js.map +1 -0
- package/lib/sessions/anonymous-session.d.ts +69 -0
- package/lib/sessions/anonymous-session.js +88 -102
- package/lib/sessions/anonymous-session.js.map +1 -0
- package/lib/sessions/app-auth-session.d.ts +92 -0
- package/lib/sessions/app-auth-session.js +140 -160
- package/lib/sessions/app-auth-session.js.map +1 -0
- package/lib/sessions/basic-session.d.ts +56 -0
- package/lib/sessions/basic-session.js +40 -50
- package/lib/sessions/basic-session.js.map +1 -0
- package/lib/sessions/persistent-session.d.ts +96 -0
- package/lib/sessions/persistent-session.js +191 -211
- package/lib/sessions/persistent-session.js.map +1 -0
- package/lib/token-manager.d.ts +191 -0
- package/lib/token-manager.js +390 -465
- package/lib/token-manager.js.map +1 -0
- package/lib/util/config.d.ts +86 -0
- package/lib/util/config.js +124 -152
- package/lib/util/config.js.map +1 -0
- package/lib/util/errors.d.ts +50 -0
- package/lib/util/errors.js +134 -145
- package/lib/util/errors.js.map +1 -0
- package/lib/util/exponential-backoff.d.ts +11 -0
- package/lib/util/exponential-backoff.js +10 -22
- package/lib/util/exponential-backoff.js.map +1 -0
- package/lib/util/paging-iterator.d.ts +53 -0
- package/lib/util/paging-iterator.js +202 -218
- package/lib/util/paging-iterator.js.map +1 -0
- package/lib/util/url-path.d.ts +16 -0
- package/lib/util/url-path.js +20 -35
- package/lib/util/url-path.js.map +1 -0
- package/package.json +24 -9
package/lib/token-manager.js
CHANGED
|
@@ -1,80 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* @fileoverview Token Manager
|
|
3
4
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
6
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
7
|
+
};
|
|
7
8
|
// ------------------------------------------------------------------------------
|
|
8
|
-
//
|
|
9
|
+
// Requirements
|
|
9
10
|
// ------------------------------------------------------------------------------
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
* @property {string} [ip] The IP Address of the requesting user. This IP will be reflected in authentication
|
|
17
|
-
* notification emails sent to your users on login. Defaults to the IP address of the
|
|
18
|
-
* server requesting the tokens.
|
|
19
|
-
*/
|
|
20
|
-
|
|
11
|
+
var bluebird_1 = __importDefault(require("bluebird"));
|
|
12
|
+
var http_status_1 = __importDefault(require("http-status"));
|
|
13
|
+
var jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
14
|
+
var uuid_1 = __importDefault(require("uuid"));
|
|
15
|
+
var errors_1 = __importDefault(require("./util/errors"));
|
|
16
|
+
var exponential_backoff_1 = __importDefault(require("./util/exponential-backoff"));
|
|
21
17
|
/**
|
|
22
|
-
*
|
|
23
|
-
* @
|
|
24
|
-
* @
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Parameters for creating an actor token via token exchange
|
|
29
|
-
* @typedef {Object} ActorParams
|
|
30
|
-
* @property {string} id The external identifier for the actor
|
|
31
|
-
* @property {string} name The display name of the actor
|
|
32
|
-
*/
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* An object representing all token information for a single Box user.
|
|
36
|
-
*
|
|
37
|
-
* @typedef {Object} TokenInfo
|
|
38
|
-
* @property {string} accessToken The API access token. Used to authenticate API requests to a certain
|
|
39
|
-
* user and/or application.
|
|
40
|
-
* @property {int} acquiredAtMS The time that the tokens were acquired.
|
|
41
|
-
* @property {int} accessTokenTTLMS The TTL of the access token. Can be used with acquiredAtMS to
|
|
42
|
-
* calculate if the current access token has expired.
|
|
43
|
-
* @property {string} [refreshToken] The API refresh token is a Longer-lasting than an access token, and can
|
|
44
|
-
* be used to gain a new access token if the current access token becomes
|
|
45
|
-
* expired. Grants like the 'client credentials' grant don't return a
|
|
46
|
-
* refresh token, and have no refresh capabilities.
|
|
18
|
+
* Determines whether a JWT auth error can be retried
|
|
19
|
+
* @param {Error} err The JWT auth error
|
|
20
|
+
* @returns {boolean} True if the error is retryable
|
|
47
21
|
*/
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
return false;
|
|
22
|
+
function isJWTAuthErrorRetryable(err /* FIXME */) {
|
|
23
|
+
if (err.authExpired &&
|
|
24
|
+
err.response.headers.date &&
|
|
25
|
+
(err.response.body.error_description.indexOf('exp') > -1 ||
|
|
26
|
+
err.response.body.error_description.indexOf('jti') > -1)) {
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
else if (err.statusCode === 429 || err.statusCode >= 500) {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
62
33
|
}
|
|
63
|
-
|
|
64
|
-
// ------------------------------------------------------------------------------
|
|
65
|
-
// Requirements
|
|
66
|
-
// ------------------------------------------------------------------------------
|
|
67
|
-
var errors = require('./util/errors'),
|
|
68
|
-
jwt = require('jsonwebtoken'),
|
|
69
|
-
uuid = require('uuid'),
|
|
70
|
-
httpStatusCodes = require('http-status'),
|
|
71
|
-
Promise = require('bluebird'),
|
|
72
|
-
getRetryTimeout = require('./util/exponential-backoff');
|
|
73
|
-
|
|
74
34
|
// ------------------------------------------------------------------------------
|
|
75
35
|
// Constants
|
|
76
36
|
// ------------------------------------------------------------------------------
|
|
77
|
-
|
|
78
37
|
/**
|
|
79
38
|
* Collection of grant types that can be used to acquire tokens via OAuth2
|
|
80
39
|
*
|
|
@@ -82,39 +41,34 @@ var errors = require('./util/errors'),
|
|
|
82
41
|
* @enum {string}
|
|
83
42
|
*/
|
|
84
43
|
var grantTypes = {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
44
|
+
AUTHORIZATION_CODE: 'authorization_code',
|
|
45
|
+
REFRESH_TOKEN: 'refresh_token',
|
|
46
|
+
CLIENT_CREDENTIALS: 'client_credentials',
|
|
47
|
+
JWT: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
|
48
|
+
TOKEN_EXCHANGE: 'urn:ietf:params:oauth:grant-type:token-exchange',
|
|
90
49
|
};
|
|
91
|
-
|
|
92
50
|
/**
|
|
93
51
|
* Collection of paths to interact with Box OAuth2 tokening system
|
|
94
52
|
*
|
|
95
53
|
* @readonly
|
|
96
54
|
* @enum {string}
|
|
97
55
|
*/
|
|
98
|
-
var tokenPaths
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
56
|
+
var tokenPaths;
|
|
57
|
+
(function (tokenPaths) {
|
|
58
|
+
tokenPaths["ROOT"] = "/oauth2";
|
|
59
|
+
tokenPaths["GET"] = "/token";
|
|
60
|
+
tokenPaths["REVOKE"] = "/revoke";
|
|
61
|
+
})(tokenPaths || (tokenPaths = {}));
|
|
104
62
|
// Timer used to track elapsed time starting with executing an async request and ending with emitting the response.
|
|
105
|
-
var asyncRequestTimer
|
|
106
|
-
|
|
63
|
+
var asyncRequestTimer /* FIXME */;
|
|
107
64
|
// The XFF header label - Used to give the API better information for uploads, rate-limiting, etc.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
65
|
+
var HEADER_XFF = 'X-Forwarded-For';
|
|
66
|
+
var ACCESS_TOKEN_TYPE = 'urn:ietf:params:oauth:token-type:access_token';
|
|
67
|
+
var ACTOR_TOKEN_TYPE = 'urn:ietf:params:oauth:token-type:id_token';
|
|
68
|
+
var BOX_JWT_AUDIENCE = 'https://api.box.com/oauth2/token';
|
|
114
69
|
// ------------------------------------------------------------------------------
|
|
115
70
|
// Private
|
|
116
71
|
// ------------------------------------------------------------------------------
|
|
117
|
-
|
|
118
72
|
/**
|
|
119
73
|
* Parse the response body to create a new TokenInfo object.
|
|
120
74
|
*
|
|
@@ -122,17 +76,16 @@ const BOX_JWT_AUDIENCE = 'https://api.box.com/oauth2/token';
|
|
|
122
76
|
* @returns {TokenInfo} A TokenInfo object.
|
|
123
77
|
* @private
|
|
124
78
|
*/
|
|
125
|
-
function getTokensFromGrantResponse(grantResponseBody) {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
79
|
+
function getTokensFromGrantResponse(grantResponseBody /* FIXME */) {
|
|
80
|
+
return {
|
|
81
|
+
// Set the access token & refresh token (if passed)
|
|
82
|
+
accessToken: grantResponseBody.access_token,
|
|
83
|
+
refreshToken: grantResponseBody.refresh_token,
|
|
84
|
+
// Box API sends back expires_in in seconds, we convert to ms for consistency of keeping all time in ms
|
|
85
|
+
accessTokenTTLMS: parseInt(grantResponseBody.expires_in, 10) * 1000,
|
|
86
|
+
acquiredAtMS: Date.now(),
|
|
87
|
+
};
|
|
134
88
|
}
|
|
135
|
-
|
|
136
89
|
/**
|
|
137
90
|
* Determines if a given string could represent an authorization code or token.
|
|
138
91
|
*
|
|
@@ -141,9 +94,8 @@ function getTokensFromGrantResponse(grantResponseBody) {
|
|
|
141
94
|
* @private
|
|
142
95
|
*/
|
|
143
96
|
function isValidCodeOrToken(codeOrToken) {
|
|
144
|
-
|
|
97
|
+
return typeof codeOrToken === 'string' && codeOrToken.length > 0;
|
|
145
98
|
}
|
|
146
|
-
|
|
147
99
|
/**
|
|
148
100
|
* Determines if a token grant response is valid
|
|
149
101
|
*
|
|
@@ -152,26 +104,24 @@ function isValidCodeOrToken(codeOrToken) {
|
|
|
152
104
|
* @returns {boolean} True if response body has expected fields, false if not.
|
|
153
105
|
* @private
|
|
154
106
|
*/
|
|
155
|
-
function isValidTokenResponse(grantType, responseBody) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
107
|
+
function isValidTokenResponse(grantType, responseBody /* FIXME */) {
|
|
108
|
+
if (!isValidCodeOrToken(responseBody.access_token)) {
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
if (typeof responseBody.expires_in !== 'number') {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
// Check the refresh_token for certain types of grants
|
|
115
|
+
if (grantType === 'authorization_code' || grantType === 'refresh_token') {
|
|
116
|
+
if (!isValidCodeOrToken(responseBody.refresh_token)) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return true;
|
|
169
121
|
}
|
|
170
|
-
|
|
171
122
|
// ------------------------------------------------------------------------------
|
|
172
123
|
// Public
|
|
173
124
|
// ------------------------------------------------------------------------------
|
|
174
|
-
|
|
175
125
|
/**
|
|
176
126
|
* Manager for API access abd refresh tokens
|
|
177
127
|
*
|
|
@@ -179,354 +129,329 @@ function isValidTokenResponse(grantType, responseBody) {
|
|
|
179
129
|
* @param {APIRequestManager} requestManager The API Request Manager
|
|
180
130
|
* @constructor
|
|
181
131
|
*/
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
*/
|
|
507
|
-
revokeTokens(token, options) {
|
|
508
|
-
var params = {
|
|
509
|
-
method: 'POST',
|
|
510
|
-
url: this.oauthBaseURL + tokenPaths.REVOKE,
|
|
511
|
-
form: {
|
|
512
|
-
token,
|
|
513
|
-
client_id: this.config.clientID,
|
|
514
|
-
client_secret: this.config.clientSecret
|
|
515
|
-
}
|
|
516
|
-
};
|
|
517
|
-
|
|
518
|
-
if (options && options.ip) {
|
|
519
|
-
params.headers = {};
|
|
520
|
-
params.headers[HEADER_XFF] = options.ip;
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
return this.requestManager.makeRequest(params);
|
|
524
|
-
}
|
|
525
|
-
};
|
|
526
|
-
|
|
527
|
-
/**
|
|
528
|
-
* Provides interactions with Box OAuth2 tokening system.
|
|
529
|
-
*
|
|
530
|
-
* @module box-node-sdk/lib/token-manager
|
|
531
|
-
*/
|
|
132
|
+
var TokenManager = /** @class */ (function () {
|
|
133
|
+
function TokenManager(config, requestManager) {
|
|
134
|
+
this.config = config;
|
|
135
|
+
this.oauthBaseURL = config.apiRootURL + tokenPaths.ROOT;
|
|
136
|
+
this.requestManager = requestManager;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Given a TokenInfo object, returns whether its access token is expired. An access token is considered
|
|
140
|
+
* expired once its TTL surpasses the current time outside of the given buffer. This is a public method so
|
|
141
|
+
* that other modules may check the validity of their tokens.
|
|
142
|
+
*
|
|
143
|
+
* @param {TokenInfo} tokenInfo the token info to be written
|
|
144
|
+
* @param {int} [bufferMS] An optional buffer we'd like to test against. The greater this buffer, the more aggressively
|
|
145
|
+
* we'll call a token invalid.
|
|
146
|
+
* @returns {boolean} True if token is valid outside of buffer, otherwise false
|
|
147
|
+
*/
|
|
148
|
+
TokenManager.prototype.isAccessTokenValid = function (tokenInfo, bufferMS) {
|
|
149
|
+
if (typeof tokenInfo.acquiredAtMS === 'undefined' ||
|
|
150
|
+
typeof tokenInfo.accessTokenTTLMS === 'undefined') {
|
|
151
|
+
return false;
|
|
152
|
+
}
|
|
153
|
+
bufferMS = bufferMS || 0;
|
|
154
|
+
var expireTime = tokenInfo.acquiredAtMS + tokenInfo.accessTokenTTLMS - bufferMS;
|
|
155
|
+
return expireTime > Date.now();
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Acquires OAuth2 tokens using a grant type (authorization_code, password, refresh_token)
|
|
159
|
+
*
|
|
160
|
+
* @param {Object} formParams - should contain all params expected by Box OAuth2 token endpoint
|
|
161
|
+
* @param {TokenRequestOptions} [options] - Sets optional behavior for the token grant, null for default behavior
|
|
162
|
+
* @returns {Promise<TokenInfo>} Promise resolving to the token info
|
|
163
|
+
* @private
|
|
164
|
+
*/
|
|
165
|
+
TokenManager.prototype.getTokens = function (formParams, options) {
|
|
166
|
+
var params = {
|
|
167
|
+
method: 'POST',
|
|
168
|
+
url: this.oauthBaseURL + tokenPaths.GET,
|
|
169
|
+
headers: {},
|
|
170
|
+
form: formParams,
|
|
171
|
+
};
|
|
172
|
+
options = options || {};
|
|
173
|
+
// add in app-specific id and secret to auth with Box
|
|
174
|
+
params.form.client_id = this.config.clientID;
|
|
175
|
+
params.form.client_secret = this.config.clientSecret;
|
|
176
|
+
if (options.ip) {
|
|
177
|
+
params.headers[HEADER_XFF] = options.ip;
|
|
178
|
+
}
|
|
179
|
+
return this.requestManager.makeRequest(params).then(function (response /* FIXME */) {
|
|
180
|
+
// Response Error: The API is telling us that we attempted an invalid token grant. This
|
|
181
|
+
// means that our refresh token or auth code has exipred, so propagate an "Expired Tokens"
|
|
182
|
+
// error.
|
|
183
|
+
if (response.body &&
|
|
184
|
+
response.body.error &&
|
|
185
|
+
response.body.error === 'invalid_grant') {
|
|
186
|
+
var errDescription = response.body.error_description;
|
|
187
|
+
var message = errDescription
|
|
188
|
+
? "Auth Error: " + errDescription
|
|
189
|
+
: undefined;
|
|
190
|
+
throw errors_1.default.buildAuthError(response, message);
|
|
191
|
+
}
|
|
192
|
+
// Unexpected Response: If the token request couldn't get a valid response, then we're
|
|
193
|
+
// out of options. Build an "Unexpected Response" error and propagate it out for the
|
|
194
|
+
// consumer to handle.
|
|
195
|
+
if (response.statusCode !== http_status_1.default.OK ||
|
|
196
|
+
response.body instanceof Buffer) {
|
|
197
|
+
throw errors_1.default.buildUnexpectedResponseError(response);
|
|
198
|
+
}
|
|
199
|
+
// Check to see if token response is valid in case the API returns us a 200 with a malformed token
|
|
200
|
+
if (!isValidTokenResponse(formParams.grant_type, response.body)) {
|
|
201
|
+
throw errors_1.default.buildResponseError(response, 'Token format from response invalid');
|
|
202
|
+
}
|
|
203
|
+
// Got valid token response. Parse out the TokenInfo and propagate it back.
|
|
204
|
+
return getTokensFromGrantResponse(response.body);
|
|
205
|
+
});
|
|
206
|
+
};
|
|
207
|
+
/**
|
|
208
|
+
* Acquires token info using an authorization code
|
|
209
|
+
*
|
|
210
|
+
* @param {string} authorizationCode - authorization code issued by Box
|
|
211
|
+
* @param {TokenRequestOptions} [options] - Sets optional behavior for the token grant
|
|
212
|
+
* @returns {Promise<TokenInfo>} Promise resolving to the token info
|
|
213
|
+
*/
|
|
214
|
+
TokenManager.prototype.getTokensAuthorizationCodeGrant = function (authorizationCode, options) {
|
|
215
|
+
if (!isValidCodeOrToken(authorizationCode)) {
|
|
216
|
+
return bluebird_1.default.reject(new Error('Invalid authorization code.'));
|
|
217
|
+
}
|
|
218
|
+
var params = {
|
|
219
|
+
grant_type: grantTypes.AUTHORIZATION_CODE,
|
|
220
|
+
code: authorizationCode,
|
|
221
|
+
};
|
|
222
|
+
return this.getTokens(params, options);
|
|
223
|
+
};
|
|
224
|
+
/**
|
|
225
|
+
* Acquires token info using the client credentials grant.
|
|
226
|
+
*
|
|
227
|
+
* @param {TokenRequestOptions} [options] - Sets optional behavior for the token grant
|
|
228
|
+
* @returns {Promise<TokenInfo>} Promise resolving to the token info
|
|
229
|
+
*/
|
|
230
|
+
TokenManager.prototype.getTokensClientCredentialsGrant = function (options) {
|
|
231
|
+
var params = {
|
|
232
|
+
grant_type: grantTypes.CLIENT_CREDENTIALS,
|
|
233
|
+
};
|
|
234
|
+
return this.getTokens(params, options);
|
|
235
|
+
};
|
|
236
|
+
/**
|
|
237
|
+
* Refreshes the access and refresh tokens for a given refresh token.
|
|
238
|
+
*
|
|
239
|
+
* @param {string} refreshToken - A valid OAuth refresh token
|
|
240
|
+
* @param {TokenRequestOptions} [options] - Sets optional behavior for the token grant
|
|
241
|
+
* @returns {Promise<TokenInfo>} Promise resolving to the token info
|
|
242
|
+
*/
|
|
243
|
+
TokenManager.prototype.getTokensRefreshGrant = function (refreshToken, options) {
|
|
244
|
+
if (!isValidCodeOrToken(refreshToken)) {
|
|
245
|
+
return bluebird_1.default.reject(new Error('Invalid refresh token.'));
|
|
246
|
+
}
|
|
247
|
+
var params = {
|
|
248
|
+
grant_type: grantTypes.REFRESH_TOKEN,
|
|
249
|
+
refresh_token: refreshToken,
|
|
250
|
+
};
|
|
251
|
+
return this.getTokens(params, options);
|
|
252
|
+
};
|
|
253
|
+
/**
|
|
254
|
+
* Gets tokens for enterprise administration of app users
|
|
255
|
+
* @param {string} type The type of token to create, "user" or "enterprise"
|
|
256
|
+
* @param {string} id The ID of the enterprise to generate a token for
|
|
257
|
+
* @param {TokenRequestOptions} [options] - Sets optional behavior for the token grant
|
|
258
|
+
* @returns {Promise<TokenInfo>} Promise resolving to the token info
|
|
259
|
+
*/
|
|
260
|
+
TokenManager.prototype.getTokensJWTGrant = function (type, id, options) {
|
|
261
|
+
var _this = this;
|
|
262
|
+
if (!this.config.appAuth.keyID) {
|
|
263
|
+
return bluebird_1.default.reject(new Error('Must provide app auth configuration to use JWT Grant'));
|
|
264
|
+
}
|
|
265
|
+
var claims = {
|
|
266
|
+
exp: Math.floor(Date.now() / 1000) + this.config.appAuth.expirationTime,
|
|
267
|
+
box_sub_type: type,
|
|
268
|
+
};
|
|
269
|
+
var jwtOptions = {
|
|
270
|
+
algorithm: this.config.appAuth.algorithm,
|
|
271
|
+
audience: BOX_JWT_AUDIENCE,
|
|
272
|
+
subject: id,
|
|
273
|
+
issuer: this.config.clientID,
|
|
274
|
+
jwtid: uuid_1.default.v4(),
|
|
275
|
+
noTimestamp: !this.config.appAuth.verifyTimestamp,
|
|
276
|
+
keyid: this.config.appAuth.keyID,
|
|
277
|
+
};
|
|
278
|
+
var keyParams = {
|
|
279
|
+
key: this.config.appAuth.privateKey,
|
|
280
|
+
passphrase: this.config.appAuth.passphrase,
|
|
281
|
+
};
|
|
282
|
+
var assertion;
|
|
283
|
+
try {
|
|
284
|
+
assertion = jsonwebtoken_1.default.sign(claims, keyParams, jwtOptions);
|
|
285
|
+
}
|
|
286
|
+
catch (jwtErr) {
|
|
287
|
+
return bluebird_1.default.reject(jwtErr);
|
|
288
|
+
}
|
|
289
|
+
var params = {
|
|
290
|
+
grant_type: grantTypes.JWT,
|
|
291
|
+
assertion: assertion,
|
|
292
|
+
};
|
|
293
|
+
// Start the request timer immediately before executing the async request
|
|
294
|
+
asyncRequestTimer = process.hrtime();
|
|
295
|
+
return this.getTokens(params, options).catch(function (err) {
|
|
296
|
+
return _this.retryJWTGrant(claims, jwtOptions, keyParams, params, options, err, 0);
|
|
297
|
+
});
|
|
298
|
+
};
|
|
299
|
+
/**
|
|
300
|
+
* Attempt a retry if possible and create a new JTI claim. If the request hasn't exceeded it's maximum number of retries,
|
|
301
|
+
* re-execute the request (after the retry interval). Otherwise, propagate a new error.
|
|
302
|
+
*
|
|
303
|
+
* @param {Object} claims - JTI claims object
|
|
304
|
+
* @param {Object} [jwtOptions] - JWT options for the signature
|
|
305
|
+
* @param {Object} keyParams - Key JWT parameters object that contains the private key and the passphrase
|
|
306
|
+
* @param {Object} params - Should contain all params expected by Box OAuth2 token endpoint
|
|
307
|
+
* @param {TokenRequestOptions} [options] - Sets optional behavior for the token grant
|
|
308
|
+
* @param {Error} error - Error from the previous JWT request
|
|
309
|
+
* @param {int} numRetries - Number of retries attempted
|
|
310
|
+
* @returns {Promise<TokenInfo>} Promise resolving to the token info
|
|
311
|
+
*/
|
|
312
|
+
// eslint-disable-next-line max-params
|
|
313
|
+
TokenManager.prototype.retryJWTGrant = function (claims /* FIXME */, jwtOptions /* FIXME */, keyParams /* FIXME */, params /* FIXME */, options, error /* FIXME */, numRetries) {
|
|
314
|
+
var _this = this;
|
|
315
|
+
if (numRetries < this.config.numMaxRetries &&
|
|
316
|
+
isJWTAuthErrorRetryable(error)) {
|
|
317
|
+
var retryTimeout;
|
|
318
|
+
numRetries += 1;
|
|
319
|
+
// If the retry strategy is defined, then use it to determine the time (in ms) until the next retry or to
|
|
320
|
+
// propagate an error to the user.
|
|
321
|
+
if (this.config.retryStrategy) {
|
|
322
|
+
// Get the total elapsed time so far since the request was executed
|
|
323
|
+
var totalElapsedTime = process.hrtime(asyncRequestTimer);
|
|
324
|
+
var totalElapsedTimeMS = totalElapsedTime[0] * 1000 + totalElapsedTime[1] / 1000000;
|
|
325
|
+
var retryOptions = {
|
|
326
|
+
error: error,
|
|
327
|
+
numRetryAttempts: numRetries,
|
|
328
|
+
numMaxRetries: this.config.numMaxRetries,
|
|
329
|
+
retryIntervalMS: this.config.retryIntervalMS,
|
|
330
|
+
totalElapsedTimeMS: totalElapsedTimeMS,
|
|
331
|
+
};
|
|
332
|
+
retryTimeout = this.config.retryStrategy(retryOptions);
|
|
333
|
+
// If the retry strategy doesn't return a number/time in ms, then propagate the response error to the user.
|
|
334
|
+
// However, if the retry strategy returns its own error, this will be propagated to the user instead.
|
|
335
|
+
if (typeof retryTimeout !== 'number') {
|
|
336
|
+
if (retryTimeout instanceof Error) {
|
|
337
|
+
error = retryTimeout;
|
|
338
|
+
}
|
|
339
|
+
throw error;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
else if (error.hasOwnProperty('response') &&
|
|
343
|
+
error.response.hasOwnProperty('headers') &&
|
|
344
|
+
error.response.headers.hasOwnProperty('retry-after')) {
|
|
345
|
+
retryTimeout = error.response.headers['retry-after'] * 1000;
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
retryTimeout = exponential_backoff_1.default(numRetries, this.config.retryIntervalMS);
|
|
349
|
+
}
|
|
350
|
+
var time = Math.floor(Date.now() / 1000);
|
|
351
|
+
if (error.response.headers.date) {
|
|
352
|
+
time = Math.floor(Date.parse(error.response.headers.date) / 1000);
|
|
353
|
+
}
|
|
354
|
+
// Add length of retry timeout to current expiration time to calculate the expiration time for the JTI claim.
|
|
355
|
+
claims.exp =
|
|
356
|
+
time + this.config.appAuth.expirationTime + retryTimeout / 1000;
|
|
357
|
+
jwtOptions.jwtid = uuid_1.default.v4();
|
|
358
|
+
try {
|
|
359
|
+
params.assertion = jsonwebtoken_1.default.sign(claims, keyParams, jwtOptions);
|
|
360
|
+
}
|
|
361
|
+
catch (jwtErr) {
|
|
362
|
+
throw jwtErr;
|
|
363
|
+
}
|
|
364
|
+
return bluebird_1.default.delay(retryTimeout).then(function () {
|
|
365
|
+
// Start the request timer immediately before executing the async request
|
|
366
|
+
asyncRequestTimer = process.hrtime();
|
|
367
|
+
return _this.getTokens(params, options).catch(function (err) {
|
|
368
|
+
return _this.retryJWTGrant(claims, jwtOptions, keyParams, params, options, err, numRetries);
|
|
369
|
+
});
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
else if (numRetries >= this.config.numMaxRetries) {
|
|
373
|
+
error.maxRetriesExceeded = true;
|
|
374
|
+
}
|
|
375
|
+
throw error;
|
|
376
|
+
};
|
|
377
|
+
/**
|
|
378
|
+
* Exchange a valid access token for one with a lower scope, or delegated to
|
|
379
|
+
* an external user identifier.
|
|
380
|
+
*
|
|
381
|
+
* @param {string} accessToken - The valid access token to exchange
|
|
382
|
+
* @param {string|string[]} scopes - The scope(s) of the new access token
|
|
383
|
+
* @param {string} [resource] - The absolute URL of an API resource to restrict the new token to
|
|
384
|
+
* @param {Object} [options] - Optional parameters
|
|
385
|
+
* @param {TokenRequestOptions} [options.tokenRequestOptions] - Sets optional behavior for the token grant
|
|
386
|
+
* @param {ActorParams} [options.actor] - Optional actor parameters for creating annotator tokens
|
|
387
|
+
* @param {SharedLinkParams} [options.sharedLink] - Optional shared link parameters for creating tokens using shared links
|
|
388
|
+
* @returns {Promise<TokenInfo>} Promise resolving to the new token info
|
|
389
|
+
*/
|
|
390
|
+
TokenManager.prototype.exchangeToken = function (accessToken, scopes, resource, options) {
|
|
391
|
+
var params = {
|
|
392
|
+
grant_type: grantTypes.TOKEN_EXCHANGE,
|
|
393
|
+
subject_token_type: ACCESS_TOKEN_TYPE,
|
|
394
|
+
subject_token: accessToken,
|
|
395
|
+
scope: typeof scopes === 'string' ? scopes : scopes.join(' '),
|
|
396
|
+
};
|
|
397
|
+
if (resource) {
|
|
398
|
+
params.resource = resource;
|
|
399
|
+
}
|
|
400
|
+
if (options && options.sharedLink) {
|
|
401
|
+
params.box_shared_link = options.sharedLink.url;
|
|
402
|
+
}
|
|
403
|
+
if (options && options.actor) {
|
|
404
|
+
var payload = {
|
|
405
|
+
iss: this.config.clientID,
|
|
406
|
+
sub: options.actor.id,
|
|
407
|
+
aud: BOX_JWT_AUDIENCE,
|
|
408
|
+
box_sub_type: 'external',
|
|
409
|
+
name: options.actor.name,
|
|
410
|
+
};
|
|
411
|
+
var jwtOptions = {
|
|
412
|
+
algorithm: 'none',
|
|
413
|
+
expiresIn: '1m',
|
|
414
|
+
noTimestamp: true,
|
|
415
|
+
jwtid: uuid_1.default.v4(),
|
|
416
|
+
};
|
|
417
|
+
var token;
|
|
418
|
+
try {
|
|
419
|
+
token = jsonwebtoken_1.default.sign(payload, 'UNUSED', jwtOptions /* FIXME */);
|
|
420
|
+
}
|
|
421
|
+
catch (jwtError) {
|
|
422
|
+
return bluebird_1.default.reject(jwtError);
|
|
423
|
+
}
|
|
424
|
+
params.actor_token = token;
|
|
425
|
+
params.actor_token_type = ACTOR_TOKEN_TYPE;
|
|
426
|
+
}
|
|
427
|
+
return this.getTokens(params, options && options.tokenRequestOptions
|
|
428
|
+
? options.tokenRequestOptions
|
|
429
|
+
: null);
|
|
430
|
+
};
|
|
431
|
+
/**
|
|
432
|
+
* Revokes a token pair associated with a given access or refresh token.
|
|
433
|
+
*
|
|
434
|
+
* @param {string} token - A valid access or refresh token to revoke
|
|
435
|
+
* @param {TokenRequestOptions} [options] - Sets optional behavior for the token grant
|
|
436
|
+
* @returns {Promise} Promise resolving if the revoke succeeds
|
|
437
|
+
*/
|
|
438
|
+
TokenManager.prototype.revokeTokens = function (token, options) {
|
|
439
|
+
var params = {
|
|
440
|
+
method: 'POST',
|
|
441
|
+
url: this.oauthBaseURL + tokenPaths.REVOKE,
|
|
442
|
+
form: {
|
|
443
|
+
token: token,
|
|
444
|
+
client_id: this.config.clientID,
|
|
445
|
+
client_secret: this.config.clientSecret,
|
|
446
|
+
},
|
|
447
|
+
};
|
|
448
|
+
if (options && options.ip) {
|
|
449
|
+
params.headers = {};
|
|
450
|
+
params.headers[HEADER_XFF] = options.ip;
|
|
451
|
+
}
|
|
452
|
+
return this.requestManager.makeRequest(params);
|
|
453
|
+
};
|
|
454
|
+
return TokenManager;
|
|
455
|
+
}());
|
|
532
456
|
module.exports = TokenManager;
|
|
457
|
+
//# sourceMappingURL=token-manager.js.map
|