@commercetools-backend/express 22.2.1 → 22.3.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.
@@ -62,42 +62,32 @@ const MC_API_PROXY_HEADERS = {
62
62
 
63
63
  const getHeaderByCaseInsensitiveKey = (headers, headerKey) => {
64
64
  var _context;
65
-
66
65
  const matchingHeader = _findInstanceProperty__default["default"](_context = _Object$entries__default["default"](headers)).call(_context, _ref => {
67
66
  let _ref2 = _slicedToArray(_ref, 1),
68
- key = _ref2[0];
69
-
67
+ key = _ref2[0];
70
68
  return headerKey.toLowerCase() === key.toLowerCase();
71
69
  });
72
-
73
70
  if (matchingHeader && matchingHeader.length > 0) {
74
71
  const _matchingHeader = _slicedToArray(matchingHeader, 2),
75
- headerValue = _matchingHeader[1];
76
-
72
+ headerValue = _matchingHeader[1];
77
73
  return _Array$isArray__default["default"](headerValue) ? headerValue[0] : headerValue;
78
74
  }
79
-
80
75
  return undefined;
81
76
  };
82
-
83
77
  const getFirstHeaderValueOrThrow = (headers, headerKey, errorMessage) => {
84
78
  const headerValue = getHeaderByCaseInsensitiveKey(headers, headerKey);
85
-
86
79
  if (!headerValue) {
87
80
  throw new Error(errorMessage);
88
81
  }
89
-
90
82
  return headerValue;
91
83
  };
92
84
 
93
85
  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; }
94
-
95
86
  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.
97
-
87
+ const decodedTokenKey = 'decoded_token';
88
+ // Assign a session object to the request object.
98
89
  const writeSessionContext = request => {
99
90
  const decodedToken = request[decodedTokenKey];
100
-
101
91
  if (decodedToken) {
102
92
  const publicClaimForProjectKey = "".concat(decodedToken.iss, "/claims/project_key");
103
93
  const publicClaimForUserPermissionsKey = "".concat(decodedToken.iss, "/claims/user_permissions");
@@ -106,143 +96,118 @@ const writeSessionContext = request => {
106
96
  projectKey: decodedToken[publicClaimForProjectKey]
107
97
  };
108
98
  const userPermissions = decodedToken[publicClaimForUserPermissionsKey];
109
-
110
99
  if (Boolean(userPermissions === null || userPermissions === void 0 ? void 0 : userPermissions.length)) {
111
100
  request.session.userPermissions = userPermissions;
112
101
  }
113
- } // Remove the field used by the JWT middleware.
114
-
102
+ }
115
103
 
104
+ // Remove the field used by the JWT middleware.
116
105
  delete request.decoded_token;
117
- }; // Given a cloud identifier, try to map it to one of the supported
106
+ };
107
+
108
+ // Given a cloud identifier, try to map it to one of the supported
118
109
  // environments and return the MC API URL for that environment.
119
110
  // The URL points to the new hostnames.
120
111
  // https://docs.commercetools.com/custom-applications/concepts/merchant-center-api#hostnames
121
-
122
-
123
112
  const mapCloudIdentifierToIssuer = issuer => {
124
113
  switch (issuer) {
125
114
  case CLOUD_IDENTIFIERS.GCP_AU:
126
115
  return MC_API_URLS.GCP_AU;
127
-
128
116
  case CLOUD_IDENTIFIERS.GCP_EU:
129
117
  return MC_API_URLS.GCP_EU;
130
-
131
118
  case CLOUD_IDENTIFIERS.GCP_US:
132
119
  return MC_API_URLS.GCP_US;
133
-
134
120
  case CLOUD_IDENTIFIERS.AWS_FRA:
135
121
  return MC_API_URLS.AWS_FRA;
136
-
137
122
  case CLOUD_IDENTIFIERS.AWS_OHIO:
138
123
  return MC_API_URLS.AWS_OHIO;
139
-
140
124
  default:
141
125
  return undefined;
142
126
  }
143
- }; // Given a cloud identifier, try to map it to a legacy hostname.
127
+ };
128
+ // Given a cloud identifier, try to map it to a legacy hostname.
144
129
  // This is for backwards compatibility.
145
-
146
-
147
130
  const mapToLegacyIssuer = cloudIdentifier => {
148
131
  switch (cloudIdentifier) {
149
132
  case CLOUD_IDENTIFIERS.GCP_EU:
150
133
  return 'https://mc-api.commercetools.com';
151
-
152
134
  case CLOUD_IDENTIFIERS.GCP_US:
153
135
  return 'https://mc-api.commercetools.co';
154
-
155
136
  default:
156
137
  return undefined;
157
138
  }
158
- }; // Verifies that the issuer is a valid URL.
159
-
160
-
139
+ };
140
+ // Verifies that the issuer is a valid URL.
161
141
  const throwIfIssuerIsNotAValidUrl = issuer => {
162
142
  try {
163
143
  new _URL__default["default"](issuer);
164
144
  } catch (error) {
165
145
  throw new Error("Invalid issuer URL \"".concat(issuer, "\". Expected a valid URL to the Merchant Center API Gateway, or a cloud identifier to one of the available cloud regions. See https://docs.commercetools.com/custom-applications/concepts/merchant-center-api#hostnames."));
166
146
  }
167
- }; // Validates required option values.
168
-
169
-
147
+ };
148
+ // Validates required option values.
170
149
  const validateRequiredValues = options => {
171
150
  if (!options.audience) {
172
151
  throw new Error("Missing required option \"audience\"");
173
152
  }
174
-
175
153
  if (!options.issuer) {
176
154
  throw new Error("Missing required option \"issuer\"");
177
155
  }
178
- }; // Attempt to parse the given issuer. If the value is a cloud identifier, it will
156
+ };
157
+ // Attempt to parse the given issuer. If the value is a cloud identifier, it will
179
158
  // be mapped to one of the supported values. If not, we assume the value is a valid URL.
180
-
181
-
182
159
  const getConfiguredDefaultIssuer = options => {
183
160
  const issuer = mapCloudIdentifierToIssuer(options.issuer);
184
-
185
161
  if (!issuer) {
186
162
  throwIfIssuerIsNotAValidUrl(options.issuer);
187
163
  return options.issuer;
188
164
  }
189
-
190
165
  return issuer;
191
- }; // Construct the audience from the given option + the request path.
166
+ };
167
+
168
+ // Construct the audience from the given option + the request path.
192
169
  // If the request path is `/`, do not append it to the audience, otherwise
193
170
  // the token validation might fail because of mismatching audiences.
194
-
195
-
196
171
  const getConfiguredAudience = (options, requestPath) => {
197
172
  var _context;
198
-
199
173
  // remove the trailing slash
200
174
  const url = new _URL__default["default"](_concatInstanceProperty__default["default"](_context = "".concat(options.audience.replace(/\/?$/, ''))).call(_context, requestPath));
201
-
202
175
  switch (options.audiencePolicy) {
203
176
  case 'forward-url-origin':
204
177
  return url.origin;
205
-
206
178
  default:
207
179
  {
208
180
  var _context2;
209
-
210
181
  if (requestPath === '/') {
211
182
  return url.origin;
212
183
  }
213
-
214
184
  return _concatInstanceProperty__default["default"](_context2 = "".concat(url.origin)).call(_context2, url.pathname);
215
185
  }
216
186
  }
217
187
  };
218
-
219
188
  function createSessionAuthVerifier(options) {
220
189
  validateRequiredValues(options);
221
- const configuredDefaultIssuer = getConfiguredDefaultIssuer(options); // Returns an async HTTP handler.
190
+ const configuredDefaultIssuer = getConfiguredDefaultIssuer(options);
222
191
 
192
+ // Returns an async HTTP handler.
223
193
  return async (request, response) => {
224
194
  var _mapCloudIdentifierTo, _request$originalUrl;
225
-
226
195
  // Get the cloud identifier header, forwarded by the `/proxy/forward-to` endpoint.
227
196
  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.
197
+ let issuer = options.inferIssuer && cloudIdentifierHeader ? (_mapCloudIdentifierTo = mapCloudIdentifierToIssuer(cloudIdentifierHeader)) !== null && _mapCloudIdentifierTo !== void 0 ? _mapCloudIdentifierTo : configuredDefaultIssuer : configuredDefaultIssuer;
230
198
 
199
+ // Get the `Accept-version` header, forwarded by the `/proxy/forward-to` endpoint.
200
+ // The version should be sent by the client making the request, to use the features of v2.
231
201
  const proxyForwardVersion = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.FORWARD_TO_VERSION, "Missing \"X-MC-API-Forward-To-Version\" header.");
232
-
233
202
  if (proxyForwardVersion === 'v1') {
234
203
  var _mapToLegacyIssuer;
235
-
236
204
  // Fall back to legacy issuer domains
237
205
  issuer = (_mapToLegacyIssuer = mapToLegacyIssuer(cloudIdentifierHeader)) !== null && _mapToLegacyIssuer !== void 0 ? _mapToLegacyIssuer : issuer;
238
206
  }
239
-
240
207
  const requestUrlPath = options.getRequestUrl ? options.getRequestUrl(request) : (_request$originalUrl = request.originalUrl) !== null && _request$originalUrl !== void 0 ? _request$originalUrl : request.url;
241
-
242
208
  if (!requestUrlPath || !_startsWithInstanceProperty__default["default"](requestUrlPath).call(requestUrlPath, '/')) {
243
209
  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
210
  }
245
-
246
211
  const audience = getConfiguredAudience(options, requestUrlPath);
247
212
  return new _Promise__default["default"]((resolve, reject) => {
248
213
  expressJwt.expressjwt({
@@ -261,8 +226,8 @@ function createSessionAuthVerifier(options) {
261
226
  // Validate the audience and the issuer.
262
227
  audience,
263
228
  issuer,
264
- algorithms: ['RS256'] // @ts-ignore: the middleware expects an Express.js Request/Response objects
265
-
229
+ algorithms: ['RS256']
230
+ // @ts-ignore: the middleware expects an Express.js Request/Response objects
266
231
  })(request, response !== null && response !== void 0 ? response : {}, error => {
267
232
  if (error) {
268
233
  reject(error);
@@ -62,42 +62,32 @@ const MC_API_PROXY_HEADERS = {
62
62
 
63
63
  const getHeaderByCaseInsensitiveKey = (headers, headerKey) => {
64
64
  var _context;
65
-
66
65
  const matchingHeader = _findInstanceProperty__default["default"](_context = _Object$entries__default["default"](headers)).call(_context, _ref => {
67
66
  let _ref2 = _slicedToArray(_ref, 1),
68
- key = _ref2[0];
69
-
67
+ key = _ref2[0];
70
68
  return headerKey.toLowerCase() === key.toLowerCase();
71
69
  });
72
-
73
70
  if (matchingHeader && matchingHeader.length > 0) {
74
71
  const _matchingHeader = _slicedToArray(matchingHeader, 2),
75
- headerValue = _matchingHeader[1];
76
-
72
+ headerValue = _matchingHeader[1];
77
73
  return _Array$isArray__default["default"](headerValue) ? headerValue[0] : headerValue;
78
74
  }
79
-
80
75
  return undefined;
81
76
  };
82
-
83
77
  const getFirstHeaderValueOrThrow = (headers, headerKey, errorMessage) => {
84
78
  const headerValue = getHeaderByCaseInsensitiveKey(headers, headerKey);
85
-
86
79
  if (!headerValue) {
87
80
  throw new Error(errorMessage);
88
81
  }
89
-
90
82
  return headerValue;
91
83
  };
92
84
 
93
85
  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; }
94
-
95
86
  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.
97
-
87
+ const decodedTokenKey = 'decoded_token';
88
+ // Assign a session object to the request object.
98
89
  const writeSessionContext = request => {
99
90
  const decodedToken = request[decodedTokenKey];
100
-
101
91
  if (decodedToken) {
102
92
  const publicClaimForProjectKey = "".concat(decodedToken.iss, "/claims/project_key");
103
93
  const publicClaimForUserPermissionsKey = "".concat(decodedToken.iss, "/claims/user_permissions");
@@ -106,143 +96,118 @@ const writeSessionContext = request => {
106
96
  projectKey: decodedToken[publicClaimForProjectKey]
107
97
  };
108
98
  const userPermissions = decodedToken[publicClaimForUserPermissionsKey];
109
-
110
99
  if (Boolean(userPermissions === null || userPermissions === void 0 ? void 0 : userPermissions.length)) {
111
100
  request.session.userPermissions = userPermissions;
112
101
  }
113
- } // Remove the field used by the JWT middleware.
114
-
102
+ }
115
103
 
104
+ // Remove the field used by the JWT middleware.
116
105
  delete request.decoded_token;
117
- }; // Given a cloud identifier, try to map it to one of the supported
106
+ };
107
+
108
+ // Given a cloud identifier, try to map it to one of the supported
118
109
  // environments and return the MC API URL for that environment.
119
110
  // The URL points to the new hostnames.
120
111
  // https://docs.commercetools.com/custom-applications/concepts/merchant-center-api#hostnames
121
-
122
-
123
112
  const mapCloudIdentifierToIssuer = issuer => {
124
113
  switch (issuer) {
125
114
  case CLOUD_IDENTIFIERS.GCP_AU:
126
115
  return MC_API_URLS.GCP_AU;
127
-
128
116
  case CLOUD_IDENTIFIERS.GCP_EU:
129
117
  return MC_API_URLS.GCP_EU;
130
-
131
118
  case CLOUD_IDENTIFIERS.GCP_US:
132
119
  return MC_API_URLS.GCP_US;
133
-
134
120
  case CLOUD_IDENTIFIERS.AWS_FRA:
135
121
  return MC_API_URLS.AWS_FRA;
136
-
137
122
  case CLOUD_IDENTIFIERS.AWS_OHIO:
138
123
  return MC_API_URLS.AWS_OHIO;
139
-
140
124
  default:
141
125
  return undefined;
142
126
  }
143
- }; // Given a cloud identifier, try to map it to a legacy hostname.
127
+ };
128
+ // Given a cloud identifier, try to map it to a legacy hostname.
144
129
  // This is for backwards compatibility.
145
-
146
-
147
130
  const mapToLegacyIssuer = cloudIdentifier => {
148
131
  switch (cloudIdentifier) {
149
132
  case CLOUD_IDENTIFIERS.GCP_EU:
150
133
  return 'https://mc-api.commercetools.com';
151
-
152
134
  case CLOUD_IDENTIFIERS.GCP_US:
153
135
  return 'https://mc-api.commercetools.co';
154
-
155
136
  default:
156
137
  return undefined;
157
138
  }
158
- }; // Verifies that the issuer is a valid URL.
159
-
160
-
139
+ };
140
+ // Verifies that the issuer is a valid URL.
161
141
  const throwIfIssuerIsNotAValidUrl = issuer => {
162
142
  try {
163
143
  new _URL__default["default"](issuer);
164
144
  } catch (error) {
165
145
  throw new Error("Invalid issuer URL \"".concat(issuer, "\". Expected a valid URL to the Merchant Center API Gateway, or a cloud identifier to one of the available cloud regions. See https://docs.commercetools.com/custom-applications/concepts/merchant-center-api#hostnames."));
166
146
  }
167
- }; // Validates required option values.
168
-
169
-
147
+ };
148
+ // Validates required option values.
170
149
  const validateRequiredValues = options => {
171
150
  if (!options.audience) {
172
151
  throw new Error("Missing required option \"audience\"");
173
152
  }
174
-
175
153
  if (!options.issuer) {
176
154
  throw new Error("Missing required option \"issuer\"");
177
155
  }
178
- }; // Attempt to parse the given issuer. If the value is a cloud identifier, it will
156
+ };
157
+ // Attempt to parse the given issuer. If the value is a cloud identifier, it will
179
158
  // be mapped to one of the supported values. If not, we assume the value is a valid URL.
180
-
181
-
182
159
  const getConfiguredDefaultIssuer = options => {
183
160
  const issuer = mapCloudIdentifierToIssuer(options.issuer);
184
-
185
161
  if (!issuer) {
186
162
  throwIfIssuerIsNotAValidUrl(options.issuer);
187
163
  return options.issuer;
188
164
  }
189
-
190
165
  return issuer;
191
- }; // Construct the audience from the given option + the request path.
166
+ };
167
+
168
+ // Construct the audience from the given option + the request path.
192
169
  // If the request path is `/`, do not append it to the audience, otherwise
193
170
  // the token validation might fail because of mismatching audiences.
194
-
195
-
196
171
  const getConfiguredAudience = (options, requestPath) => {
197
172
  var _context;
198
-
199
173
  // remove the trailing slash
200
174
  const url = new _URL__default["default"](_concatInstanceProperty__default["default"](_context = "".concat(options.audience.replace(/\/?$/, ''))).call(_context, requestPath));
201
-
202
175
  switch (options.audiencePolicy) {
203
176
  case 'forward-url-origin':
204
177
  return url.origin;
205
-
206
178
  default:
207
179
  {
208
180
  var _context2;
209
-
210
181
  if (requestPath === '/') {
211
182
  return url.origin;
212
183
  }
213
-
214
184
  return _concatInstanceProperty__default["default"](_context2 = "".concat(url.origin)).call(_context2, url.pathname);
215
185
  }
216
186
  }
217
187
  };
218
-
219
188
  function createSessionAuthVerifier(options) {
220
189
  validateRequiredValues(options);
221
- const configuredDefaultIssuer = getConfiguredDefaultIssuer(options); // Returns an async HTTP handler.
190
+ const configuredDefaultIssuer = getConfiguredDefaultIssuer(options);
222
191
 
192
+ // Returns an async HTTP handler.
223
193
  return async (request, response) => {
224
194
  var _mapCloudIdentifierTo, _request$originalUrl;
225
-
226
195
  // Get the cloud identifier header, forwarded by the `/proxy/forward-to` endpoint.
227
196
  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.
197
+ let issuer = options.inferIssuer && cloudIdentifierHeader ? (_mapCloudIdentifierTo = mapCloudIdentifierToIssuer(cloudIdentifierHeader)) !== null && _mapCloudIdentifierTo !== void 0 ? _mapCloudIdentifierTo : configuredDefaultIssuer : configuredDefaultIssuer;
230
198
 
199
+ // Get the `Accept-version` header, forwarded by the `/proxy/forward-to` endpoint.
200
+ // The version should be sent by the client making the request, to use the features of v2.
231
201
  const proxyForwardVersion = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.FORWARD_TO_VERSION, "Missing \"X-MC-API-Forward-To-Version\" header.");
232
-
233
202
  if (proxyForwardVersion === 'v1') {
234
203
  var _mapToLegacyIssuer;
235
-
236
204
  // Fall back to legacy issuer domains
237
205
  issuer = (_mapToLegacyIssuer = mapToLegacyIssuer(cloudIdentifierHeader)) !== null && _mapToLegacyIssuer !== void 0 ? _mapToLegacyIssuer : issuer;
238
206
  }
239
-
240
207
  const requestUrlPath = options.getRequestUrl ? options.getRequestUrl(request) : (_request$originalUrl = request.originalUrl) !== null && _request$originalUrl !== void 0 ? _request$originalUrl : request.url;
241
-
242
208
  if (!requestUrlPath || !_startsWithInstanceProperty__default["default"](requestUrlPath).call(requestUrlPath, '/')) {
243
209
  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
210
  }
245
-
246
211
  const audience = getConfiguredAudience(options, requestUrlPath);
247
212
  return new _Promise__default["default"]((resolve, reject) => {
248
213
  expressJwt.expressjwt({
@@ -261,8 +226,8 @@ function createSessionAuthVerifier(options) {
261
226
  // Validate the audience and the issuer.
262
227
  audience,
263
228
  issuer,
264
- algorithms: ['RS256'] // @ts-ignore: the middleware expects an Express.js Request/Response objects
265
-
229
+ algorithms: ['RS256']
230
+ // @ts-ignore: the middleware expects an Express.js Request/Response objects
266
231
  })(request, response !== null && response !== void 0 ? response : {}, error => {
267
232
  if (error) {
268
233
  reject(error);
@@ -39,42 +39,32 @@ const MC_API_PROXY_HEADERS = {
39
39
 
40
40
  const getHeaderByCaseInsensitiveKey = (headers, headerKey) => {
41
41
  var _context;
42
-
43
42
  const matchingHeader = _findInstanceProperty(_context = _Object$entries(headers)).call(_context, _ref => {
44
43
  let _ref2 = _slicedToArray(_ref, 1),
45
- key = _ref2[0];
46
-
44
+ key = _ref2[0];
47
45
  return headerKey.toLowerCase() === key.toLowerCase();
48
46
  });
49
-
50
47
  if (matchingHeader && matchingHeader.length > 0) {
51
48
  const _matchingHeader = _slicedToArray(matchingHeader, 2),
52
- headerValue = _matchingHeader[1];
53
-
49
+ headerValue = _matchingHeader[1];
54
50
  return _Array$isArray(headerValue) ? headerValue[0] : headerValue;
55
51
  }
56
-
57
52
  return undefined;
58
53
  };
59
-
60
54
  const getFirstHeaderValueOrThrow = (headers, headerKey, errorMessage) => {
61
55
  const headerValue = getHeaderByCaseInsensitiveKey(headers, headerKey);
62
-
63
56
  if (!headerValue) {
64
57
  throw new Error(errorMessage);
65
58
  }
66
-
67
59
  return headerValue;
68
60
  };
69
61
 
70
62
  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; }
71
-
72
63
  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.
74
-
64
+ const decodedTokenKey = 'decoded_token';
65
+ // Assign a session object to the request object.
75
66
  const writeSessionContext = request => {
76
67
  const decodedToken = request[decodedTokenKey];
77
-
78
68
  if (decodedToken) {
79
69
  const publicClaimForProjectKey = "".concat(decodedToken.iss, "/claims/project_key");
80
70
  const publicClaimForUserPermissionsKey = "".concat(decodedToken.iss, "/claims/user_permissions");
@@ -83,143 +73,118 @@ const writeSessionContext = request => {
83
73
  projectKey: decodedToken[publicClaimForProjectKey]
84
74
  };
85
75
  const userPermissions = decodedToken[publicClaimForUserPermissionsKey];
86
-
87
76
  if (Boolean(userPermissions === null || userPermissions === void 0 ? void 0 : userPermissions.length)) {
88
77
  request.session.userPermissions = userPermissions;
89
78
  }
90
- } // Remove the field used by the JWT middleware.
91
-
79
+ }
92
80
 
81
+ // Remove the field used by the JWT middleware.
93
82
  delete request.decoded_token;
94
- }; // Given a cloud identifier, try to map it to one of the supported
83
+ };
84
+
85
+ // Given a cloud identifier, try to map it to one of the supported
95
86
  // environments and return the MC API URL for that environment.
96
87
  // The URL points to the new hostnames.
97
88
  // https://docs.commercetools.com/custom-applications/concepts/merchant-center-api#hostnames
98
-
99
-
100
89
  const mapCloudIdentifierToIssuer = issuer => {
101
90
  switch (issuer) {
102
91
  case CLOUD_IDENTIFIERS.GCP_AU:
103
92
  return MC_API_URLS.GCP_AU;
104
-
105
93
  case CLOUD_IDENTIFIERS.GCP_EU:
106
94
  return MC_API_URLS.GCP_EU;
107
-
108
95
  case CLOUD_IDENTIFIERS.GCP_US:
109
96
  return MC_API_URLS.GCP_US;
110
-
111
97
  case CLOUD_IDENTIFIERS.AWS_FRA:
112
98
  return MC_API_URLS.AWS_FRA;
113
-
114
99
  case CLOUD_IDENTIFIERS.AWS_OHIO:
115
100
  return MC_API_URLS.AWS_OHIO;
116
-
117
101
  default:
118
102
  return undefined;
119
103
  }
120
- }; // Given a cloud identifier, try to map it to a legacy hostname.
104
+ };
105
+ // Given a cloud identifier, try to map it to a legacy hostname.
121
106
  // This is for backwards compatibility.
122
-
123
-
124
107
  const mapToLegacyIssuer = cloudIdentifier => {
125
108
  switch (cloudIdentifier) {
126
109
  case CLOUD_IDENTIFIERS.GCP_EU:
127
110
  return 'https://mc-api.commercetools.com';
128
-
129
111
  case CLOUD_IDENTIFIERS.GCP_US:
130
112
  return 'https://mc-api.commercetools.co';
131
-
132
113
  default:
133
114
  return undefined;
134
115
  }
135
- }; // Verifies that the issuer is a valid URL.
136
-
137
-
116
+ };
117
+ // Verifies that the issuer is a valid URL.
138
118
  const throwIfIssuerIsNotAValidUrl = issuer => {
139
119
  try {
140
120
  new _URL(issuer);
141
121
  } catch (error) {
142
122
  throw new Error("Invalid issuer URL \"".concat(issuer, "\". Expected a valid URL to the Merchant Center API Gateway, or a cloud identifier to one of the available cloud regions. See https://docs.commercetools.com/custom-applications/concepts/merchant-center-api#hostnames."));
143
123
  }
144
- }; // Validates required option values.
145
-
146
-
124
+ };
125
+ // Validates required option values.
147
126
  const validateRequiredValues = options => {
148
127
  if (!options.audience) {
149
128
  throw new Error("Missing required option \"audience\"");
150
129
  }
151
-
152
130
  if (!options.issuer) {
153
131
  throw new Error("Missing required option \"issuer\"");
154
132
  }
155
- }; // Attempt to parse the given issuer. If the value is a cloud identifier, it will
133
+ };
134
+ // Attempt to parse the given issuer. If the value is a cloud identifier, it will
156
135
  // be mapped to one of the supported values. If not, we assume the value is a valid URL.
157
-
158
-
159
136
  const getConfiguredDefaultIssuer = options => {
160
137
  const issuer = mapCloudIdentifierToIssuer(options.issuer);
161
-
162
138
  if (!issuer) {
163
139
  throwIfIssuerIsNotAValidUrl(options.issuer);
164
140
  return options.issuer;
165
141
  }
166
-
167
142
  return issuer;
168
- }; // Construct the audience from the given option + the request path.
143
+ };
144
+
145
+ // Construct the audience from the given option + the request path.
169
146
  // If the request path is `/`, do not append it to the audience, otherwise
170
147
  // the token validation might fail because of mismatching audiences.
171
-
172
-
173
148
  const getConfiguredAudience = (options, requestPath) => {
174
149
  var _context;
175
-
176
150
  // remove the trailing slash
177
151
  const url = new _URL(_concatInstanceProperty(_context = "".concat(options.audience.replace(/\/?$/, ''))).call(_context, requestPath));
178
-
179
152
  switch (options.audiencePolicy) {
180
153
  case 'forward-url-origin':
181
154
  return url.origin;
182
-
183
155
  default:
184
156
  {
185
157
  var _context2;
186
-
187
158
  if (requestPath === '/') {
188
159
  return url.origin;
189
160
  }
190
-
191
161
  return _concatInstanceProperty(_context2 = "".concat(url.origin)).call(_context2, url.pathname);
192
162
  }
193
163
  }
194
164
  };
195
-
196
165
  function createSessionAuthVerifier(options) {
197
166
  validateRequiredValues(options);
198
- const configuredDefaultIssuer = getConfiguredDefaultIssuer(options); // Returns an async HTTP handler.
167
+ const configuredDefaultIssuer = getConfiguredDefaultIssuer(options);
199
168
 
169
+ // Returns an async HTTP handler.
200
170
  return async (request, response) => {
201
171
  var _mapCloudIdentifierTo, _request$originalUrl;
202
-
203
172
  // Get the cloud identifier header, forwarded by the `/proxy/forward-to` endpoint.
204
173
  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.
174
+ let issuer = options.inferIssuer && cloudIdentifierHeader ? (_mapCloudIdentifierTo = mapCloudIdentifierToIssuer(cloudIdentifierHeader)) !== null && _mapCloudIdentifierTo !== void 0 ? _mapCloudIdentifierTo : configuredDefaultIssuer : configuredDefaultIssuer;
207
175
 
176
+ // Get the `Accept-version` header, forwarded by the `/proxy/forward-to` endpoint.
177
+ // The version should be sent by the client making the request, to use the features of v2.
208
178
  const proxyForwardVersion = getFirstHeaderValueOrThrow(request.headers, MC_API_PROXY_HEADERS.FORWARD_TO_VERSION, "Missing \"X-MC-API-Forward-To-Version\" header.");
209
-
210
179
  if (proxyForwardVersion === 'v1') {
211
180
  var _mapToLegacyIssuer;
212
-
213
181
  // Fall back to legacy issuer domains
214
182
  issuer = (_mapToLegacyIssuer = mapToLegacyIssuer(cloudIdentifierHeader)) !== null && _mapToLegacyIssuer !== void 0 ? _mapToLegacyIssuer : issuer;
215
183
  }
216
-
217
184
  const requestUrlPath = options.getRequestUrl ? options.getRequestUrl(request) : (_request$originalUrl = request.originalUrl) !== null && _request$originalUrl !== void 0 ? _request$originalUrl : request.url;
218
-
219
185
  if (!requestUrlPath || !_startsWithInstanceProperty(requestUrlPath).call(requestUrlPath, '/')) {
220
186
  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
187
  }
222
-
223
188
  const audience = getConfiguredAudience(options, requestUrlPath);
224
189
  return new _Promise((resolve, reject) => {
225
190
  expressjwt({
@@ -238,8 +203,8 @@ function createSessionAuthVerifier(options) {
238
203
  // Validate the audience and the issuer.
239
204
  audience,
240
205
  issuer,
241
- algorithms: ['RS256'] // @ts-ignore: the middleware expects an Express.js Request/Response objects
242
-
206
+ algorithms: ['RS256']
207
+ // @ts-ignore: the middleware expects an Express.js Request/Response objects
243
208
  })(request, response !== null && response !== void 0 ? response : {}, error => {
244
209
  if (error) {
245
210
  reject(error);
@@ -4,10 +4,10 @@ type TDecodedJWT = {
4
4
  iss: string;
5
5
  [property: string]: string | string[];
6
6
  };
7
- declare const writeSessionContext: <Request_1 extends TBaseRequest>(request: Request_1 & {
7
+ declare const writeSessionContext: <Request extends TBaseRequest>(request: Request & {
8
8
  decoded_token?: TDecodedJWT | undefined;
9
9
  session?: TSession | undefined;
10
10
  }) => void;
11
- export declare const getConfiguredAudience: <Request_1 extends TBaseRequest>(options: TSessionMiddlewareOptions<Request_1>, requestPath: string) => string;
11
+ export declare const getConfiguredAudience: <Request extends TBaseRequest>(options: TSessionMiddlewareOptions<Request>, requestPath: string) => string;
12
12
  declare function createSessionAuthVerifier<Request extends TBaseRequest>(options: TSessionMiddlewareOptions<Request>): (request: Request, response?: unknown) => Promise<void>;
13
13
  export { createSessionAuthVerifier, writeSessionContext };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commercetools-backend/express",
3
- "version": "22.2.1",
3
+ "version": "22.3.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": {
@@ -9,17 +9,30 @@
9
9
  "directory": "packages-backend/express"
10
10
  },
11
11
  "homepage": "https://docs.commercetools.com/custom-applications",
12
- "keywords": ["javascript", "nodejs", "express", "http", "server", "toolkit"],
12
+ "keywords": [
13
+ "javascript",
14
+ "nodejs",
15
+ "express",
16
+ "http",
17
+ "server",
18
+ "toolkit"
19
+ ],
13
20
  "license": "MIT",
14
21
  "publishConfig": {
15
22
  "access": "public"
16
23
  },
17
24
  "main": "dist/commercetools-backend-express.cjs.js",
18
25
  "module": "dist/commercetools-backend-express.esm.js",
19
- "files": ["dist", "package.json", "LICENSE", "README.md"],
26
+ "files": [
27
+ "dist",
28
+ "package.json",
29
+ "LICENSE",
30
+ "README.md"
31
+ ],
20
32
  "dependencies": {
21
33
  "@babel/runtime": "^7.20.13",
22
34
  "@babel/runtime-corejs3": "^7.20.13",
35
+ "@types/express": "^4.17.17",
23
36
  "@types/node": "^18.15.11",
24
37
  "express": "4.18.2",
25
38
  "express-jwt": "8.4.1",
@@ -32,4 +45,4 @@
32
45
  "jose": "2.0.6",
33
46
  "msw": "0.49.3"
34
47
  }
35
- }
48
+ }