postman-runtime 7.28.0 → 7.28.4
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.yaml +46 -8
- package/dist/index.js +1 -1
- package/lib/authorizer/auth-interface.js +8 -1
- package/lib/authorizer/ntlm.js +22 -2
- package/lib/authorizer/oauth1.js +56 -14
- package/lib/requester/requester.js +17 -4
- package/lib/runner/instruction.js +3 -0
- package/lib/runner/request-helpers-presend.js +1 -1
- package/package.json +12 -11
|
@@ -7,15 +7,22 @@ var _ = require('lodash'),
|
|
|
7
7
|
*
|
|
8
8
|
* @constructs AuthInterface
|
|
9
9
|
* @param {RequestAuth} auth
|
|
10
|
+
* @param {Object} protocolProfileBehavior - Protocol profile behaviors
|
|
10
11
|
* @return {AuthInterface}
|
|
11
12
|
* @throws {Error}
|
|
12
13
|
*/
|
|
13
|
-
createAuthInterface = function (auth) {
|
|
14
|
+
createAuthInterface = function (auth, protocolProfileBehavior) {
|
|
14
15
|
if (!(auth && auth.parameters && auth.parameters())) {
|
|
15
16
|
throw new Error('runtime~createAuthInterface: invalid auth');
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
return /** @lends AuthInterface.prototype **/{
|
|
20
|
+
/**
|
|
21
|
+
* @private
|
|
22
|
+
* @property {protocolProfileBehavior} - Protocol profile behaviors
|
|
23
|
+
*/
|
|
24
|
+
_protocolProfileBehavior: protocolProfileBehavior || {},
|
|
25
|
+
|
|
19
26
|
/**
|
|
20
27
|
* @param {String|Array<String>} keys
|
|
21
28
|
* @return {*} Returns a value for a key or an object having all keys & values depending on the input
|
package/lib/authorizer/ntlm.js
CHANGED
|
@@ -36,6 +36,7 @@ var ntlmUtil = require('httpntlm').ntlm,
|
|
|
36
36
|
* - Down-Level Logon name format `DOMAIN\USERNAME`
|
|
37
37
|
* - User Principal Name format `USERNAME@DOMAIN`
|
|
38
38
|
*
|
|
39
|
+
* @private
|
|
39
40
|
* @param {String} username - Username string to parse from
|
|
40
41
|
* @return {Object} - An object with `username` and `domain` fields, which are `strings`.
|
|
41
42
|
*/
|
|
@@ -83,6 +84,26 @@ function parseParametersFromUsername (username) {
|
|
|
83
84
|
};
|
|
84
85
|
}
|
|
85
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Check if `WWW-Authenticate` header has NTLM challenge.
|
|
89
|
+
*
|
|
90
|
+
* @private
|
|
91
|
+
* @param {*} headers - Postman headers instance
|
|
92
|
+
* @returns {Boolean}
|
|
93
|
+
*/
|
|
94
|
+
function hasNTLMChallenge (headers) {
|
|
95
|
+
// Case 1: multiple headers
|
|
96
|
+
// - WWW-Authenticate: NTLM
|
|
97
|
+
// - WWW-Authenticate: Negotiate
|
|
98
|
+
if (headers.has(WWW_AUTHENTICATE, NTLM) || headers.has(WWW_AUTHENTICATE, NEGOTIATE)) {
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Case 2: single header
|
|
103
|
+
// - WWW-Authenticate: Negotiate, NTLM
|
|
104
|
+
return String(headers.get(WWW_AUTHENTICATE)).includes(NTLM);
|
|
105
|
+
}
|
|
106
|
+
|
|
86
107
|
/**
|
|
87
108
|
* NTLM auth while authenticating requires negotiateMessage (type 1) and authenticateMessage (type 3) to be stored.
|
|
88
109
|
* Also it needs to know which stage is it in (INITIALIZED, T1_MSG_CREATED and T3_MSG_CREATED).
|
|
@@ -170,8 +191,7 @@ module.exports = {
|
|
|
170
191
|
|
|
171
192
|
if (state === STATES.INITIALIZED) {
|
|
172
193
|
// Nothing to do if the server does not ask us for auth in the first place.
|
|
173
|
-
if (!(response.headers
|
|
174
|
-
response.headers.has(WWW_AUTHENTICATE, NEGOTIATE))) {
|
|
194
|
+
if (!hasNTLMChallenge(response.headers)) {
|
|
175
195
|
return done(null, true);
|
|
176
196
|
}
|
|
177
197
|
|
package/lib/authorizer/oauth1.js
CHANGED
|
@@ -42,7 +42,7 @@ function getOAuth1BaseUrl (url) {
|
|
|
42
42
|
host = ((port === HTTP_PORT ||
|
|
43
43
|
port === HTTPS_PORT ||
|
|
44
44
|
port === undefined) && url.hostname) || url.host,
|
|
45
|
-
path = url.
|
|
45
|
+
path = url.path,
|
|
46
46
|
|
|
47
47
|
// trim to convert 'http:' from Node's URL object to 'http'
|
|
48
48
|
protocol = _.trimEnd(url.protocol || PROTOCOL_HTTP, PROTOCOL_SEPARATOR);
|
|
@@ -52,6 +52,34 @@ function getOAuth1BaseUrl (url) {
|
|
|
52
52
|
return protocol.toLowerCase() + host.toLowerCase() + path;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Query parameters are encoded with WHATWG encoding in the request. OAuth1.0
|
|
57
|
+
* requires the query params to be encoded with the RFC-3986 standard. This
|
|
58
|
+
* function decodes the query parameters and encodes them to the required RFC-3986
|
|
59
|
+
* standard. For details: https://oauth.net/core/1.0a/#encoding_parameters
|
|
60
|
+
*
|
|
61
|
+
* @param {Request} request - request to update query parameters
|
|
62
|
+
* @param {Object} url - Node.js like url object
|
|
63
|
+
*/
|
|
64
|
+
function updateQueryParamEncoding (request, url) {
|
|
65
|
+
// early bailout if no query is set.
|
|
66
|
+
if (!url.query) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const queryParams = oAuth1.decodeForm(url.query);
|
|
71
|
+
|
|
72
|
+
// clear all query parameters
|
|
73
|
+
request.url.query.clear();
|
|
74
|
+
|
|
75
|
+
_.forEach(queryParams, function (param) {
|
|
76
|
+
request.url.query.add({
|
|
77
|
+
key: param[0] && oAuth1.percentEncode(param[0]),
|
|
78
|
+
value: param[1] && oAuth1.percentEncode(param[1])
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
55
83
|
/**
|
|
56
84
|
* Calculates body hash with given algorithm and digestEncoding.
|
|
57
85
|
*
|
|
@@ -252,13 +280,13 @@ module.exports = {
|
|
|
252
280
|
*
|
|
253
281
|
* @param {Request} request - request to add oauth1 parameters
|
|
254
282
|
* @param {Object} params - oauth data to generate signature
|
|
283
|
+
* @param {Object} protocolProfileBehavior - Protocol profile behaviors
|
|
255
284
|
* @param {Function} done - callback function
|
|
256
285
|
*/
|
|
257
|
-
addAuthDataToRequest: function (request, params, done) {
|
|
286
|
+
addAuthDataToRequest: function (request, params, protocolProfileBehavior, done) {
|
|
258
287
|
var url = urlEncoder.toNodeUrl(request.url),
|
|
259
288
|
signatureParams,
|
|
260
289
|
urlencodedBody,
|
|
261
|
-
queryParams,
|
|
262
290
|
bodyParams,
|
|
263
291
|
allParams,
|
|
264
292
|
signature,
|
|
@@ -268,7 +296,8 @@ module.exports = {
|
|
|
268
296
|
consumerSecret: params.consumerSecret || EMPTY,
|
|
269
297
|
tokenSecret: params.tokenSecret || EMPTY,
|
|
270
298
|
privateKey: params.privateKey || EMPTY
|
|
271
|
-
}
|
|
299
|
+
},
|
|
300
|
+
disableUrlEncoding = protocolProfileBehavior && protocolProfileBehavior.disableUrlEncoding;
|
|
272
301
|
|
|
273
302
|
signatureParams = [
|
|
274
303
|
{system: true, key: OAUTH1_PARAMS.oauthConsumerKey, value: params.consumerKey},
|
|
@@ -300,11 +329,6 @@ module.exports = {
|
|
|
300
329
|
return params.addEmptyParamsToSign || param.value;
|
|
301
330
|
});
|
|
302
331
|
|
|
303
|
-
// filter disabled query parameters
|
|
304
|
-
queryParams = request.url.query.filter(function (param) {
|
|
305
|
-
return !param.disabled;
|
|
306
|
-
});
|
|
307
|
-
|
|
308
332
|
urlencodedBody = request.body &&
|
|
309
333
|
request.body.mode === RequestBody.MODES.urlencoded &&
|
|
310
334
|
request.body.urlencoded;
|
|
@@ -315,7 +339,7 @@ module.exports = {
|
|
|
315
339
|
return !param.disabled;
|
|
316
340
|
}) : [];
|
|
317
341
|
|
|
318
|
-
allParams = [].concat(signatureParams,
|
|
342
|
+
allParams = [].concat(signatureParams, bodyParams);
|
|
319
343
|
|
|
320
344
|
message = {
|
|
321
345
|
action: getOAuth1BaseUrl(url),
|
|
@@ -333,6 +357,13 @@ module.exports = {
|
|
|
333
357
|
return done(err);
|
|
334
358
|
}
|
|
335
359
|
|
|
360
|
+
// Update the encoding for query parameters to RFC-3986 in accordance with the
|
|
361
|
+
// OAuth1.0a specification: https://oauth.net/core/1.0a/#encoding_parameters
|
|
362
|
+
// disableUrlEncoding option should be respected in authorization flow as well
|
|
363
|
+
if (disableUrlEncoding !== true) {
|
|
364
|
+
updateQueryParamEncoding(request, url);
|
|
365
|
+
}
|
|
366
|
+
|
|
336
367
|
signatureParams.push({system: true, key: OAUTH1_PARAMS.oauthSignature, value: signature});
|
|
337
368
|
|
|
338
369
|
// Add signature params to the request. The OAuth specification says
|
|
@@ -358,9 +389,19 @@ module.exports = {
|
|
|
358
389
|
urlencodedBody.add(param);
|
|
359
390
|
});
|
|
360
391
|
}
|
|
361
|
-
else {
|
|
392
|
+
else if (disableUrlEncoding === true) {
|
|
393
|
+
// disableUrlEncoding option should be respected in authorization flow as well
|
|
362
394
|
request.addQueryParams(signatureParams);
|
|
363
395
|
}
|
|
396
|
+
else {
|
|
397
|
+
_.forEach(signatureParams, function (param) {
|
|
398
|
+
request.url.query.add({
|
|
399
|
+
key: param.key && oAuth1.percentEncode(param.key),
|
|
400
|
+
value: param.value && oAuth1.percentEncode(param.value),
|
|
401
|
+
system: true
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
}
|
|
364
405
|
|
|
365
406
|
done();
|
|
366
407
|
},
|
|
@@ -394,7 +435,8 @@ module.exports = {
|
|
|
394
435
|
]),
|
|
395
436
|
urlencodedBody = request.body,
|
|
396
437
|
signatureAlgo,
|
|
397
|
-
hashAlgo
|
|
438
|
+
hashAlgo,
|
|
439
|
+
protocolProfileBehavior = auth._protocolProfileBehavior;
|
|
398
440
|
|
|
399
441
|
// extract hash and signature algorithm form signatureMethod
|
|
400
442
|
// signature methods are in this format: '<signatureAlgo>-<hashAlgo>' e.g. RSA-SHA1
|
|
@@ -440,13 +482,13 @@ module.exports = {
|
|
|
440
482
|
// Don't include body hash as defined in specification
|
|
441
483
|
// @see: https://tools.ietf.org/id/draft-eaton-oauth-bodyhash-00.html#when_to_include
|
|
442
484
|
if (urlencodedBody || !(params.includeBodyHash && hashAlgo)) {
|
|
443
|
-
return self.addAuthDataToRequest(request, params, done);
|
|
485
|
+
return self.addAuthDataToRequest(request, params, protocolProfileBehavior, done);
|
|
444
486
|
}
|
|
445
487
|
|
|
446
488
|
computeBodyHash(request.body, hashAlgo, 'base64', function (bodyHash) {
|
|
447
489
|
params.bodyHash = bodyHash;
|
|
448
490
|
|
|
449
|
-
return self.addAuthDataToRequest(request, params, done);
|
|
491
|
+
return self.addAuthDataToRequest(request, params, protocolProfileBehavior, done);
|
|
450
492
|
});
|
|
451
493
|
}
|
|
452
494
|
};
|
|
@@ -315,6 +315,9 @@ _.assign(Requester.prototype, /** @lends Requester.prototype */ {
|
|
|
315
315
|
*/
|
|
316
316
|
onStart = function (response) {
|
|
317
317
|
var responseStartEventName = RESPONSE_START_EVENT_BASE + id,
|
|
318
|
+
executionData,
|
|
319
|
+
initialRequest,
|
|
320
|
+
finalRequest,
|
|
318
321
|
sdkResponse,
|
|
319
322
|
history,
|
|
320
323
|
done = function () {
|
|
@@ -342,12 +345,22 @@ _.assign(Requester.prototype, /** @lends Requester.prototype */ {
|
|
|
342
345
|
// prepare history from request debug data
|
|
343
346
|
history = getExecutionHistory(_.get(response, 'request._debug'));
|
|
344
347
|
|
|
348
|
+
// get the initial and final (on redirect) request from history
|
|
349
|
+
executionData = _.get(history, 'execution.data') || [];
|
|
350
|
+
initialRequest = _.get(executionData, '[0].request') || {};
|
|
351
|
+
finalRequest = executionData.length > 1 ?
|
|
352
|
+
// get final redirect
|
|
353
|
+
_.get(executionData, [executionData.length - 1, 'request']) :
|
|
354
|
+
// no redirects
|
|
355
|
+
initialRequest;
|
|
356
|
+
|
|
345
357
|
// add missing request headers so that they get bubbled up into the UI
|
|
346
|
-
addMissingRequestHeaders(
|
|
358
|
+
addMissingRequestHeaders(initialRequest.headers);
|
|
347
359
|
|
|
348
|
-
//
|
|
360
|
+
// pull out cookies from the cookie jar, and make them chrome compatible.
|
|
349
361
|
if (cookieJar && _.isFunction(cookieJar.getCookies)) {
|
|
350
|
-
|
|
362
|
+
// get cookies set for the final request URL
|
|
363
|
+
cookieJar.getCookies(finalRequest.href, function (err, cookiesFromJar) {
|
|
351
364
|
if (err) {
|
|
352
365
|
return done();
|
|
353
366
|
}
|
|
@@ -371,7 +384,7 @@ _.assign(Requester.prototype, /** @lends Requester.prototype */ {
|
|
|
371
384
|
// we can't trust the integrity of this request
|
|
372
385
|
// bail out if request url is empty
|
|
373
386
|
if (!(request && request.url && request.url.toString && request.url.toString())) {
|
|
374
|
-
return onEnd(new Error('runtime:
|
|
387
|
+
return onEnd(new Error('runtime:extensions~request: request url is empty'));
|
|
375
388
|
}
|
|
376
389
|
|
|
377
390
|
cookieJar = self.options.cookieJar;
|
|
@@ -190,7 +190,7 @@ module.exports = [
|
|
|
190
190
|
return done();
|
|
191
191
|
}
|
|
192
192
|
|
|
193
|
-
authInterface = createAuthInterface(auth);
|
|
193
|
+
authInterface = createAuthInterface(auth, context.protocolProfileBehavior);
|
|
194
194
|
|
|
195
195
|
/**
|
|
196
196
|
* We go through the `pre` request send validation for the auth. In this step one of the three things can happen
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "postman-runtime",
|
|
3
|
-
"version": "7.28.
|
|
3
|
+
"version": "7.28.4",
|
|
4
4
|
"description": "Underlying library of executing Postman Collections (used by Newman)",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"directories": {
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"test": "test"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
+
"codecov": "node npm/publish-coverage.js",
|
|
11
12
|
"test": "npm run test-lint && npm run test-system && npm run test-unit && npm run test-integration && npm run test-integration-legacy",
|
|
12
13
|
"test-system": "node npm/test-system.js",
|
|
13
14
|
"test-lint": "node npm/test-lint.js",
|
|
@@ -39,23 +40,23 @@
|
|
|
39
40
|
"eventemitter3": "4.0.7",
|
|
40
41
|
"handlebars": "4.7.7",
|
|
41
42
|
"http-reasons": "0.1.0",
|
|
42
|
-
"httpntlm": "1.7.
|
|
43
|
+
"httpntlm": "1.7.7",
|
|
43
44
|
"inherits": "2.0.4",
|
|
44
45
|
"js-sha512": "0.8.0",
|
|
45
46
|
"lodash": "4.17.21",
|
|
46
47
|
"node-oauth1": "1.3.0",
|
|
47
48
|
"performance-now": "2.1.0",
|
|
48
|
-
"postman-collection": "
|
|
49
|
+
"postman-collection": "4.1.0",
|
|
49
50
|
"postman-request": "2.88.1-postman.30",
|
|
50
|
-
"postman-sandbox": "4.0.
|
|
51
|
-
"postman-url-encoder": "3.0.
|
|
51
|
+
"postman-sandbox": "4.0.5",
|
|
52
|
+
"postman-url-encoder": "3.0.5",
|
|
52
53
|
"resolve-from": "5.0.0",
|
|
53
54
|
"serialised-error": "1.1.3",
|
|
54
55
|
"tough-cookie": "3.0.1",
|
|
55
56
|
"uuid": "3.4.0"
|
|
56
57
|
},
|
|
57
58
|
"devDependencies": {
|
|
58
|
-
"@postman/shipit": "0.
|
|
59
|
+
"@postman/shipit": "0.3.0",
|
|
59
60
|
"ajv": "6.12.6",
|
|
60
61
|
"browserify": "16.5.2",
|
|
61
62
|
"chai": "4.3.4",
|
|
@@ -63,13 +64,13 @@
|
|
|
63
64
|
"editorconfig": "0.15.3",
|
|
64
65
|
"eslint": "5.16.0",
|
|
65
66
|
"eslint-plugin-jsdoc": "8.7.0",
|
|
66
|
-
"eslint-plugin-lodash": "7.
|
|
67
|
+
"eslint-plugin-lodash": "7.3.0",
|
|
67
68
|
"eslint-plugin-mocha": "6.3.0",
|
|
68
69
|
"eslint-plugin-security": "1.4.0",
|
|
69
70
|
"express": "4.17.1",
|
|
70
|
-
"graphql": "15.5.
|
|
71
|
-
"js-yaml": "4.
|
|
72
|
-
"jsdoc": "3.6.
|
|
71
|
+
"graphql": "15.5.1",
|
|
72
|
+
"js-yaml": "4.1.0",
|
|
73
|
+
"jsdoc": "3.6.7",
|
|
73
74
|
"jsdoc-to-markdown": "7.0.1",
|
|
74
75
|
"karma": "3.1.4",
|
|
75
76
|
"karma-browserify": "6.1.0",
|
|
@@ -87,7 +88,7 @@
|
|
|
87
88
|
"shelljs": "0.8.4",
|
|
88
89
|
"sinon": "8.1.1",
|
|
89
90
|
"teleport-javascript": "1.0.0",
|
|
90
|
-
"terser": "5.
|
|
91
|
+
"terser": "5.7.1",
|
|
91
92
|
"tmp": "0.2.1",
|
|
92
93
|
"yankee": "1.0.8"
|
|
93
94
|
},
|