@commercetools-backend/express 21.23.10 → 21.24.1
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.
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
|
|
6
|
-
var _asyncToGenerator = require('@babel/runtime-corejs3/helpers/asyncToGenerator');
|
|
7
|
-
var _regeneratorRuntime = require('@babel/runtime-corejs3/regenerator');
|
|
8
6
|
var _URL = require('@babel/runtime-corejs3/core-js-stable/url');
|
|
9
7
|
var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat');
|
|
10
8
|
var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with');
|
|
@@ -17,8 +15,8 @@ var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/in
|
|
|
17
15
|
var _Object$getOwnPropertyDescriptors = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors');
|
|
18
16
|
var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/object/define-properties');
|
|
19
17
|
var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
|
|
20
|
-
var jwksRsa = require('jwks-rsa');
|
|
21
18
|
var expressJwt = require('express-jwt');
|
|
19
|
+
var jwksRsa = require('jwks-rsa');
|
|
22
20
|
var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray');
|
|
23
21
|
var _findInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/find');
|
|
24
22
|
var _Object$entries = require('@babel/runtime-corejs3/core-js-stable/object/entries');
|
|
@@ -26,7 +24,6 @@ var _Array$isArray = require('@babel/runtime-corejs3/core-js-stable/array/is-arr
|
|
|
26
24
|
|
|
27
25
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
28
26
|
|
|
29
|
-
var _regeneratorRuntime__default = /*#__PURE__*/_interopDefault(_regeneratorRuntime);
|
|
30
27
|
var _URL__default = /*#__PURE__*/_interopDefault(_URL);
|
|
31
28
|
var _concatInstanceProperty__default = /*#__PURE__*/_interopDefault(_concatInstanceProperty);
|
|
32
29
|
var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsWithInstanceProperty);
|
|
@@ -44,38 +41,38 @@ var _findInstanceProperty__default = /*#__PURE__*/_interopDefault(_findInstanceP
|
|
|
44
41
|
var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
|
|
45
42
|
var _Array$isArray__default = /*#__PURE__*/_interopDefault(_Array$isArray);
|
|
46
43
|
|
|
47
|
-
|
|
44
|
+
const CLOUD_IDENTIFIERS = {
|
|
48
45
|
GCP_AU: 'gcp-au',
|
|
49
46
|
GCP_EU: 'gcp-eu',
|
|
50
47
|
GCP_US: 'gcp-us',
|
|
51
48
|
AWS_FRA: 'aws-fra',
|
|
52
49
|
AWS_OHIO: 'aws-ohio'
|
|
53
50
|
};
|
|
54
|
-
|
|
51
|
+
const MC_API_URLS = {
|
|
55
52
|
GCP_AU: 'https://mc-api.australia-southeast1.gcp.commercetools.com',
|
|
56
53
|
GCP_EU: 'https://mc-api.europe-west1.gcp.commercetools.com',
|
|
57
54
|
GCP_US: 'https://mc-api.us-central1.gcp.commercetools.com',
|
|
58
55
|
AWS_FRA: 'https://mc-api.eu-central-1.aws.commercetools.com',
|
|
59
56
|
AWS_OHIO: 'https://mc-api.us-east-2.aws.commercetools.com'
|
|
60
57
|
};
|
|
61
|
-
|
|
58
|
+
const MC_API_PROXY_HEADERS = {
|
|
62
59
|
FORWARD_TO_VERSION: 'x-mc-api-forward-to-version',
|
|
63
60
|
CLOUD_IDENTIFIER: 'x-mc-api-cloud-identifier'
|
|
64
61
|
};
|
|
65
62
|
|
|
66
|
-
|
|
63
|
+
const getHeaderByCaseInsensitiveKey = (headers, headerKey) => {
|
|
67
64
|
var _context;
|
|
68
65
|
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
const matchingHeader = _findInstanceProperty__default["default"](_context = _Object$entries__default["default"](headers)).call(_context, _ref => {
|
|
67
|
+
let _ref2 = _slicedToArray(_ref, 1),
|
|
71
68
|
key = _ref2[0];
|
|
72
69
|
|
|
73
70
|
return headerKey.toLowerCase() === key.toLowerCase();
|
|
74
71
|
});
|
|
75
72
|
|
|
76
73
|
if (matchingHeader && matchingHeader.length > 0) {
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
const _matchingHeader = _slicedToArray(matchingHeader, 2),
|
|
75
|
+
headerValue = _matchingHeader[1];
|
|
79
76
|
|
|
80
77
|
return _Array$isArray__default["default"](headerValue) ? headerValue[0] : headerValue;
|
|
81
78
|
}
|
|
@@ -83,8 +80,8 @@ var getHeaderByCaseInsensitiveKey = function getHeaderByCaseInsensitiveKey(heade
|
|
|
83
80
|
return undefined;
|
|
84
81
|
};
|
|
85
82
|
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
const getFirstHeaderValueOrThrow = (headers, headerKey, errorMessage) => {
|
|
84
|
+
const headerValue = getHeaderByCaseInsensitiveKey(headers, headerKey);
|
|
88
85
|
|
|
89
86
|
if (!headerValue) {
|
|
90
87
|
throw new Error(errorMessage);
|
|
@@ -95,20 +92,20 @@ var getFirstHeaderValueOrThrow = function getFirstHeaderValueOrThrow(headers, he
|
|
|
95
92
|
|
|
96
93
|
function ownKeys(object, enumerableOnly) { var keys = _Object$keys__default["default"](object); if (_Object$getOwnPropertySymbols__default["default"]) { var symbols = _Object$getOwnPropertySymbols__default["default"](object); enumerableOnly && (symbols = _filterInstanceProperty__default["default"](symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor__default["default"](object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
97
94
|
|
|
98
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var
|
|
99
|
-
|
|
95
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var _context3, _context4; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? _forEachInstanceProperty__default["default"](_context3 = ownKeys(Object(source), !0)).call(_context3, function (key) { _defineProperty(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](target, _Object$getOwnPropertyDescriptors__default["default"](source)) : _forEachInstanceProperty__default["default"](_context4 = ownKeys(Object(source))).call(_context4, function (key) { _Object$defineProperty__default["default"](target, key, _Object$getOwnPropertyDescriptor__default["default"](source, key)); }); } return target; }
|
|
96
|
+
const decodedTokenKey = 'decoded_token'; // Assign a session object to the request object.
|
|
100
97
|
|
|
101
|
-
|
|
102
|
-
|
|
98
|
+
const writeSessionContext = request => {
|
|
99
|
+
const decodedToken = request[decodedTokenKey];
|
|
103
100
|
|
|
104
101
|
if (decodedToken) {
|
|
105
|
-
|
|
106
|
-
|
|
102
|
+
const publicClaimForProjectKey = "".concat(decodedToken.iss, "/claims/project_key");
|
|
103
|
+
const publicClaimForUserPermissionsKey = "".concat(decodedToken.iss, "/claims/user_permissions");
|
|
107
104
|
request.session = {
|
|
108
105
|
userId: decodedToken.sub,
|
|
109
106
|
projectKey: decodedToken[publicClaimForProjectKey]
|
|
110
107
|
};
|
|
111
|
-
|
|
108
|
+
const userPermissions = decodedToken[publicClaimForUserPermissionsKey];
|
|
112
109
|
|
|
113
110
|
if (Boolean(userPermissions === null || userPermissions === void 0 ? void 0 : userPermissions.length)) {
|
|
114
111
|
request.session.userPermissions = userPermissions;
|
|
@@ -123,7 +120,7 @@ var writeSessionContext = function writeSessionContext(request) {
|
|
|
123
120
|
// https://docs.commercetools.com/custom-applications/concepts/merchant-center-api#hostnames
|
|
124
121
|
|
|
125
122
|
|
|
126
|
-
|
|
123
|
+
const mapCloudIdentifierToIssuer = issuer => {
|
|
127
124
|
switch (issuer) {
|
|
128
125
|
case CLOUD_IDENTIFIERS.GCP_AU:
|
|
129
126
|
return MC_API_URLS.GCP_AU;
|
|
@@ -147,7 +144,7 @@ var mapCloudIdentifierToIssuer = function mapCloudIdentifierToIssuer(issuer) {
|
|
|
147
144
|
// This is for backwards compatibility.
|
|
148
145
|
|
|
149
146
|
|
|
150
|
-
|
|
147
|
+
const mapToLegacyIssuer = cloudIdentifier => {
|
|
151
148
|
switch (cloudIdentifier) {
|
|
152
149
|
case CLOUD_IDENTIFIERS.GCP_EU:
|
|
153
150
|
return 'https://mc-api.commercetools.com';
|
|
@@ -161,7 +158,7 @@ var mapToLegacyIssuer = function mapToLegacyIssuer(cloudIdentifier) {
|
|
|
161
158
|
}; // Verifies that the issuer is a valid URL.
|
|
162
159
|
|
|
163
160
|
|
|
164
|
-
|
|
161
|
+
const throwIfIssuerIsNotAValidUrl = issuer => {
|
|
165
162
|
try {
|
|
166
163
|
new _URL__default["default"](issuer);
|
|
167
164
|
} catch (error) {
|
|
@@ -170,7 +167,7 @@ var throwIfIssuerIsNotAValidUrl = function throwIfIssuerIsNotAValidUrl(issuer) {
|
|
|
170
167
|
}; // Validates required option values.
|
|
171
168
|
|
|
172
169
|
|
|
173
|
-
|
|
170
|
+
const validateRequiredValues = options => {
|
|
174
171
|
if (!options.audience) {
|
|
175
172
|
throw new Error("Missing required option \"audience\"");
|
|
176
173
|
}
|
|
@@ -182,8 +179,8 @@ var validateRequiredValues = function validateRequiredValues(options) {
|
|
|
182
179
|
// be mapped to one of the supported values. If not, we assume the value is a valid URL.
|
|
183
180
|
|
|
184
181
|
|
|
185
|
-
|
|
186
|
-
|
|
182
|
+
const getConfiguredDefaultIssuer = options => {
|
|
183
|
+
const issuer = mapCloudIdentifierToIssuer(options.issuer);
|
|
187
184
|
|
|
188
185
|
if (!issuer) {
|
|
189
186
|
throwIfIssuerIsNotAValidUrl(options.issuer);
|
|
@@ -196,11 +193,11 @@ var getConfiguredDefaultIssuer = function getConfiguredDefaultIssuer(options) {
|
|
|
196
193
|
// the token validation might fail because of mismatching audiences.
|
|
197
194
|
|
|
198
195
|
|
|
199
|
-
|
|
196
|
+
const getConfiguredAudience = (options, requestPath) => {
|
|
200
197
|
var _context;
|
|
201
198
|
|
|
202
199
|
// remove the trailing slash
|
|
203
|
-
|
|
200
|
+
const url = new _URL__default["default"](_concatInstanceProperty__default["default"](_context = "".concat(options.audience.replace(/\/?$/, ''))).call(_context, requestPath));
|
|
204
201
|
|
|
205
202
|
switch (options.audiencePolicy) {
|
|
206
203
|
case 'forward-url-origin':
|
|
@@ -221,120 +218,75 @@ var getConfiguredAudience = function getConfiguredAudience(options, requestPath)
|
|
|
221
218
|
|
|
222
219
|
function createSessionAuthVerifier(options) {
|
|
223
220
|
validateRequiredValues(options);
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
return /*#__PURE__*/function () {
|
|
227
|
-
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime__default["default"].mark(function _callee(request, response) {
|
|
228
|
-
var _mapCloudIdentifierTo, _request$originalUrl;
|
|
229
|
-
|
|
230
|
-
var cloudIdentifierHeader, issuer, proxyForwardVersion, _mapToLegacyIssuer, requestUrlPath, audience;
|
|
231
|
-
|
|
232
|
-
return _regeneratorRuntime__default["default"].wrap(function _callee$(_context3) {
|
|
233
|
-
while (1) {
|
|
234
|
-
switch (_context3.prev = _context3.next) {
|
|
235
|
-
case 0:
|
|
236
|
-
// Get the cloud identifier header, forwarded by the `/proxy/forward-to` endpoint.
|
|
237
|
-
cloudIdentifierHeader = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.CLOUD_IDENTIFIER, "Missing \"X-MC-API-Cloud-Identifier\" header.");
|
|
238
|
-
issuer = options.inferIssuer && cloudIdentifierHeader ? (_mapCloudIdentifierTo = mapCloudIdentifierToIssuer(cloudIdentifierHeader)) !== null && _mapCloudIdentifierTo !== void 0 ? _mapCloudIdentifierTo : configuredDefaultIssuer : configuredDefaultIssuer; // Get the `Accept-version` header, forwarded by the `/proxy/forward-to` endpoint.
|
|
239
|
-
// The version should be sent by the client making the request, to use the features of v2.
|
|
240
|
-
|
|
241
|
-
proxyForwardVersion = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.FORWARD_TO_VERSION, "Missing \"X-MC-API-Forward-To-Version\" header.");
|
|
242
|
-
|
|
243
|
-
if (proxyForwardVersion === 'v1') {
|
|
244
|
-
// Fall back to legacy issuer domains
|
|
245
|
-
issuer = (_mapToLegacyIssuer = mapToLegacyIssuer(cloudIdentifierHeader)) !== null && _mapToLegacyIssuer !== void 0 ? _mapToLegacyIssuer : issuer;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
requestUrlPath = options.getRequestUrl ? options.getRequestUrl(request) : (_request$originalUrl = request.originalUrl) !== null && _request$originalUrl !== void 0 ? _request$originalUrl : request.url;
|
|
249
|
-
|
|
250
|
-
if (!(!requestUrlPath || !_startsWithInstanceProperty__default["default"](requestUrlPath).call(requestUrlPath, '/'))) {
|
|
251
|
-
_context3.next = 7;
|
|
252
|
-
break;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
throw new Error("Invalid request URI path \"".concat(requestUrlPath, "\". Please make sure that the \"request\" object has either a property \"originalUrl\" or \"url\". If not, you should implement the \"getRequestUrl\" function and make sure to return a valid URI path value starting with \"/\". More info at https://docs.commercetools.com/custom-applications/concepts/integrate-with-your-own-api#validating-the-json-web-token"));
|
|
256
|
-
|
|
257
|
-
case 7:
|
|
258
|
-
audience = getConfiguredAudience(options, requestUrlPath);
|
|
259
|
-
return _context3.abrupt("return", new _Promise__default["default"](function (resolve, reject) {
|
|
260
|
-
expressJwt.expressjwt({
|
|
261
|
-
// Dynamically provide a signing key based on the kid in the header
|
|
262
|
-
// and the singing keys provided by the JWKS endpoint
|
|
263
|
-
secret: jwksRsa__default["default"].expressJwtSecret(_objectSpread(_objectSpread({
|
|
264
|
-
// Default options
|
|
265
|
-
cache: true,
|
|
266
|
-
rateLimit: true,
|
|
267
|
-
jwksRequestsPerMinute: 5
|
|
268
|
-
}, options.jwks || {}), {}, {
|
|
269
|
-
// This should be set by the middleware, no matter what.
|
|
270
|
-
jwksUri: "".concat(issuer, "/.well-known/jwks.json")
|
|
271
|
-
})),
|
|
272
|
-
requestProperty: decodedTokenKey,
|
|
273
|
-
// Validate the audience and the issuer.
|
|
274
|
-
audience: audience,
|
|
275
|
-
issuer: issuer,
|
|
276
|
-
algorithms: ['RS256'] // @ts-ignore: the middleware expects an Express.js Request/Response objects
|
|
277
|
-
|
|
278
|
-
})(request, response !== null && response !== void 0 ? response : {}, function (error) {
|
|
279
|
-
if (error) {
|
|
280
|
-
reject(error);
|
|
281
|
-
} else {
|
|
282
|
-
// @ts-ignore: the Request object does not know about some additional fields
|
|
283
|
-
// like `decoded_token` and `session`
|
|
284
|
-
writeSessionContext(request);
|
|
285
|
-
resolve();
|
|
286
|
-
}
|
|
287
|
-
});
|
|
288
|
-
}));
|
|
289
|
-
|
|
290
|
-
case 9:
|
|
291
|
-
case "end":
|
|
292
|
-
return _context3.stop();
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}, _callee);
|
|
296
|
-
}));
|
|
221
|
+
const configuredDefaultIssuer = getConfiguredDefaultIssuer(options); // Returns an async HTTP handler.
|
|
297
222
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
};
|
|
301
|
-
}();
|
|
302
|
-
}
|
|
223
|
+
return async (request, response) => {
|
|
224
|
+
var _mapCloudIdentifierTo, _request$originalUrl;
|
|
303
225
|
|
|
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
|
-
|
|
226
|
+
// Get the cloud identifier header, forwarded by the `/proxy/forward-to` endpoint.
|
|
227
|
+
const cloudIdentifierHeader = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.CLOUD_IDENTIFIER, "Missing \"X-MC-API-Cloud-Identifier\" header.");
|
|
228
|
+
let issuer = options.inferIssuer && cloudIdentifierHeader ? (_mapCloudIdentifierTo = mapCloudIdentifierToIssuer(cloudIdentifierHeader)) !== null && _mapCloudIdentifierTo !== void 0 ? _mapCloudIdentifierTo : configuredDefaultIssuer : configuredDefaultIssuer; // Get the `Accept-version` header, forwarded by the `/proxy/forward-to` endpoint.
|
|
229
|
+
// The version should be sent by the client making the request, to use the features of v2.
|
|
230
|
+
|
|
231
|
+
const proxyForwardVersion = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.FORWARD_TO_VERSION, "Missing \"X-MC-API-Forward-To-Version\" header.");
|
|
232
|
+
|
|
233
|
+
if (proxyForwardVersion === 'v1') {
|
|
234
|
+
var _mapToLegacyIssuer;
|
|
235
|
+
|
|
236
|
+
// Fall back to legacy issuer domains
|
|
237
|
+
issuer = (_mapToLegacyIssuer = mapToLegacyIssuer(cloudIdentifierHeader)) !== null && _mapToLegacyIssuer !== void 0 ? _mapToLegacyIssuer : issuer;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const requestUrlPath = options.getRequestUrl ? options.getRequestUrl(request) : (_request$originalUrl = request.originalUrl) !== null && _request$originalUrl !== void 0 ? _request$originalUrl : request.url;
|
|
241
|
+
|
|
242
|
+
if (!requestUrlPath || !_startsWithInstanceProperty__default["default"](requestUrlPath).call(requestUrlPath, '/')) {
|
|
243
|
+
throw new Error("Invalid request URI path \"".concat(requestUrlPath, "\". Please make sure that the \"request\" object has either a property \"originalUrl\" or \"url\". If not, you should implement the \"getRequestUrl\" function and make sure to return a valid URI path value starting with \"/\". More info at https://docs.commercetools.com/custom-applications/concepts/integrate-with-your-own-api#validating-the-json-web-token"));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const audience = getConfiguredAudience(options, requestUrlPath);
|
|
247
|
+
return new _Promise__default["default"]((resolve, reject) => {
|
|
248
|
+
expressJwt.expressjwt({
|
|
249
|
+
// Dynamically provide a signing key based on the kid in the header
|
|
250
|
+
// and the singing keys provided by the JWKS endpoint
|
|
251
|
+
secret: jwksRsa__default["default"].expressJwtSecret(_objectSpread(_objectSpread({
|
|
252
|
+
// Default options
|
|
253
|
+
cache: true,
|
|
254
|
+
rateLimit: true,
|
|
255
|
+
jwksRequestsPerMinute: 5
|
|
256
|
+
}, options.jwks || {}), {}, {
|
|
257
|
+
// This should be set by the middleware, no matter what.
|
|
258
|
+
jwksUri: "".concat(issuer, "/.well-known/jwks.json")
|
|
259
|
+
})),
|
|
260
|
+
requestProperty: decodedTokenKey,
|
|
261
|
+
// Validate the audience and the issuer.
|
|
262
|
+
audience,
|
|
263
|
+
issuer,
|
|
264
|
+
algorithms: ['RS256'] // @ts-ignore: the middleware expects an Express.js Request/Response objects
|
|
265
|
+
|
|
266
|
+
})(request, response !== null && response !== void 0 ? response : {}, error => {
|
|
267
|
+
if (error) {
|
|
268
|
+
reject(error);
|
|
269
|
+
} else {
|
|
270
|
+
// @ts-ignore: the Request object does not know about some additional fields
|
|
271
|
+
// like `decoded_token` and `session`
|
|
272
|
+
writeSessionContext(request);
|
|
273
|
+
resolve();
|
|
330
274
|
}
|
|
331
|
-
}
|
|
332
|
-
})
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
};
|
|
278
|
+
}
|
|
333
279
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
280
|
+
function createSessionMiddleware(options) {
|
|
281
|
+
const sessionAuthVerifier = createSessionAuthVerifier(options);
|
|
282
|
+
return async (request, response, next) => {
|
|
283
|
+
try {
|
|
284
|
+
await sessionAuthVerifier(request, response);
|
|
285
|
+
next();
|
|
286
|
+
} catch (error) {
|
|
287
|
+
next(error);
|
|
288
|
+
}
|
|
289
|
+
};
|
|
338
290
|
}
|
|
339
291
|
|
|
340
292
|
exports.CLOUD_IDENTIFIERS = CLOUD_IDENTIFIERS;
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
|
|
6
|
-
var _asyncToGenerator = require('@babel/runtime-corejs3/helpers/asyncToGenerator');
|
|
7
|
-
var _regeneratorRuntime = require('@babel/runtime-corejs3/regenerator');
|
|
8
6
|
var _URL = require('@babel/runtime-corejs3/core-js-stable/url');
|
|
9
7
|
var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat');
|
|
10
8
|
var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with');
|
|
@@ -17,8 +15,8 @@ var _forEachInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/in
|
|
|
17
15
|
var _Object$getOwnPropertyDescriptors = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors');
|
|
18
16
|
var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/object/define-properties');
|
|
19
17
|
var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
|
|
20
|
-
var jwksRsa = require('jwks-rsa');
|
|
21
18
|
var expressJwt = require('express-jwt');
|
|
19
|
+
var jwksRsa = require('jwks-rsa');
|
|
22
20
|
var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray');
|
|
23
21
|
var _findInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/find');
|
|
24
22
|
var _Object$entries = require('@babel/runtime-corejs3/core-js-stable/object/entries');
|
|
@@ -26,7 +24,6 @@ var _Array$isArray = require('@babel/runtime-corejs3/core-js-stable/array/is-arr
|
|
|
26
24
|
|
|
27
25
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
28
26
|
|
|
29
|
-
var _regeneratorRuntime__default = /*#__PURE__*/_interopDefault(_regeneratorRuntime);
|
|
30
27
|
var _URL__default = /*#__PURE__*/_interopDefault(_URL);
|
|
31
28
|
var _concatInstanceProperty__default = /*#__PURE__*/_interopDefault(_concatInstanceProperty);
|
|
32
29
|
var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsWithInstanceProperty);
|
|
@@ -44,38 +41,38 @@ var _findInstanceProperty__default = /*#__PURE__*/_interopDefault(_findInstanceP
|
|
|
44
41
|
var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
|
|
45
42
|
var _Array$isArray__default = /*#__PURE__*/_interopDefault(_Array$isArray);
|
|
46
43
|
|
|
47
|
-
|
|
44
|
+
const CLOUD_IDENTIFIERS = {
|
|
48
45
|
GCP_AU: 'gcp-au',
|
|
49
46
|
GCP_EU: 'gcp-eu',
|
|
50
47
|
GCP_US: 'gcp-us',
|
|
51
48
|
AWS_FRA: 'aws-fra',
|
|
52
49
|
AWS_OHIO: 'aws-ohio'
|
|
53
50
|
};
|
|
54
|
-
|
|
51
|
+
const MC_API_URLS = {
|
|
55
52
|
GCP_AU: 'https://mc-api.australia-southeast1.gcp.commercetools.com',
|
|
56
53
|
GCP_EU: 'https://mc-api.europe-west1.gcp.commercetools.com',
|
|
57
54
|
GCP_US: 'https://mc-api.us-central1.gcp.commercetools.com',
|
|
58
55
|
AWS_FRA: 'https://mc-api.eu-central-1.aws.commercetools.com',
|
|
59
56
|
AWS_OHIO: 'https://mc-api.us-east-2.aws.commercetools.com'
|
|
60
57
|
};
|
|
61
|
-
|
|
58
|
+
const MC_API_PROXY_HEADERS = {
|
|
62
59
|
FORWARD_TO_VERSION: 'x-mc-api-forward-to-version',
|
|
63
60
|
CLOUD_IDENTIFIER: 'x-mc-api-cloud-identifier'
|
|
64
61
|
};
|
|
65
62
|
|
|
66
|
-
|
|
63
|
+
const getHeaderByCaseInsensitiveKey = (headers, headerKey) => {
|
|
67
64
|
var _context;
|
|
68
65
|
|
|
69
|
-
|
|
70
|
-
|
|
66
|
+
const matchingHeader = _findInstanceProperty__default["default"](_context = _Object$entries__default["default"](headers)).call(_context, _ref => {
|
|
67
|
+
let _ref2 = _slicedToArray(_ref, 1),
|
|
71
68
|
key = _ref2[0];
|
|
72
69
|
|
|
73
70
|
return headerKey.toLowerCase() === key.toLowerCase();
|
|
74
71
|
});
|
|
75
72
|
|
|
76
73
|
if (matchingHeader && matchingHeader.length > 0) {
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
const _matchingHeader = _slicedToArray(matchingHeader, 2),
|
|
75
|
+
headerValue = _matchingHeader[1];
|
|
79
76
|
|
|
80
77
|
return _Array$isArray__default["default"](headerValue) ? headerValue[0] : headerValue;
|
|
81
78
|
}
|
|
@@ -83,8 +80,8 @@ var getHeaderByCaseInsensitiveKey = function getHeaderByCaseInsensitiveKey(heade
|
|
|
83
80
|
return undefined;
|
|
84
81
|
};
|
|
85
82
|
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
const getFirstHeaderValueOrThrow = (headers, headerKey, errorMessage) => {
|
|
84
|
+
const headerValue = getHeaderByCaseInsensitiveKey(headers, headerKey);
|
|
88
85
|
|
|
89
86
|
if (!headerValue) {
|
|
90
87
|
throw new Error(errorMessage);
|
|
@@ -95,20 +92,20 @@ var getFirstHeaderValueOrThrow = function getFirstHeaderValueOrThrow(headers, he
|
|
|
95
92
|
|
|
96
93
|
function ownKeys(object, enumerableOnly) { var keys = _Object$keys__default["default"](object); if (_Object$getOwnPropertySymbols__default["default"]) { var symbols = _Object$getOwnPropertySymbols__default["default"](object); enumerableOnly && (symbols = _filterInstanceProperty__default["default"](symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor__default["default"](object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
97
94
|
|
|
98
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var
|
|
99
|
-
|
|
95
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var _context3, _context4; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? _forEachInstanceProperty__default["default"](_context3 = ownKeys(Object(source), !0)).call(_context3, function (key) { _defineProperty(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](target, _Object$getOwnPropertyDescriptors__default["default"](source)) : _forEachInstanceProperty__default["default"](_context4 = ownKeys(Object(source))).call(_context4, function (key) { _Object$defineProperty__default["default"](target, key, _Object$getOwnPropertyDescriptor__default["default"](source, key)); }); } return target; }
|
|
96
|
+
const decodedTokenKey = 'decoded_token'; // Assign a session object to the request object.
|
|
100
97
|
|
|
101
|
-
|
|
102
|
-
|
|
98
|
+
const writeSessionContext = request => {
|
|
99
|
+
const decodedToken = request[decodedTokenKey];
|
|
103
100
|
|
|
104
101
|
if (decodedToken) {
|
|
105
|
-
|
|
106
|
-
|
|
102
|
+
const publicClaimForProjectKey = "".concat(decodedToken.iss, "/claims/project_key");
|
|
103
|
+
const publicClaimForUserPermissionsKey = "".concat(decodedToken.iss, "/claims/user_permissions");
|
|
107
104
|
request.session = {
|
|
108
105
|
userId: decodedToken.sub,
|
|
109
106
|
projectKey: decodedToken[publicClaimForProjectKey]
|
|
110
107
|
};
|
|
111
|
-
|
|
108
|
+
const userPermissions = decodedToken[publicClaimForUserPermissionsKey];
|
|
112
109
|
|
|
113
110
|
if (Boolean(userPermissions === null || userPermissions === void 0 ? void 0 : userPermissions.length)) {
|
|
114
111
|
request.session.userPermissions = userPermissions;
|
|
@@ -123,7 +120,7 @@ var writeSessionContext = function writeSessionContext(request) {
|
|
|
123
120
|
// https://docs.commercetools.com/custom-applications/concepts/merchant-center-api#hostnames
|
|
124
121
|
|
|
125
122
|
|
|
126
|
-
|
|
123
|
+
const mapCloudIdentifierToIssuer = issuer => {
|
|
127
124
|
switch (issuer) {
|
|
128
125
|
case CLOUD_IDENTIFIERS.GCP_AU:
|
|
129
126
|
return MC_API_URLS.GCP_AU;
|
|
@@ -147,7 +144,7 @@ var mapCloudIdentifierToIssuer = function mapCloudIdentifierToIssuer(issuer) {
|
|
|
147
144
|
// This is for backwards compatibility.
|
|
148
145
|
|
|
149
146
|
|
|
150
|
-
|
|
147
|
+
const mapToLegacyIssuer = cloudIdentifier => {
|
|
151
148
|
switch (cloudIdentifier) {
|
|
152
149
|
case CLOUD_IDENTIFIERS.GCP_EU:
|
|
153
150
|
return 'https://mc-api.commercetools.com';
|
|
@@ -161,7 +158,7 @@ var mapToLegacyIssuer = function mapToLegacyIssuer(cloudIdentifier) {
|
|
|
161
158
|
}; // Verifies that the issuer is a valid URL.
|
|
162
159
|
|
|
163
160
|
|
|
164
|
-
|
|
161
|
+
const throwIfIssuerIsNotAValidUrl = issuer => {
|
|
165
162
|
try {
|
|
166
163
|
new _URL__default["default"](issuer);
|
|
167
164
|
} catch (error) {
|
|
@@ -170,7 +167,7 @@ var throwIfIssuerIsNotAValidUrl = function throwIfIssuerIsNotAValidUrl(issuer) {
|
|
|
170
167
|
}; // Validates required option values.
|
|
171
168
|
|
|
172
169
|
|
|
173
|
-
|
|
170
|
+
const validateRequiredValues = options => {
|
|
174
171
|
if (!options.audience) {
|
|
175
172
|
throw new Error("Missing required option \"audience\"");
|
|
176
173
|
}
|
|
@@ -182,8 +179,8 @@ var validateRequiredValues = function validateRequiredValues(options) {
|
|
|
182
179
|
// be mapped to one of the supported values. If not, we assume the value is a valid URL.
|
|
183
180
|
|
|
184
181
|
|
|
185
|
-
|
|
186
|
-
|
|
182
|
+
const getConfiguredDefaultIssuer = options => {
|
|
183
|
+
const issuer = mapCloudIdentifierToIssuer(options.issuer);
|
|
187
184
|
|
|
188
185
|
if (!issuer) {
|
|
189
186
|
throwIfIssuerIsNotAValidUrl(options.issuer);
|
|
@@ -196,11 +193,11 @@ var getConfiguredDefaultIssuer = function getConfiguredDefaultIssuer(options) {
|
|
|
196
193
|
// the token validation might fail because of mismatching audiences.
|
|
197
194
|
|
|
198
195
|
|
|
199
|
-
|
|
196
|
+
const getConfiguredAudience = (options, requestPath) => {
|
|
200
197
|
var _context;
|
|
201
198
|
|
|
202
199
|
// remove the trailing slash
|
|
203
|
-
|
|
200
|
+
const url = new _URL__default["default"](_concatInstanceProperty__default["default"](_context = "".concat(options.audience.replace(/\/?$/, ''))).call(_context, requestPath));
|
|
204
201
|
|
|
205
202
|
switch (options.audiencePolicy) {
|
|
206
203
|
case 'forward-url-origin':
|
|
@@ -221,120 +218,75 @@ var getConfiguredAudience = function getConfiguredAudience(options, requestPath)
|
|
|
221
218
|
|
|
222
219
|
function createSessionAuthVerifier(options) {
|
|
223
220
|
validateRequiredValues(options);
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
return /*#__PURE__*/function () {
|
|
227
|
-
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime__default["default"].mark(function _callee(request, response) {
|
|
228
|
-
var _mapCloudIdentifierTo, _request$originalUrl;
|
|
229
|
-
|
|
230
|
-
var cloudIdentifierHeader, issuer, proxyForwardVersion, _mapToLegacyIssuer, requestUrlPath, audience;
|
|
231
|
-
|
|
232
|
-
return _regeneratorRuntime__default["default"].wrap(function _callee$(_context3) {
|
|
233
|
-
while (1) {
|
|
234
|
-
switch (_context3.prev = _context3.next) {
|
|
235
|
-
case 0:
|
|
236
|
-
// Get the cloud identifier header, forwarded by the `/proxy/forward-to` endpoint.
|
|
237
|
-
cloudIdentifierHeader = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.CLOUD_IDENTIFIER, "Missing \"X-MC-API-Cloud-Identifier\" header.");
|
|
238
|
-
issuer = options.inferIssuer && cloudIdentifierHeader ? (_mapCloudIdentifierTo = mapCloudIdentifierToIssuer(cloudIdentifierHeader)) !== null && _mapCloudIdentifierTo !== void 0 ? _mapCloudIdentifierTo : configuredDefaultIssuer : configuredDefaultIssuer; // Get the `Accept-version` header, forwarded by the `/proxy/forward-to` endpoint.
|
|
239
|
-
// The version should be sent by the client making the request, to use the features of v2.
|
|
240
|
-
|
|
241
|
-
proxyForwardVersion = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.FORWARD_TO_VERSION, "Missing \"X-MC-API-Forward-To-Version\" header.");
|
|
242
|
-
|
|
243
|
-
if (proxyForwardVersion === 'v1') {
|
|
244
|
-
// Fall back to legacy issuer domains
|
|
245
|
-
issuer = (_mapToLegacyIssuer = mapToLegacyIssuer(cloudIdentifierHeader)) !== null && _mapToLegacyIssuer !== void 0 ? _mapToLegacyIssuer : issuer;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
requestUrlPath = options.getRequestUrl ? options.getRequestUrl(request) : (_request$originalUrl = request.originalUrl) !== null && _request$originalUrl !== void 0 ? _request$originalUrl : request.url;
|
|
249
|
-
|
|
250
|
-
if (!(!requestUrlPath || !_startsWithInstanceProperty__default["default"](requestUrlPath).call(requestUrlPath, '/'))) {
|
|
251
|
-
_context3.next = 7;
|
|
252
|
-
break;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
throw new Error("Invalid request URI path \"".concat(requestUrlPath, "\". Please make sure that the \"request\" object has either a property \"originalUrl\" or \"url\". If not, you should implement the \"getRequestUrl\" function and make sure to return a valid URI path value starting with \"/\". More info at https://docs.commercetools.com/custom-applications/concepts/integrate-with-your-own-api#validating-the-json-web-token"));
|
|
256
|
-
|
|
257
|
-
case 7:
|
|
258
|
-
audience = getConfiguredAudience(options, requestUrlPath);
|
|
259
|
-
return _context3.abrupt("return", new _Promise__default["default"](function (resolve, reject) {
|
|
260
|
-
expressJwt.expressjwt({
|
|
261
|
-
// Dynamically provide a signing key based on the kid in the header
|
|
262
|
-
// and the singing keys provided by the JWKS endpoint
|
|
263
|
-
secret: jwksRsa__default["default"].expressJwtSecret(_objectSpread(_objectSpread({
|
|
264
|
-
// Default options
|
|
265
|
-
cache: true,
|
|
266
|
-
rateLimit: true,
|
|
267
|
-
jwksRequestsPerMinute: 5
|
|
268
|
-
}, options.jwks || {}), {}, {
|
|
269
|
-
// This should be set by the middleware, no matter what.
|
|
270
|
-
jwksUri: "".concat(issuer, "/.well-known/jwks.json")
|
|
271
|
-
})),
|
|
272
|
-
requestProperty: decodedTokenKey,
|
|
273
|
-
// Validate the audience and the issuer.
|
|
274
|
-
audience: audience,
|
|
275
|
-
issuer: issuer,
|
|
276
|
-
algorithms: ['RS256'] // @ts-ignore: the middleware expects an Express.js Request/Response objects
|
|
277
|
-
|
|
278
|
-
})(request, response !== null && response !== void 0 ? response : {}, function (error) {
|
|
279
|
-
if (error) {
|
|
280
|
-
reject(error);
|
|
281
|
-
} else {
|
|
282
|
-
// @ts-ignore: the Request object does not know about some additional fields
|
|
283
|
-
// like `decoded_token` and `session`
|
|
284
|
-
writeSessionContext(request);
|
|
285
|
-
resolve();
|
|
286
|
-
}
|
|
287
|
-
});
|
|
288
|
-
}));
|
|
289
|
-
|
|
290
|
-
case 9:
|
|
291
|
-
case "end":
|
|
292
|
-
return _context3.stop();
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}, _callee);
|
|
296
|
-
}));
|
|
221
|
+
const configuredDefaultIssuer = getConfiguredDefaultIssuer(options); // Returns an async HTTP handler.
|
|
297
222
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
};
|
|
301
|
-
}();
|
|
302
|
-
}
|
|
223
|
+
return async (request, response) => {
|
|
224
|
+
var _mapCloudIdentifierTo, _request$originalUrl;
|
|
303
225
|
|
|
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
|
-
|
|
226
|
+
// Get the cloud identifier header, forwarded by the `/proxy/forward-to` endpoint.
|
|
227
|
+
const cloudIdentifierHeader = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.CLOUD_IDENTIFIER, "Missing \"X-MC-API-Cloud-Identifier\" header.");
|
|
228
|
+
let issuer = options.inferIssuer && cloudIdentifierHeader ? (_mapCloudIdentifierTo = mapCloudIdentifierToIssuer(cloudIdentifierHeader)) !== null && _mapCloudIdentifierTo !== void 0 ? _mapCloudIdentifierTo : configuredDefaultIssuer : configuredDefaultIssuer; // Get the `Accept-version` header, forwarded by the `/proxy/forward-to` endpoint.
|
|
229
|
+
// The version should be sent by the client making the request, to use the features of v2.
|
|
230
|
+
|
|
231
|
+
const proxyForwardVersion = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.FORWARD_TO_VERSION, "Missing \"X-MC-API-Forward-To-Version\" header.");
|
|
232
|
+
|
|
233
|
+
if (proxyForwardVersion === 'v1') {
|
|
234
|
+
var _mapToLegacyIssuer;
|
|
235
|
+
|
|
236
|
+
// Fall back to legacy issuer domains
|
|
237
|
+
issuer = (_mapToLegacyIssuer = mapToLegacyIssuer(cloudIdentifierHeader)) !== null && _mapToLegacyIssuer !== void 0 ? _mapToLegacyIssuer : issuer;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const requestUrlPath = options.getRequestUrl ? options.getRequestUrl(request) : (_request$originalUrl = request.originalUrl) !== null && _request$originalUrl !== void 0 ? _request$originalUrl : request.url;
|
|
241
|
+
|
|
242
|
+
if (!requestUrlPath || !_startsWithInstanceProperty__default["default"](requestUrlPath).call(requestUrlPath, '/')) {
|
|
243
|
+
throw new Error("Invalid request URI path \"".concat(requestUrlPath, "\". Please make sure that the \"request\" object has either a property \"originalUrl\" or \"url\". If not, you should implement the \"getRequestUrl\" function and make sure to return a valid URI path value starting with \"/\". More info at https://docs.commercetools.com/custom-applications/concepts/integrate-with-your-own-api#validating-the-json-web-token"));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const audience = getConfiguredAudience(options, requestUrlPath);
|
|
247
|
+
return new _Promise__default["default"]((resolve, reject) => {
|
|
248
|
+
expressJwt.expressjwt({
|
|
249
|
+
// Dynamically provide a signing key based on the kid in the header
|
|
250
|
+
// and the singing keys provided by the JWKS endpoint
|
|
251
|
+
secret: jwksRsa__default["default"].expressJwtSecret(_objectSpread(_objectSpread({
|
|
252
|
+
// Default options
|
|
253
|
+
cache: true,
|
|
254
|
+
rateLimit: true,
|
|
255
|
+
jwksRequestsPerMinute: 5
|
|
256
|
+
}, options.jwks || {}), {}, {
|
|
257
|
+
// This should be set by the middleware, no matter what.
|
|
258
|
+
jwksUri: "".concat(issuer, "/.well-known/jwks.json")
|
|
259
|
+
})),
|
|
260
|
+
requestProperty: decodedTokenKey,
|
|
261
|
+
// Validate the audience and the issuer.
|
|
262
|
+
audience,
|
|
263
|
+
issuer,
|
|
264
|
+
algorithms: ['RS256'] // @ts-ignore: the middleware expects an Express.js Request/Response objects
|
|
265
|
+
|
|
266
|
+
})(request, response !== null && response !== void 0 ? response : {}, error => {
|
|
267
|
+
if (error) {
|
|
268
|
+
reject(error);
|
|
269
|
+
} else {
|
|
270
|
+
// @ts-ignore: the Request object does not know about some additional fields
|
|
271
|
+
// like `decoded_token` and `session`
|
|
272
|
+
writeSessionContext(request);
|
|
273
|
+
resolve();
|
|
330
274
|
}
|
|
331
|
-
}
|
|
332
|
-
})
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
};
|
|
278
|
+
}
|
|
333
279
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
280
|
+
function createSessionMiddleware(options) {
|
|
281
|
+
const sessionAuthVerifier = createSessionAuthVerifier(options);
|
|
282
|
+
return async (request, response, next) => {
|
|
283
|
+
try {
|
|
284
|
+
await sessionAuthVerifier(request, response);
|
|
285
|
+
next();
|
|
286
|
+
} catch (error) {
|
|
287
|
+
next(error);
|
|
288
|
+
}
|
|
289
|
+
};
|
|
338
290
|
}
|
|
339
291
|
|
|
340
292
|
exports.CLOUD_IDENTIFIERS = CLOUD_IDENTIFIERS;
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import _defineProperty from '@babel/runtime-corejs3/helpers/esm/defineProperty';
|
|
2
|
-
import _asyncToGenerator from '@babel/runtime-corejs3/helpers/esm/asyncToGenerator';
|
|
3
|
-
import _regeneratorRuntime from '@babel/runtime-corejs3/regenerator';
|
|
4
2
|
import _URL from '@babel/runtime-corejs3/core-js-stable/url';
|
|
5
3
|
import _concatInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/concat';
|
|
6
4
|
import _startsWithInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/starts-with';
|
|
@@ -13,45 +11,45 @@ import _forEachInstanceProperty from '@babel/runtime-corejs3/core-js-stable/inst
|
|
|
13
11
|
import _Object$getOwnPropertyDescriptors from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors';
|
|
14
12
|
import _Object$defineProperties from '@babel/runtime-corejs3/core-js-stable/object/define-properties';
|
|
15
13
|
import _Object$defineProperty from '@babel/runtime-corejs3/core-js-stable/object/define-property';
|
|
16
|
-
import jwksRsa from 'jwks-rsa';
|
|
17
14
|
import { expressjwt } from 'express-jwt';
|
|
15
|
+
import jwksRsa from 'jwks-rsa';
|
|
18
16
|
import _slicedToArray from '@babel/runtime-corejs3/helpers/esm/slicedToArray';
|
|
19
17
|
import _findInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/find';
|
|
20
18
|
import _Object$entries from '@babel/runtime-corejs3/core-js-stable/object/entries';
|
|
21
19
|
import _Array$isArray from '@babel/runtime-corejs3/core-js-stable/array/is-array';
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
const CLOUD_IDENTIFIERS = {
|
|
24
22
|
GCP_AU: 'gcp-au',
|
|
25
23
|
GCP_EU: 'gcp-eu',
|
|
26
24
|
GCP_US: 'gcp-us',
|
|
27
25
|
AWS_FRA: 'aws-fra',
|
|
28
26
|
AWS_OHIO: 'aws-ohio'
|
|
29
27
|
};
|
|
30
|
-
|
|
28
|
+
const MC_API_URLS = {
|
|
31
29
|
GCP_AU: 'https://mc-api.australia-southeast1.gcp.commercetools.com',
|
|
32
30
|
GCP_EU: 'https://mc-api.europe-west1.gcp.commercetools.com',
|
|
33
31
|
GCP_US: 'https://mc-api.us-central1.gcp.commercetools.com',
|
|
34
32
|
AWS_FRA: 'https://mc-api.eu-central-1.aws.commercetools.com',
|
|
35
33
|
AWS_OHIO: 'https://mc-api.us-east-2.aws.commercetools.com'
|
|
36
34
|
};
|
|
37
|
-
|
|
35
|
+
const MC_API_PROXY_HEADERS = {
|
|
38
36
|
FORWARD_TO_VERSION: 'x-mc-api-forward-to-version',
|
|
39
37
|
CLOUD_IDENTIFIER: 'x-mc-api-cloud-identifier'
|
|
40
38
|
};
|
|
41
39
|
|
|
42
|
-
|
|
40
|
+
const getHeaderByCaseInsensitiveKey = (headers, headerKey) => {
|
|
43
41
|
var _context;
|
|
44
42
|
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
const matchingHeader = _findInstanceProperty(_context = _Object$entries(headers)).call(_context, _ref => {
|
|
44
|
+
let _ref2 = _slicedToArray(_ref, 1),
|
|
47
45
|
key = _ref2[0];
|
|
48
46
|
|
|
49
47
|
return headerKey.toLowerCase() === key.toLowerCase();
|
|
50
48
|
});
|
|
51
49
|
|
|
52
50
|
if (matchingHeader && matchingHeader.length > 0) {
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
const _matchingHeader = _slicedToArray(matchingHeader, 2),
|
|
52
|
+
headerValue = _matchingHeader[1];
|
|
55
53
|
|
|
56
54
|
return _Array$isArray(headerValue) ? headerValue[0] : headerValue;
|
|
57
55
|
}
|
|
@@ -59,8 +57,8 @@ var getHeaderByCaseInsensitiveKey = function getHeaderByCaseInsensitiveKey(heade
|
|
|
59
57
|
return undefined;
|
|
60
58
|
};
|
|
61
59
|
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
const getFirstHeaderValueOrThrow = (headers, headerKey, errorMessage) => {
|
|
61
|
+
const headerValue = getHeaderByCaseInsensitiveKey(headers, headerKey);
|
|
64
62
|
|
|
65
63
|
if (!headerValue) {
|
|
66
64
|
throw new Error(errorMessage);
|
|
@@ -71,20 +69,20 @@ var getFirstHeaderValueOrThrow = function getFirstHeaderValueOrThrow(headers, he
|
|
|
71
69
|
|
|
72
70
|
function ownKeys(object, enumerableOnly) { var keys = _Object$keys(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); enumerableOnly && (symbols = _filterInstanceProperty(symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
73
71
|
|
|
74
|
-
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var
|
|
75
|
-
|
|
72
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var _context3, _context4; var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? _forEachInstanceProperty(_context3 = ownKeys(Object(source), !0)).call(_context3, function (key) { _defineProperty(target, key, source[key]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)) : _forEachInstanceProperty(_context4 = ownKeys(Object(source))).call(_context4, function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
73
|
+
const decodedTokenKey = 'decoded_token'; // Assign a session object to the request object.
|
|
76
74
|
|
|
77
|
-
|
|
78
|
-
|
|
75
|
+
const writeSessionContext = request => {
|
|
76
|
+
const decodedToken = request[decodedTokenKey];
|
|
79
77
|
|
|
80
78
|
if (decodedToken) {
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
const publicClaimForProjectKey = "".concat(decodedToken.iss, "/claims/project_key");
|
|
80
|
+
const publicClaimForUserPermissionsKey = "".concat(decodedToken.iss, "/claims/user_permissions");
|
|
83
81
|
request.session = {
|
|
84
82
|
userId: decodedToken.sub,
|
|
85
83
|
projectKey: decodedToken[publicClaimForProjectKey]
|
|
86
84
|
};
|
|
87
|
-
|
|
85
|
+
const userPermissions = decodedToken[publicClaimForUserPermissionsKey];
|
|
88
86
|
|
|
89
87
|
if (Boolean(userPermissions === null || userPermissions === void 0 ? void 0 : userPermissions.length)) {
|
|
90
88
|
request.session.userPermissions = userPermissions;
|
|
@@ -99,7 +97,7 @@ var writeSessionContext = function writeSessionContext(request) {
|
|
|
99
97
|
// https://docs.commercetools.com/custom-applications/concepts/merchant-center-api#hostnames
|
|
100
98
|
|
|
101
99
|
|
|
102
|
-
|
|
100
|
+
const mapCloudIdentifierToIssuer = issuer => {
|
|
103
101
|
switch (issuer) {
|
|
104
102
|
case CLOUD_IDENTIFIERS.GCP_AU:
|
|
105
103
|
return MC_API_URLS.GCP_AU;
|
|
@@ -123,7 +121,7 @@ var mapCloudIdentifierToIssuer = function mapCloudIdentifierToIssuer(issuer) {
|
|
|
123
121
|
// This is for backwards compatibility.
|
|
124
122
|
|
|
125
123
|
|
|
126
|
-
|
|
124
|
+
const mapToLegacyIssuer = cloudIdentifier => {
|
|
127
125
|
switch (cloudIdentifier) {
|
|
128
126
|
case CLOUD_IDENTIFIERS.GCP_EU:
|
|
129
127
|
return 'https://mc-api.commercetools.com';
|
|
@@ -137,7 +135,7 @@ var mapToLegacyIssuer = function mapToLegacyIssuer(cloudIdentifier) {
|
|
|
137
135
|
}; // Verifies that the issuer is a valid URL.
|
|
138
136
|
|
|
139
137
|
|
|
140
|
-
|
|
138
|
+
const throwIfIssuerIsNotAValidUrl = issuer => {
|
|
141
139
|
try {
|
|
142
140
|
new _URL(issuer);
|
|
143
141
|
} catch (error) {
|
|
@@ -146,7 +144,7 @@ var throwIfIssuerIsNotAValidUrl = function throwIfIssuerIsNotAValidUrl(issuer) {
|
|
|
146
144
|
}; // Validates required option values.
|
|
147
145
|
|
|
148
146
|
|
|
149
|
-
|
|
147
|
+
const validateRequiredValues = options => {
|
|
150
148
|
if (!options.audience) {
|
|
151
149
|
throw new Error("Missing required option \"audience\"");
|
|
152
150
|
}
|
|
@@ -158,8 +156,8 @@ var validateRequiredValues = function validateRequiredValues(options) {
|
|
|
158
156
|
// be mapped to one of the supported values. If not, we assume the value is a valid URL.
|
|
159
157
|
|
|
160
158
|
|
|
161
|
-
|
|
162
|
-
|
|
159
|
+
const getConfiguredDefaultIssuer = options => {
|
|
160
|
+
const issuer = mapCloudIdentifierToIssuer(options.issuer);
|
|
163
161
|
|
|
164
162
|
if (!issuer) {
|
|
165
163
|
throwIfIssuerIsNotAValidUrl(options.issuer);
|
|
@@ -172,11 +170,11 @@ var getConfiguredDefaultIssuer = function getConfiguredDefaultIssuer(options) {
|
|
|
172
170
|
// the token validation might fail because of mismatching audiences.
|
|
173
171
|
|
|
174
172
|
|
|
175
|
-
|
|
173
|
+
const getConfiguredAudience = (options, requestPath) => {
|
|
176
174
|
var _context;
|
|
177
175
|
|
|
178
176
|
// remove the trailing slash
|
|
179
|
-
|
|
177
|
+
const url = new _URL(_concatInstanceProperty(_context = "".concat(options.audience.replace(/\/?$/, ''))).call(_context, requestPath));
|
|
180
178
|
|
|
181
179
|
switch (options.audiencePolicy) {
|
|
182
180
|
case 'forward-url-origin':
|
|
@@ -197,120 +195,75 @@ var getConfiguredAudience = function getConfiguredAudience(options, requestPath)
|
|
|
197
195
|
|
|
198
196
|
function createSessionAuthVerifier(options) {
|
|
199
197
|
validateRequiredValues(options);
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
return /*#__PURE__*/function () {
|
|
203
|
-
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(request, response) {
|
|
204
|
-
var _mapCloudIdentifierTo, _request$originalUrl;
|
|
205
|
-
|
|
206
|
-
var cloudIdentifierHeader, issuer, proxyForwardVersion, _mapToLegacyIssuer, requestUrlPath, audience;
|
|
207
|
-
|
|
208
|
-
return _regeneratorRuntime.wrap(function _callee$(_context3) {
|
|
209
|
-
while (1) {
|
|
210
|
-
switch (_context3.prev = _context3.next) {
|
|
211
|
-
case 0:
|
|
212
|
-
// Get the cloud identifier header, forwarded by the `/proxy/forward-to` endpoint.
|
|
213
|
-
cloudIdentifierHeader = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.CLOUD_IDENTIFIER, "Missing \"X-MC-API-Cloud-Identifier\" header.");
|
|
214
|
-
issuer = options.inferIssuer && cloudIdentifierHeader ? (_mapCloudIdentifierTo = mapCloudIdentifierToIssuer(cloudIdentifierHeader)) !== null && _mapCloudIdentifierTo !== void 0 ? _mapCloudIdentifierTo : configuredDefaultIssuer : configuredDefaultIssuer; // Get the `Accept-version` header, forwarded by the `/proxy/forward-to` endpoint.
|
|
215
|
-
// The version should be sent by the client making the request, to use the features of v2.
|
|
216
|
-
|
|
217
|
-
proxyForwardVersion = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.FORWARD_TO_VERSION, "Missing \"X-MC-API-Forward-To-Version\" header.");
|
|
218
|
-
|
|
219
|
-
if (proxyForwardVersion === 'v1') {
|
|
220
|
-
// Fall back to legacy issuer domains
|
|
221
|
-
issuer = (_mapToLegacyIssuer = mapToLegacyIssuer(cloudIdentifierHeader)) !== null && _mapToLegacyIssuer !== void 0 ? _mapToLegacyIssuer : issuer;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
requestUrlPath = options.getRequestUrl ? options.getRequestUrl(request) : (_request$originalUrl = request.originalUrl) !== null && _request$originalUrl !== void 0 ? _request$originalUrl : request.url;
|
|
225
|
-
|
|
226
|
-
if (!(!requestUrlPath || !_startsWithInstanceProperty(requestUrlPath).call(requestUrlPath, '/'))) {
|
|
227
|
-
_context3.next = 7;
|
|
228
|
-
break;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
throw new Error("Invalid request URI path \"".concat(requestUrlPath, "\". Please make sure that the \"request\" object has either a property \"originalUrl\" or \"url\". If not, you should implement the \"getRequestUrl\" function and make sure to return a valid URI path value starting with \"/\". More info at https://docs.commercetools.com/custom-applications/concepts/integrate-with-your-own-api#validating-the-json-web-token"));
|
|
232
|
-
|
|
233
|
-
case 7:
|
|
234
|
-
audience = getConfiguredAudience(options, requestUrlPath);
|
|
235
|
-
return _context3.abrupt("return", new _Promise(function (resolve, reject) {
|
|
236
|
-
expressjwt({
|
|
237
|
-
// Dynamically provide a signing key based on the kid in the header
|
|
238
|
-
// and the singing keys provided by the JWKS endpoint
|
|
239
|
-
secret: jwksRsa.expressJwtSecret(_objectSpread(_objectSpread({
|
|
240
|
-
// Default options
|
|
241
|
-
cache: true,
|
|
242
|
-
rateLimit: true,
|
|
243
|
-
jwksRequestsPerMinute: 5
|
|
244
|
-
}, options.jwks || {}), {}, {
|
|
245
|
-
// This should be set by the middleware, no matter what.
|
|
246
|
-
jwksUri: "".concat(issuer, "/.well-known/jwks.json")
|
|
247
|
-
})),
|
|
248
|
-
requestProperty: decodedTokenKey,
|
|
249
|
-
// Validate the audience and the issuer.
|
|
250
|
-
audience: audience,
|
|
251
|
-
issuer: issuer,
|
|
252
|
-
algorithms: ['RS256'] // @ts-ignore: the middleware expects an Express.js Request/Response objects
|
|
253
|
-
|
|
254
|
-
})(request, response !== null && response !== void 0 ? response : {}, function (error) {
|
|
255
|
-
if (error) {
|
|
256
|
-
reject(error);
|
|
257
|
-
} else {
|
|
258
|
-
// @ts-ignore: the Request object does not know about some additional fields
|
|
259
|
-
// like `decoded_token` and `session`
|
|
260
|
-
writeSessionContext(request);
|
|
261
|
-
resolve();
|
|
262
|
-
}
|
|
263
|
-
});
|
|
264
|
-
}));
|
|
265
|
-
|
|
266
|
-
case 9:
|
|
267
|
-
case "end":
|
|
268
|
-
return _context3.stop();
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
}, _callee);
|
|
272
|
-
}));
|
|
198
|
+
const configuredDefaultIssuer = getConfiguredDefaultIssuer(options); // Returns an async HTTP handler.
|
|
273
199
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
};
|
|
277
|
-
}();
|
|
278
|
-
}
|
|
200
|
+
return async (request, response) => {
|
|
201
|
+
var _mapCloudIdentifierTo, _request$originalUrl;
|
|
279
202
|
|
|
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
|
-
|
|
203
|
+
// Get the cloud identifier header, forwarded by the `/proxy/forward-to` endpoint.
|
|
204
|
+
const cloudIdentifierHeader = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.CLOUD_IDENTIFIER, "Missing \"X-MC-API-Cloud-Identifier\" header.");
|
|
205
|
+
let issuer = options.inferIssuer && cloudIdentifierHeader ? (_mapCloudIdentifierTo = mapCloudIdentifierToIssuer(cloudIdentifierHeader)) !== null && _mapCloudIdentifierTo !== void 0 ? _mapCloudIdentifierTo : configuredDefaultIssuer : configuredDefaultIssuer; // Get the `Accept-version` header, forwarded by the `/proxy/forward-to` endpoint.
|
|
206
|
+
// The version should be sent by the client making the request, to use the features of v2.
|
|
207
|
+
|
|
208
|
+
const proxyForwardVersion = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.FORWARD_TO_VERSION, "Missing \"X-MC-API-Forward-To-Version\" header.");
|
|
209
|
+
|
|
210
|
+
if (proxyForwardVersion === 'v1') {
|
|
211
|
+
var _mapToLegacyIssuer;
|
|
212
|
+
|
|
213
|
+
// Fall back to legacy issuer domains
|
|
214
|
+
issuer = (_mapToLegacyIssuer = mapToLegacyIssuer(cloudIdentifierHeader)) !== null && _mapToLegacyIssuer !== void 0 ? _mapToLegacyIssuer : issuer;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const requestUrlPath = options.getRequestUrl ? options.getRequestUrl(request) : (_request$originalUrl = request.originalUrl) !== null && _request$originalUrl !== void 0 ? _request$originalUrl : request.url;
|
|
218
|
+
|
|
219
|
+
if (!requestUrlPath || !_startsWithInstanceProperty(requestUrlPath).call(requestUrlPath, '/')) {
|
|
220
|
+
throw new Error("Invalid request URI path \"".concat(requestUrlPath, "\". Please make sure that the \"request\" object has either a property \"originalUrl\" or \"url\". If not, you should implement the \"getRequestUrl\" function and make sure to return a valid URI path value starting with \"/\". More info at https://docs.commercetools.com/custom-applications/concepts/integrate-with-your-own-api#validating-the-json-web-token"));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const audience = getConfiguredAudience(options, requestUrlPath);
|
|
224
|
+
return new _Promise((resolve, reject) => {
|
|
225
|
+
expressjwt({
|
|
226
|
+
// Dynamically provide a signing key based on the kid in the header
|
|
227
|
+
// and the singing keys provided by the JWKS endpoint
|
|
228
|
+
secret: jwksRsa.expressJwtSecret(_objectSpread(_objectSpread({
|
|
229
|
+
// Default options
|
|
230
|
+
cache: true,
|
|
231
|
+
rateLimit: true,
|
|
232
|
+
jwksRequestsPerMinute: 5
|
|
233
|
+
}, options.jwks || {}), {}, {
|
|
234
|
+
// This should be set by the middleware, no matter what.
|
|
235
|
+
jwksUri: "".concat(issuer, "/.well-known/jwks.json")
|
|
236
|
+
})),
|
|
237
|
+
requestProperty: decodedTokenKey,
|
|
238
|
+
// Validate the audience and the issuer.
|
|
239
|
+
audience,
|
|
240
|
+
issuer,
|
|
241
|
+
algorithms: ['RS256'] // @ts-ignore: the middleware expects an Express.js Request/Response objects
|
|
242
|
+
|
|
243
|
+
})(request, response !== null && response !== void 0 ? response : {}, error => {
|
|
244
|
+
if (error) {
|
|
245
|
+
reject(error);
|
|
246
|
+
} else {
|
|
247
|
+
// @ts-ignore: the Request object does not know about some additional fields
|
|
248
|
+
// like `decoded_token` and `session`
|
|
249
|
+
writeSessionContext(request);
|
|
250
|
+
resolve();
|
|
306
251
|
}
|
|
307
|
-
}
|
|
308
|
-
})
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
};
|
|
255
|
+
}
|
|
309
256
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
257
|
+
function createSessionMiddleware(options) {
|
|
258
|
+
const sessionAuthVerifier = createSessionAuthVerifier(options);
|
|
259
|
+
return async (request, response, next) => {
|
|
260
|
+
try {
|
|
261
|
+
await sessionAuthVerifier(request, response);
|
|
262
|
+
next();
|
|
263
|
+
} catch (error) {
|
|
264
|
+
next(error);
|
|
265
|
+
}
|
|
266
|
+
};
|
|
314
267
|
}
|
|
315
268
|
|
|
316
269
|
export { CLOUD_IDENTIFIERS, MC_API_URLS, createSessionAuthVerifier, createSessionMiddleware };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commercetools-backend/express",
|
|
3
|
-
"version": "21.
|
|
3
|
+
"version": "21.24.1",
|
|
4
4
|
"description": "Zero-config HTTP server as Express.js to facilitate development",
|
|
5
5
|
"bugs": "https://github.com/commercetools/merchant-center-application-kit/issues",
|
|
6
6
|
"repository": {
|
|
@@ -30,6 +30,6 @@
|
|
|
30
30
|
"@types/express-unless": "^0.5.3",
|
|
31
31
|
"@types/jsonwebtoken": "^8.5.9",
|
|
32
32
|
"jose": "2.0.6",
|
|
33
|
-
"msw": "0.
|
|
33
|
+
"msw": "0.49.3"
|
|
34
34
|
}
|
|
35
35
|
}
|