@commercetools-backend/express 21.6.0 → 21.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +1 -69
- package/dist/commercetools-backend-express.cjs.dev.js +51 -12
- package/dist/commercetools-backend-express.cjs.prod.js +51 -12
- package/dist/commercetools-backend-express.esm.js +48 -12
- package/dist/declarations/src/types.d.ts +30 -0
- package/dist/declarations/src/utils.d.ts +3 -2
- package/package.json +6 -5
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -14,72 +14,4 @@ This package is primarily built for HTTP servers used by Custom Applications and
|
|
|
14
14
|
$ npm install --save @commercetools-backend/express
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
This Express.js middleware should be used to handle the authentication exchange between the server and the `/proxy/forward-to` endpoint of the Merchant Center API Gateway.
|
|
20
|
-
|
|
21
|
-
> You can read more about the "Proxy to External API" concepts [here](https://docs.commercetools.com/custom-applications/main-concepts/proxy-to-external-api).
|
|
22
|
-
|
|
23
|
-
```js
|
|
24
|
-
const {
|
|
25
|
-
createSessionMiddleware,
|
|
26
|
-
CLOUD_IDENTIFIERS,
|
|
27
|
-
} = require('@commercetools-backend/express');
|
|
28
|
-
|
|
29
|
-
app.use(
|
|
30
|
-
createSessionMiddleware({
|
|
31
|
-
audience: 'https://my-api-server.com',
|
|
32
|
-
issuer: CLOUD_IDENTIFIERS.GCP_EU,
|
|
33
|
-
})
|
|
34
|
-
);
|
|
35
|
-
app.use((request, response, next) => {
|
|
36
|
-
// `request.session` contains the useful information
|
|
37
|
-
});
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
### Middleware options
|
|
41
|
-
|
|
42
|
-
- `audience` (_string_): The public-facing URL of your API server. The value should only contain the origin URL (protocol, hostname, port), the request path is inferred from the incoming request.
|
|
43
|
-
|
|
44
|
-
- `issuer` (_string_): Either a cloud identifier or a valid URL to the Merchant Center API Gateway. The cloud identifier maps to the Merchant Center API URL of the related [cloud region](https://docs.commercetools.com/custom-applications/concepts/merchant-center-api#cloud-regions).
|
|
45
|
-
|
|
46
|
-
- `gcp-au`: `https://mc-api.australia-southeast1.gcp.commercetools.com`
|
|
47
|
-
- `gcp-eu`: `https://mc-api.europe-west1.gcp.commercetools.com`
|
|
48
|
-
- `gcp-us`: `https://mc-api.us-central1.gcp.commercetools.com`
|
|
49
|
-
- `aws-fra`: `https://mc-api.eu-central-1.aws.commercetools.com`
|
|
50
|
-
- `aws-ohio`: `https://mc-api.us-east-2.aws.commercetools.com`
|
|
51
|
-
|
|
52
|
-
- `inferIssuer` (_boolean_): Determines whether the issuer should be inferred from the custom request HTTP header `x-mc-api-cloud-identifier` which is sent by the Merchant Center API Gateway when forwarding the request. This might be useful in case the server is used in multiple regions.
|
|
53
|
-
|
|
54
|
-
- `jwks` (_object_): See options of `jwks-rsa`.
|
|
55
|
-
|
|
56
|
-
### Usage in Serverless Functions
|
|
57
|
-
|
|
58
|
-
If your HTTP server runs as a Serverless Function, the Express.js middleware should not be needed. Instead you can use the underlying function that does not require the `next` callback.
|
|
59
|
-
|
|
60
|
-
**Example for Google Cloud Functions**
|
|
61
|
-
|
|
62
|
-
```js
|
|
63
|
-
const {
|
|
64
|
-
createSessionAuthVerifier,
|
|
65
|
-
CLOUD_IDENTIFIERS,
|
|
66
|
-
} = require('@commercetools-backend/express');
|
|
67
|
-
|
|
68
|
-
const sessionAuthVerifier = createSessionAuthVerifier({
|
|
69
|
-
audience: 'https://my-api-server.com',
|
|
70
|
-
issuer: CLOUD_IDENTIFIERS.GCP_EU,
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
exports.handler = async function (request, response) {
|
|
74
|
-
try {
|
|
75
|
-
await sessionAuthVerifier(request, response);
|
|
76
|
-
} catch (error) {
|
|
77
|
-
response.status(401).send(JSON.stringify({ message: 'Unauthorized' }));
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// `request.session` contains the useful information
|
|
82
|
-
};
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
> The same concept applies for serverless functions in other cloud providers.
|
|
17
|
+
Check out the [documentation](https://docs.commercetools.com/custom-applications/concepts/integrate-with-your-own-api) for more information.
|
|
@@ -7,6 +7,7 @@ var _asyncToGenerator = require('@babel/runtime-corejs3/helpers/asyncToGenerator
|
|
|
7
7
|
var _regeneratorRuntime = require('@babel/runtime-corejs3/regenerator');
|
|
8
8
|
var _URL = require('@babel/runtime-corejs3/core-js-stable/url');
|
|
9
9
|
var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat');
|
|
10
|
+
var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with');
|
|
10
11
|
var _Promise = require('@babel/runtime-corejs3/core-js-stable/promise');
|
|
11
12
|
var _Object$keys = require('@babel/runtime-corejs3/core-js-stable/object/keys');
|
|
12
13
|
var _Object$getOwnPropertySymbols = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols');
|
|
@@ -18,6 +19,9 @@ var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/ob
|
|
|
18
19
|
var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
|
|
19
20
|
var jwksRsa = require('jwks-rsa');
|
|
20
21
|
var expressJwt = require('express-jwt');
|
|
22
|
+
var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray');
|
|
23
|
+
var _findInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/find');
|
|
24
|
+
var _Object$entries = require('@babel/runtime-corejs3/core-js-stable/object/entries');
|
|
21
25
|
var _Array$isArray = require('@babel/runtime-corejs3/core-js-stable/array/is-array');
|
|
22
26
|
|
|
23
27
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
@@ -25,6 +29,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e };
|
|
|
25
29
|
var _regeneratorRuntime__default = /*#__PURE__*/_interopDefault(_regeneratorRuntime);
|
|
26
30
|
var _URL__default = /*#__PURE__*/_interopDefault(_URL);
|
|
27
31
|
var _concatInstanceProperty__default = /*#__PURE__*/_interopDefault(_concatInstanceProperty);
|
|
32
|
+
var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsWithInstanceProperty);
|
|
28
33
|
var _Promise__default = /*#__PURE__*/_interopDefault(_Promise);
|
|
29
34
|
var _Object$keys__default = /*#__PURE__*/_interopDefault(_Object$keys);
|
|
30
35
|
var _Object$getOwnPropertySymbols__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertySymbols);
|
|
@@ -35,6 +40,8 @@ var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_O
|
|
|
35
40
|
var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
|
|
36
41
|
var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
|
|
37
42
|
var jwksRsa__default = /*#__PURE__*/_interopDefault(jwksRsa);
|
|
43
|
+
var _findInstanceProperty__default = /*#__PURE__*/_interopDefault(_findInstanceProperty);
|
|
44
|
+
var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
|
|
38
45
|
var _Array$isArray__default = /*#__PURE__*/_interopDefault(_Array$isArray);
|
|
39
46
|
|
|
40
47
|
var CLOUD_IDENTIFIERS = {
|
|
@@ -56,12 +63,34 @@ var MC_API_PROXY_HEADERS = {
|
|
|
56
63
|
CLOUD_IDENTIFIER: 'x-mc-api-cloud-identifier'
|
|
57
64
|
};
|
|
58
65
|
|
|
59
|
-
var
|
|
60
|
-
|
|
66
|
+
var getHeaderByCaseInsensitiveKey = function getHeaderByCaseInsensitiveKey(headers, headerKey) {
|
|
67
|
+
var _context;
|
|
68
|
+
|
|
69
|
+
var matchingHeader = _findInstanceProperty__default["default"](_context = _Object$entries__default["default"](headers)).call(_context, function (_ref) {
|
|
70
|
+
var _ref2 = _slicedToArray(_ref, 1),
|
|
71
|
+
key = _ref2[0];
|
|
72
|
+
|
|
73
|
+
return headerKey.toLowerCase() === key.toLowerCase();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (matchingHeader && matchingHeader.length > 0) {
|
|
77
|
+
var _matchingHeader = _slicedToArray(matchingHeader, 2),
|
|
78
|
+
headerValue = _matchingHeader[1];
|
|
79
|
+
|
|
80
|
+
return _Array$isArray__default["default"](headerValue) ? headerValue[0] : headerValue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return undefined;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
var getFirstHeaderValueOrThrow = function getFirstHeaderValueOrThrow(headers, headerKey, errorMessage) {
|
|
87
|
+
var headerValue = getHeaderByCaseInsensitiveKey(headers, headerKey);
|
|
88
|
+
|
|
89
|
+
if (!headerValue) {
|
|
61
90
|
throw new Error(errorMessage);
|
|
62
91
|
}
|
|
63
92
|
|
|
64
|
-
return
|
|
93
|
+
return headerValue;
|
|
65
94
|
};
|
|
66
95
|
|
|
67
96
|
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; }
|
|
@@ -162,16 +191,26 @@ var getConfiguredDefaultIssuer = function getConfiguredDefaultIssuer(options) {
|
|
|
162
191
|
|
|
163
192
|
|
|
164
193
|
var getConfiguredAudience = function getConfiguredAudience(options, requestPath) {
|
|
165
|
-
var _context
|
|
194
|
+
var _context;
|
|
166
195
|
|
|
167
196
|
// remove the trailing slash
|
|
168
197
|
var url = new _URL__default["default"](_concatInstanceProperty__default["default"](_context = "".concat(options.audience.replace(/\/?$/, ''))).call(_context, requestPath));
|
|
169
198
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
199
|
+
switch (options.audiencePolicy) {
|
|
200
|
+
case 'forward-url-origin':
|
|
201
|
+
return url.origin;
|
|
202
|
+
|
|
203
|
+
default:
|
|
204
|
+
{
|
|
205
|
+
var _context2;
|
|
173
206
|
|
|
174
|
-
|
|
207
|
+
if (requestPath === '/') {
|
|
208
|
+
return url.origin;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return _concatInstanceProperty__default["default"](_context2 = "".concat(url.origin)).call(_context2, url.pathname);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
175
214
|
};
|
|
176
215
|
|
|
177
216
|
function createSessionAuthVerifier(options) {
|
|
@@ -189,11 +228,11 @@ function createSessionAuthVerifier(options) {
|
|
|
189
228
|
switch (_context3.prev = _context3.next) {
|
|
190
229
|
case 0:
|
|
191
230
|
// Get the cloud identifier header, forwarded by the `/proxy/forward-to` endpoint.
|
|
192
|
-
cloudIdentifierHeader =
|
|
231
|
+
cloudIdentifierHeader = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.CLOUD_IDENTIFIER, "Missing \"X-MC-API-Cloud-Identifier\" header.");
|
|
193
232
|
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.
|
|
194
233
|
// The version should be sent by the client making the request, to use the features of v2.
|
|
195
234
|
|
|
196
|
-
proxyForwardVersion =
|
|
235
|
+
proxyForwardVersion = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.FORWARD_TO_VERSION, "Missing \"X-MC-API-Forward-To-Version\" header.");
|
|
197
236
|
|
|
198
237
|
if (proxyForwardVersion === 'v1') {
|
|
199
238
|
// Fall back to legacy issuer domains
|
|
@@ -202,12 +241,12 @@ function createSessionAuthVerifier(options) {
|
|
|
202
241
|
|
|
203
242
|
requestUrlPath = options.getRequestUrl ? options.getRequestUrl(request) : (_request$originalUrl = request.originalUrl) !== null && _request$originalUrl !== void 0 ? _request$originalUrl : request.url;
|
|
204
243
|
|
|
205
|
-
if (requestUrlPath) {
|
|
244
|
+
if (!(!requestUrlPath || !_startsWithInstanceProperty__default["default"](requestUrlPath).call(requestUrlPath, '/'))) {
|
|
206
245
|
_context3.next = 7;
|
|
207
246
|
break;
|
|
208
247
|
}
|
|
209
248
|
|
|
210
|
-
throw new Error(
|
|
249
|
+
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"));
|
|
211
250
|
|
|
212
251
|
case 7:
|
|
213
252
|
audience = getConfiguredAudience(options, requestUrlPath);
|
|
@@ -7,6 +7,7 @@ var _asyncToGenerator = require('@babel/runtime-corejs3/helpers/asyncToGenerator
|
|
|
7
7
|
var _regeneratorRuntime = require('@babel/runtime-corejs3/regenerator');
|
|
8
8
|
var _URL = require('@babel/runtime-corejs3/core-js-stable/url');
|
|
9
9
|
var _concatInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/concat');
|
|
10
|
+
var _startsWithInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/starts-with');
|
|
10
11
|
var _Promise = require('@babel/runtime-corejs3/core-js-stable/promise');
|
|
11
12
|
var _Object$keys = require('@babel/runtime-corejs3/core-js-stable/object/keys');
|
|
12
13
|
var _Object$getOwnPropertySymbols = require('@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols');
|
|
@@ -18,6 +19,9 @@ var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/ob
|
|
|
18
19
|
var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
|
|
19
20
|
var jwksRsa = require('jwks-rsa');
|
|
20
21
|
var expressJwt = require('express-jwt');
|
|
22
|
+
var _slicedToArray = require('@babel/runtime-corejs3/helpers/slicedToArray');
|
|
23
|
+
var _findInstanceProperty = require('@babel/runtime-corejs3/core-js-stable/instance/find');
|
|
24
|
+
var _Object$entries = require('@babel/runtime-corejs3/core-js-stable/object/entries');
|
|
21
25
|
var _Array$isArray = require('@babel/runtime-corejs3/core-js-stable/array/is-array');
|
|
22
26
|
|
|
23
27
|
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
@@ -25,6 +29,7 @@ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e };
|
|
|
25
29
|
var _regeneratorRuntime__default = /*#__PURE__*/_interopDefault(_regeneratorRuntime);
|
|
26
30
|
var _URL__default = /*#__PURE__*/_interopDefault(_URL);
|
|
27
31
|
var _concatInstanceProperty__default = /*#__PURE__*/_interopDefault(_concatInstanceProperty);
|
|
32
|
+
var _startsWithInstanceProperty__default = /*#__PURE__*/_interopDefault(_startsWithInstanceProperty);
|
|
28
33
|
var _Promise__default = /*#__PURE__*/_interopDefault(_Promise);
|
|
29
34
|
var _Object$keys__default = /*#__PURE__*/_interopDefault(_Object$keys);
|
|
30
35
|
var _Object$getOwnPropertySymbols__default = /*#__PURE__*/_interopDefault(_Object$getOwnPropertySymbols);
|
|
@@ -35,6 +40,8 @@ var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_O
|
|
|
35
40
|
var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
|
|
36
41
|
var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
|
|
37
42
|
var jwksRsa__default = /*#__PURE__*/_interopDefault(jwksRsa);
|
|
43
|
+
var _findInstanceProperty__default = /*#__PURE__*/_interopDefault(_findInstanceProperty);
|
|
44
|
+
var _Object$entries__default = /*#__PURE__*/_interopDefault(_Object$entries);
|
|
38
45
|
var _Array$isArray__default = /*#__PURE__*/_interopDefault(_Array$isArray);
|
|
39
46
|
|
|
40
47
|
var CLOUD_IDENTIFIERS = {
|
|
@@ -56,12 +63,34 @@ var MC_API_PROXY_HEADERS = {
|
|
|
56
63
|
CLOUD_IDENTIFIER: 'x-mc-api-cloud-identifier'
|
|
57
64
|
};
|
|
58
65
|
|
|
59
|
-
var
|
|
60
|
-
|
|
66
|
+
var getHeaderByCaseInsensitiveKey = function getHeaderByCaseInsensitiveKey(headers, headerKey) {
|
|
67
|
+
var _context;
|
|
68
|
+
|
|
69
|
+
var matchingHeader = _findInstanceProperty__default["default"](_context = _Object$entries__default["default"](headers)).call(_context, function (_ref) {
|
|
70
|
+
var _ref2 = _slicedToArray(_ref, 1),
|
|
71
|
+
key = _ref2[0];
|
|
72
|
+
|
|
73
|
+
return headerKey.toLowerCase() === key.toLowerCase();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
if (matchingHeader && matchingHeader.length > 0) {
|
|
77
|
+
var _matchingHeader = _slicedToArray(matchingHeader, 2),
|
|
78
|
+
headerValue = _matchingHeader[1];
|
|
79
|
+
|
|
80
|
+
return _Array$isArray__default["default"](headerValue) ? headerValue[0] : headerValue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return undefined;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
var getFirstHeaderValueOrThrow = function getFirstHeaderValueOrThrow(headers, headerKey, errorMessage) {
|
|
87
|
+
var headerValue = getHeaderByCaseInsensitiveKey(headers, headerKey);
|
|
88
|
+
|
|
89
|
+
if (!headerValue) {
|
|
61
90
|
throw new Error(errorMessage);
|
|
62
91
|
}
|
|
63
92
|
|
|
64
|
-
return
|
|
93
|
+
return headerValue;
|
|
65
94
|
};
|
|
66
95
|
|
|
67
96
|
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; }
|
|
@@ -162,16 +191,26 @@ var getConfiguredDefaultIssuer = function getConfiguredDefaultIssuer(options) {
|
|
|
162
191
|
|
|
163
192
|
|
|
164
193
|
var getConfiguredAudience = function getConfiguredAudience(options, requestPath) {
|
|
165
|
-
var _context
|
|
194
|
+
var _context;
|
|
166
195
|
|
|
167
196
|
// remove the trailing slash
|
|
168
197
|
var url = new _URL__default["default"](_concatInstanceProperty__default["default"](_context = "".concat(options.audience.replace(/\/?$/, ''))).call(_context, requestPath));
|
|
169
198
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
199
|
+
switch (options.audiencePolicy) {
|
|
200
|
+
case 'forward-url-origin':
|
|
201
|
+
return url.origin;
|
|
202
|
+
|
|
203
|
+
default:
|
|
204
|
+
{
|
|
205
|
+
var _context2;
|
|
173
206
|
|
|
174
|
-
|
|
207
|
+
if (requestPath === '/') {
|
|
208
|
+
return url.origin;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return _concatInstanceProperty__default["default"](_context2 = "".concat(url.origin)).call(_context2, url.pathname);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
175
214
|
};
|
|
176
215
|
|
|
177
216
|
function createSessionAuthVerifier(options) {
|
|
@@ -189,11 +228,11 @@ function createSessionAuthVerifier(options) {
|
|
|
189
228
|
switch (_context3.prev = _context3.next) {
|
|
190
229
|
case 0:
|
|
191
230
|
// Get the cloud identifier header, forwarded by the `/proxy/forward-to` endpoint.
|
|
192
|
-
cloudIdentifierHeader =
|
|
231
|
+
cloudIdentifierHeader = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.CLOUD_IDENTIFIER, "Missing \"X-MC-API-Cloud-Identifier\" header.");
|
|
193
232
|
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.
|
|
194
233
|
// The version should be sent by the client making the request, to use the features of v2.
|
|
195
234
|
|
|
196
|
-
proxyForwardVersion =
|
|
235
|
+
proxyForwardVersion = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.FORWARD_TO_VERSION, "Missing \"X-MC-API-Forward-To-Version\" header.");
|
|
197
236
|
|
|
198
237
|
if (proxyForwardVersion === 'v1') {
|
|
199
238
|
// Fall back to legacy issuer domains
|
|
@@ -202,12 +241,12 @@ function createSessionAuthVerifier(options) {
|
|
|
202
241
|
|
|
203
242
|
requestUrlPath = options.getRequestUrl ? options.getRequestUrl(request) : (_request$originalUrl = request.originalUrl) !== null && _request$originalUrl !== void 0 ? _request$originalUrl : request.url;
|
|
204
243
|
|
|
205
|
-
if (requestUrlPath) {
|
|
244
|
+
if (!(!requestUrlPath || !_startsWithInstanceProperty__default["default"](requestUrlPath).call(requestUrlPath, '/'))) {
|
|
206
245
|
_context3.next = 7;
|
|
207
246
|
break;
|
|
208
247
|
}
|
|
209
248
|
|
|
210
|
-
throw new Error(
|
|
249
|
+
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"));
|
|
211
250
|
|
|
212
251
|
case 7:
|
|
213
252
|
audience = getConfiguredAudience(options, requestUrlPath);
|
|
@@ -3,6 +3,7 @@ import _asyncToGenerator from '@babel/runtime-corejs3/helpers/esm/asyncToGenerat
|
|
|
3
3
|
import _regeneratorRuntime from '@babel/runtime-corejs3/regenerator';
|
|
4
4
|
import _URL from '@babel/runtime-corejs3/core-js-stable/url';
|
|
5
5
|
import _concatInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/concat';
|
|
6
|
+
import _startsWithInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/starts-with';
|
|
6
7
|
import _Promise from '@babel/runtime-corejs3/core-js-stable/promise';
|
|
7
8
|
import _Object$keys from '@babel/runtime-corejs3/core-js-stable/object/keys';
|
|
8
9
|
import _Object$getOwnPropertySymbols from '@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols';
|
|
@@ -14,6 +15,9 @@ import _Object$defineProperties from '@babel/runtime-corejs3/core-js-stable/obje
|
|
|
14
15
|
import _Object$defineProperty from '@babel/runtime-corejs3/core-js-stable/object/define-property';
|
|
15
16
|
import jwksRsa from 'jwks-rsa';
|
|
16
17
|
import { expressjwt } from 'express-jwt';
|
|
18
|
+
import _slicedToArray from '@babel/runtime-corejs3/helpers/esm/slicedToArray';
|
|
19
|
+
import _findInstanceProperty from '@babel/runtime-corejs3/core-js-stable/instance/find';
|
|
20
|
+
import _Object$entries from '@babel/runtime-corejs3/core-js-stable/object/entries';
|
|
17
21
|
import _Array$isArray from '@babel/runtime-corejs3/core-js-stable/array/is-array';
|
|
18
22
|
|
|
19
23
|
var CLOUD_IDENTIFIERS = {
|
|
@@ -35,12 +39,34 @@ var MC_API_PROXY_HEADERS = {
|
|
|
35
39
|
CLOUD_IDENTIFIER: 'x-mc-api-cloud-identifier'
|
|
36
40
|
};
|
|
37
41
|
|
|
38
|
-
var
|
|
39
|
-
|
|
42
|
+
var getHeaderByCaseInsensitiveKey = function getHeaderByCaseInsensitiveKey(headers, headerKey) {
|
|
43
|
+
var _context;
|
|
44
|
+
|
|
45
|
+
var matchingHeader = _findInstanceProperty(_context = _Object$entries(headers)).call(_context, function (_ref) {
|
|
46
|
+
var _ref2 = _slicedToArray(_ref, 1),
|
|
47
|
+
key = _ref2[0];
|
|
48
|
+
|
|
49
|
+
return headerKey.toLowerCase() === key.toLowerCase();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (matchingHeader && matchingHeader.length > 0) {
|
|
53
|
+
var _matchingHeader = _slicedToArray(matchingHeader, 2),
|
|
54
|
+
headerValue = _matchingHeader[1];
|
|
55
|
+
|
|
56
|
+
return _Array$isArray(headerValue) ? headerValue[0] : headerValue;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return undefined;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
var getFirstHeaderValueOrThrow = function getFirstHeaderValueOrThrow(headers, headerKey, errorMessage) {
|
|
63
|
+
var headerValue = getHeaderByCaseInsensitiveKey(headers, headerKey);
|
|
64
|
+
|
|
65
|
+
if (!headerValue) {
|
|
40
66
|
throw new Error(errorMessage);
|
|
41
67
|
}
|
|
42
68
|
|
|
43
|
-
return
|
|
69
|
+
return headerValue;
|
|
44
70
|
};
|
|
45
71
|
|
|
46
72
|
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; }
|
|
@@ -141,16 +167,26 @@ var getConfiguredDefaultIssuer = function getConfiguredDefaultIssuer(options) {
|
|
|
141
167
|
|
|
142
168
|
|
|
143
169
|
var getConfiguredAudience = function getConfiguredAudience(options, requestPath) {
|
|
144
|
-
var _context
|
|
170
|
+
var _context;
|
|
145
171
|
|
|
146
172
|
// remove the trailing slash
|
|
147
173
|
var url = new _URL(_concatInstanceProperty(_context = "".concat(options.audience.replace(/\/?$/, ''))).call(_context, requestPath));
|
|
148
174
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
175
|
+
switch (options.audiencePolicy) {
|
|
176
|
+
case 'forward-url-origin':
|
|
177
|
+
return url.origin;
|
|
178
|
+
|
|
179
|
+
default:
|
|
180
|
+
{
|
|
181
|
+
var _context2;
|
|
152
182
|
|
|
153
|
-
|
|
183
|
+
if (requestPath === '/') {
|
|
184
|
+
return url.origin;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return _concatInstanceProperty(_context2 = "".concat(url.origin)).call(_context2, url.pathname);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
154
190
|
};
|
|
155
191
|
|
|
156
192
|
function createSessionAuthVerifier(options) {
|
|
@@ -168,11 +204,11 @@ function createSessionAuthVerifier(options) {
|
|
|
168
204
|
switch (_context3.prev = _context3.next) {
|
|
169
205
|
case 0:
|
|
170
206
|
// Get the cloud identifier header, forwarded by the `/proxy/forward-to` endpoint.
|
|
171
|
-
cloudIdentifierHeader =
|
|
207
|
+
cloudIdentifierHeader = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.CLOUD_IDENTIFIER, "Missing \"X-MC-API-Cloud-Identifier\" header.");
|
|
172
208
|
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.
|
|
173
209
|
// The version should be sent by the client making the request, to use the features of v2.
|
|
174
210
|
|
|
175
|
-
proxyForwardVersion =
|
|
211
|
+
proxyForwardVersion = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.FORWARD_TO_VERSION, "Missing \"X-MC-API-Forward-To-Version\" header.");
|
|
176
212
|
|
|
177
213
|
if (proxyForwardVersion === 'v1') {
|
|
178
214
|
// Fall back to legacy issuer domains
|
|
@@ -181,12 +217,12 @@ function createSessionAuthVerifier(options) {
|
|
|
181
217
|
|
|
182
218
|
requestUrlPath = options.getRequestUrl ? options.getRequestUrl(request) : (_request$originalUrl = request.originalUrl) !== null && _request$originalUrl !== void 0 ? _request$originalUrl : request.url;
|
|
183
219
|
|
|
184
|
-
if (requestUrlPath) {
|
|
220
|
+
if (!(!requestUrlPath || !_startsWithInstanceProperty(requestUrlPath).call(requestUrlPath, '/'))) {
|
|
185
221
|
_context3.next = 7;
|
|
186
222
|
break;
|
|
187
223
|
}
|
|
188
224
|
|
|
189
|
-
throw new Error(
|
|
225
|
+
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"));
|
|
190
226
|
|
|
191
227
|
case 7:
|
|
192
228
|
audience = getConfiguredAudience(options, requestUrlPath);
|
|
@@ -3,16 +3,46 @@ import { CLOUD_IDENTIFIERS } from './constants';
|
|
|
3
3
|
export declare type TAudience = string;
|
|
4
4
|
export declare type TIssuer = string;
|
|
5
5
|
export declare type TCloudIdentifier = typeof CLOUD_IDENTIFIERS[keyof typeof CLOUD_IDENTIFIERS];
|
|
6
|
+
export declare type TAudiencePolicy = 'forward-url-full-path' | 'forward-url-origin';
|
|
6
7
|
export interface TBaseRequest {
|
|
7
8
|
headers: Record<string, string | string[] | undefined>;
|
|
8
9
|
url?: string;
|
|
9
10
|
originalUrl?: string;
|
|
10
11
|
}
|
|
11
12
|
export declare type TSessionMiddlewareOptions<Request extends TBaseRequest> = {
|
|
13
|
+
/**
|
|
14
|
+
* The public-facing URL used to connect to the server / serverless function.
|
|
15
|
+
* The value should only contain the origin URL (protocol, hostname, port),
|
|
16
|
+
* the request path is inferred from the incoming request.
|
|
17
|
+
*/
|
|
12
18
|
audience: TAudience;
|
|
19
|
+
/**
|
|
20
|
+
* How the audience value should be exchanged between the server and the client.
|
|
21
|
+
* By default it uses the full URL (origin + pathname).
|
|
22
|
+
*/
|
|
23
|
+
audiencePolicy?: TAudiencePolicy;
|
|
24
|
+
/**
|
|
25
|
+
* The cloud identifier (see `CLOUD_IDENTIFIERS`) that maps to the MC API URL
|
|
26
|
+
* of the related cloud region or the MC API URL.
|
|
27
|
+
*/
|
|
13
28
|
issuer: TCloudIdentifier | TIssuer;
|
|
29
|
+
/**
|
|
30
|
+
* Determines whether the issuer should be inferred from the custom request
|
|
31
|
+
* HTTP header `x-mc-api-cloud-identifier` which is sent by the MC API when
|
|
32
|
+
* forwarding the request.
|
|
33
|
+
* This might be useful in case the server is used in multiple regions.
|
|
34
|
+
*/
|
|
14
35
|
inferIssuer?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Options for the `jwksRsa.expressJwtSecret`
|
|
38
|
+
*/
|
|
15
39
|
jwks?: Omit<ExpressJwtOptions, 'jwksUri'>;
|
|
40
|
+
/**
|
|
41
|
+
* By default we assume that the `request` is a Node.js-like object having either
|
|
42
|
+
* an `originalUrl` or `url` properties.
|
|
43
|
+
* If that's not the case (for example in AWS Lambda functions) you need to correctly
|
|
44
|
+
* map the URL (URI path + query string) of the `request`.
|
|
45
|
+
*/
|
|
16
46
|
getRequestUrl?: (request: Request) => string;
|
|
17
47
|
};
|
|
18
48
|
export declare type TSession = {
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
declare const
|
|
2
|
-
|
|
1
|
+
declare const getHeaderByCaseInsensitiveKey: (headers: Record<string, string | string[] | undefined>, headerKey: string) => string | undefined;
|
|
2
|
+
declare const getFirstHeaderValueOrThrow: (headers: Record<string, string | string[] | undefined>, headerKey: string, errorMessage: string) => string;
|
|
3
|
+
export { getHeaderByCaseInsensitiveKey, getFirstHeaderValueOrThrow };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commercetools-backend/express",
|
|
3
|
-
"version": "21.
|
|
3
|
+
"version": "21.9.0",
|
|
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": {
|
|
@@ -18,17 +18,18 @@
|
|
|
18
18
|
"module": "dist/commercetools-backend-express.esm.js",
|
|
19
19
|
"files": ["dist", "package.json", "LICENSE", "README.md"],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@babel/runtime": "^7.
|
|
22
|
-
"@babel/runtime-corejs3": "^7.
|
|
23
|
-
"@types/node": "16.11.33",
|
|
21
|
+
"@babel/runtime": "^7.18.6",
|
|
22
|
+
"@babel/runtime-corejs3": "^7.18.6",
|
|
23
|
+
"@types/node": "^16.11.33",
|
|
24
24
|
"express": "4.18.1",
|
|
25
25
|
"express-jwt": "7.7.0",
|
|
26
26
|
"jwks-rsa": "2.1.1"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
+
"@tsconfig/node16": "^1.0.3",
|
|
29
30
|
"@types/express-unless": "^0.5.3",
|
|
30
31
|
"@types/jsonwebtoken": "^8.5.8",
|
|
31
32
|
"jose": "2.0.5",
|
|
32
|
-
"msw": "0.
|
|
33
|
+
"msw": "0.44.0"
|
|
33
34
|
}
|
|
34
35
|
}
|