@sap-ux/backend-proxy-middleware 0.10.1 → 0.10.3

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.
@@ -1,13 +1,14 @@
1
- import type { ServerOptions } from 'http-proxy';
2
- import type { RequestHandler, Options } from 'http-proxy-middleware';
3
- import type { ClientRequest, IncomingMessage, ServerResponse } from 'http';
4
1
  import { ToolsLogger, type Logger } from '@sap-ux/logger';
2
+ import type { ClientRequest, IncomingMessage, ServerResponse } from 'http';
3
+ import type { ServerOptions } from 'http-proxy';
4
+ import type { Options, RequestHandler } from 'http-proxy-middleware';
5
5
  import type { BackendConfig, DestinationBackendConfig } from './types';
6
6
  import type { BackendSystem } from '@sap-ux/store';
7
- import type { Url } from 'node:url';
8
- import type { Socket } from 'node:net';
9
- import type { Request } from 'express';
7
+ import { AuthenticationType } from '@sap-ux/store';
10
8
  import type connect from 'connect';
9
+ import type { Request } from 'express';
10
+ import type { Socket } from 'node:net';
11
+ import type { Url } from 'node:url';
11
12
  export type EnhancedIncomingMessage = (IncomingMessage & Pick<Request, 'originalUrl'>) | connect.IncomingMessage;
12
13
  /**
13
14
  * Collection of custom event handler for the proxy.
@@ -50,6 +51,13 @@ export declare function proxyErrorHandler(err: Error & {
50
51
  * Collection of path rewrite functions.
51
52
  */
52
53
  export declare const PathRewriters: {
54
+ /**
55
+ * Generates a rewrite function that replaces the matched string with '/manifest.json'.
56
+ *
57
+ * @param bspPath the bsp path from the yaml config
58
+ * @returns a path rewrite function
59
+ */
60
+ convertAppDescriptorToManifest(bspPath: string): (path: string) => string;
53
61
  /**
54
62
  * Generates a rewrite function that replaces the matched string with the prefix in the given string.
55
63
  *
@@ -59,7 +67,7 @@ export declare const PathRewriters: {
59
67
  */
60
68
  replacePrefix(match: string, prefix: string): (path: string) => string;
61
69
  /**
62
- * Add or replace the sap-client url parameter if missing or inocrrect in the original request path.
70
+ * Add or replace the sap-client url parameter if missing or incorrect in the original request path.
63
71
  *
64
72
  * @param client sap-client as string
65
73
  * @returns a path rewrite function
@@ -82,7 +90,7 @@ export declare function initI18n(): Promise<void>;
82
90
  * Enhance the proxy options and backend configurations for the usage of destinations in SAP Business Application Studio.
83
91
  *
84
92
  * @param proxyOptions reference to a proxy options object that the function will enhance
85
- * @param backend reference to the backend configuration that the the function may enhance
93
+ * @param backend reference to the backend configuration that the function may enhance
86
94
  */
87
95
  export declare function enhanceConfigsForDestination(proxyOptions: Options & {
88
96
  headers: object;
@@ -92,12 +100,12 @@ export declare function enhanceConfigsForDestination(proxyOptions: Options & {
92
100
  *
93
101
  * @param proxyOptions reference to a proxy options object that the function will enhance
94
102
  * @param system backend system information (most likely) read from the store
95
- * @param oAuthRequired if true then the OAuth flow is triggered to get cookies
103
+ * @param authType determines the authentication protocol to be used
96
104
  * @param tokenChangedCallback function to call if a new refreshToken is available
97
105
  */
98
106
  export declare function enhanceConfigForSystem(proxyOptions: Options & {
99
107
  headers: object;
100
- }, system: BackendSystem | undefined, oAuthRequired: boolean | undefined, tokenChangedCallback: (refreshToken?: string) => void): Promise<void>;
108
+ }, system: BackendSystem | undefined, authType: AuthenticationType, tokenChangedCallback: (refreshToken?: string) => void): Promise<void>;
101
109
  /**
102
110
  * Generate options for the proxy middleware based on the input.
103
111
  *
@@ -10,17 +10,17 @@ exports.enhanceConfigsForDestination = enhanceConfigsForDestination;
10
10
  exports.enhanceConfigForSystem = enhanceConfigForSystem;
11
11
  exports.generateProxyMiddlewareOptions = generateProxyMiddlewareOptions;
12
12
  exports.createProxy = createProxy;
13
- const https_proxy_agent_1 = require("https-proxy-agent");
14
- const http_proxy_middleware_1 = require("http-proxy-middleware");
15
- const i18next_1 = __importDefault(require("i18next"));
16
- const logger_1 = require("@sap-ux/logger");
17
13
  const axios_extension_1 = require("@sap-ux/axios-extension");
18
14
  const btp_utils_1 = require("@sap-ux/btp-utils");
15
+ const logger_1 = require("@sap-ux/logger");
16
+ const http_proxy_middleware_1 = require("http-proxy-middleware");
17
+ const https_proxy_agent_1 = require("https-proxy-agent");
18
+ const i18next_1 = __importDefault(require("i18next"));
19
19
  const i18n_json_1 = __importDefault(require("./i18n.json"));
20
20
  const store_1 = require("@sap-ux/store");
21
- const config_1 = require("./config");
22
- const bsp_1 = require("../ext/bsp");
23
21
  const proxy_from_env_1 = require("proxy-from-env");
22
+ const bsp_1 = require("../ext/bsp");
23
+ const config_1 = require("./config");
24
24
  /**
25
25
  * Collection of custom event handler for the proxy.
26
26
  */
@@ -107,6 +107,16 @@ async function getApiHubKey(logger) {
107
107
  * Collection of path rewrite functions.
108
108
  */
109
109
  exports.PathRewriters = {
110
+ /**
111
+ * Generates a rewrite function that replaces the matched string with '/manifest.json'.
112
+ *
113
+ * @param bspPath the bsp path from the yaml config
114
+ * @returns a path rewrite function
115
+ */
116
+ convertAppDescriptorToManifest(bspPath) {
117
+ const regex = new RegExp('(' + bspPath + '/manifest\\.appdescr\\b)');
118
+ return (path) => (path.match(regex) ? '/manifest.json' : path);
119
+ },
110
120
  /**
111
121
  * Generates a rewrite function that replaces the matched string with the prefix in the given string.
112
122
  *
@@ -118,7 +128,7 @@ exports.PathRewriters = {
118
128
  return (path) => path.replace(match, prefix.replace(/\/$/, ''));
119
129
  },
120
130
  /**
121
- * Add or replace the sap-client url parameter if missing or inocrrect in the original request path.
131
+ * Add or replace the sap-client url parameter if missing or incorrect in the original request path.
122
132
  *
123
133
  * @param client sap-client as string
124
134
  * @returns a path rewrite function
@@ -154,6 +164,9 @@ exports.PathRewriters = {
154
164
  if (config.client) {
155
165
  functions.push(exports.PathRewriters.replaceClient(config.client));
156
166
  }
167
+ if (config.bsp) {
168
+ functions.push(exports.PathRewriters.convertAppDescriptorToManifest(config.bsp));
169
+ }
157
170
  if (functions.length > 0) {
158
171
  return (path, req) => {
159
172
  let newPath = path;
@@ -199,7 +212,7 @@ async function initI18n() {
199
212
  * Enhance the proxy options and backend configurations for the usage of destinations in SAP Business Application Studio.
200
213
  *
201
214
  * @param proxyOptions reference to a proxy options object that the function will enhance
202
- * @param backend reference to the backend configuration that the the function may enhance
215
+ * @param backend reference to the backend configuration that the function may enhance
203
216
  */
204
217
  async function enhanceConfigsForDestination(proxyOptions, backend) {
205
218
  proxyOptions.target = (0, btp_utils_1.getDestinationUrlForAppStudio)(backend.destination);
@@ -226,11 +239,11 @@ async function enhanceConfigsForDestination(proxyOptions, backend) {
226
239
  *
227
240
  * @param proxyOptions reference to a proxy options object that the function will enhance
228
241
  * @param system backend system information (most likely) read from the store
229
- * @param oAuthRequired if true then the OAuth flow is triggered to get cookies
242
+ * @param authType determines the authentication protocol to be used
230
243
  * @param tokenChangedCallback function to call if a new refreshToken is available
231
244
  */
232
- async function enhanceConfigForSystem(proxyOptions, system, oAuthRequired, tokenChangedCallback) {
233
- if (oAuthRequired) {
245
+ async function enhanceConfigForSystem(proxyOptions, system, authType, tokenChangedCallback) {
246
+ if (authType === store_1.AuthenticationType.OAuth2RefreshToken) {
234
247
  if (system?.serviceKeys) {
235
248
  const provider = (0, axios_extension_1.createForAbapOnCloud)({
236
249
  environment: axios_extension_1.AbapCloudEnvironment.Standalone,
@@ -242,10 +255,10 @@ async function enhanceConfigForSystem(proxyOptions, system, oAuthRequired, token
242
255
  await provider.getAtoInfo();
243
256
  }
244
257
  else {
245
- throw new Error('Cannot connect to ABAP Environment on BTP without service keys.');
258
+ throw new Error('Cannot connect to ABAP Environment on BTP using OAuth without service keys.');
246
259
  }
247
260
  }
248
- else if (system?.authenticationType === store_1.AuthenticationType.ReentranceTicket) {
261
+ else if (system && authType === store_1.AuthenticationType.ReentranceTicket) {
249
262
  const provider = (0, axios_extension_1.createForAbapOnCloud)({
250
263
  ignoreCertErrors: proxyOptions.secure === false,
251
264
  environment: axios_extension_1.AbapCloudEnvironment.EmbeddedSteampunk,
@@ -296,33 +309,7 @@ async function generateProxyMiddlewareOptions(backend, options = {}, logger = ne
296
309
  }
297
310
  }
298
311
  else {
299
- const localBackend = backend;
300
- // check if system credentials are stored in the store
301
- try {
302
- const systemStore = await (0, store_1.getService)({ logger, entityName: 'system' });
303
- const system = (await systemStore.read(new store_1.BackendSystemKey({ url: localBackend.url, client: localBackend.client }))) ?? {
304
- name: '<unknown>',
305
- url: localBackend.url,
306
- authenticationType: localBackend.authenticationType
307
- };
308
- await enhanceConfigForSystem(proxyOptions, system, backend.scp, (refreshToken, accessToken) => {
309
- if (refreshToken) {
310
- logger.info('Updating refresh token for: ' + localBackend.url);
311
- systemStore.write({ ...system, refreshToken }).catch((error) => logger.error(error));
312
- }
313
- if (accessToken) {
314
- logger.info('Setting access token');
315
- proxyOptions.headers['authorization'] = `bearer ${accessToken}`;
316
- }
317
- else {
318
- logger.warn('Setting of access token failed.');
319
- }
320
- });
321
- }
322
- catch (error) {
323
- logger.warn('Accessing the credentials store failed.');
324
- logger.debug(error);
325
- }
312
+ await updateProxyConfigFromStore(backend, logger, proxyOptions);
326
313
  }
327
314
  if (!proxyOptions.auth && process.env.FIORI_TOOLS_USER && process.env.FIORI_TOOLS_PASSWORD) {
328
315
  proxyOptions.auth = `${process.env.FIORI_TOOLS_USER}:${process.env.FIORI_TOOLS_PASSWORD}`;
@@ -348,6 +335,44 @@ async function generateProxyMiddlewareOptions(backend, options = {}, logger = ne
348
335
  logger.info(`Backend proxy created for ${proxyOptions.target}`);
349
336
  return proxyOptions;
350
337
  }
338
+ /**
339
+ * Determine the correct authentication configuration for connections from a non-BAS platform.
340
+ *
341
+ * @param backend the backend config loaded from the yaml config
342
+ * @param logger a logger instance
343
+ * @param proxyOptions additional proxy header, request and response settings
344
+ */
345
+ async function updateProxyConfigFromStore(backend, logger, proxyOptions) {
346
+ const localBackend = backend;
347
+ // check if system credentials are stored in the store
348
+ try {
349
+ const systemStore = await (0, store_1.getService)({ logger, entityName: 'system' });
350
+ const system = (await systemStore.read(new store_1.BackendSystemKey({ url: localBackend.url, client: localBackend.client }))) ?? {
351
+ name: '<unknown>',
352
+ url: localBackend.url,
353
+ authenticationType: localBackend.authenticationType
354
+ };
355
+ // Auth type is determined from app config as we may have multiple stored systems with the same url/client using different auth types
356
+ await enhanceConfigForSystem(proxyOptions, system, localBackend.authenticationType ??
357
+ (localBackend.scp ? store_1.AuthenticationType.OAuth2RefreshToken : store_1.AuthenticationType.Basic), (refreshToken, accessToken) => {
358
+ if (refreshToken) {
359
+ logger.info('Updating refresh token for: ' + localBackend.url);
360
+ systemStore.write({ ...system, refreshToken }).catch((error) => logger.error(error));
361
+ }
362
+ if (accessToken) {
363
+ logger.info('Setting access token');
364
+ proxyOptions.headers['authorization'] = `bearer ${accessToken}`;
365
+ }
366
+ else {
367
+ logger.warn('Setting of access token failed.');
368
+ }
369
+ });
370
+ }
371
+ catch (error) {
372
+ logger.warn('Accessing the credentials store failed.');
373
+ logger.debug(error);
374
+ }
375
+ }
351
376
  /**
352
377
  * Generate an instance of the proxy middleware based on the input.
353
378
  *
package/dist/ext/bsp.d.ts CHANGED
@@ -1,12 +1,5 @@
1
1
  import type { Options } from 'http-proxy-middleware';
2
2
  import type { Logger } from '@sap-ux/logger';
3
- /**
4
- * Replace calls to manifest.appdescr file if we are running the FLP embedded flow.
5
- *
6
- * @param bsp path of the BSP page
7
- * @returns a path rewrite function
8
- */
9
- export declare function convertAppDescriptorToManifest(bsp: string): (path: string) => string;
10
3
  /**
11
4
  * Prompts the user for credentials.
12
5
  *
package/dist/ext/bsp.js CHANGED
@@ -3,23 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.convertAppDescriptorToManifest = convertAppDescriptorToManifest;
7
6
  exports.promptUserPass = promptUserPass;
8
7
  exports.addOptionsForEmbeddedBSP = addOptionsForEmbeddedBSP;
9
8
  const chalk_1 = require("chalk");
10
9
  const i18next_1 = __importDefault(require("i18next"));
11
10
  const prompts_1 = __importDefault(require("prompts"));
12
11
  const btp_utils_1 = require("@sap-ux/btp-utils");
13
- /**
14
- * Replace calls to manifest.appdescr file if we are running the FLP embedded flow.
15
- *
16
- * @param bsp path of the BSP page
17
- * @returns a path rewrite function
18
- */
19
- function convertAppDescriptorToManifest(bsp) {
20
- const regex = new RegExp('(' + bsp + '/manifest\\.appdescr\\b)');
21
- return (path) => (path.match(regex) ? '/manifest.json' : path);
22
- }
23
12
  /**
24
13
  * Prompts the user for credentials.
25
14
  *
@@ -98,14 +87,6 @@ async function addOptionsForEmbeddedBSP(bspPath, proxyOptions, logger) {
98
87
  return undefined;
99
88
  }
100
89
  };
101
- if (proxyOptions.pathRewrite) {
102
- const oldRewrite = proxyOptions.pathRewrite;
103
- const appDescrRewrite = convertAppDescriptorToManifest(bspPath);
104
- proxyOptions.pathRewrite = (path) => appDescrRewrite(oldRewrite(path));
105
- }
106
- else {
107
- proxyOptions.pathRewrite = convertAppDescriptorToManifest(bspPath);
108
- }
109
90
  if (!proxyOptions.auth) {
110
91
  proxyOptions.auth = await promptUserPass(logger);
111
92
  }
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "bugs": {
10
10
  "url": "https://github.com/SAP/open-ux-tools/issues?q=is%3Aopen+is%3Aissue+label%3Abug+label%3Abackend-proxy-middleware"
11
11
  },
12
- "version": "0.10.1",
12
+ "version": "0.10.3",
13
13
  "license": "Apache-2.0",
14
14
  "author": "@SAP/ux-tools-team",
15
15
  "main": "dist/index.js",
@@ -28,10 +28,10 @@
28
28
  "i18next": "25.3.0",
29
29
  "prompts": "2.4.2",
30
30
  "proxy-from-env": "1.1.0",
31
- "@sap-ux/axios-extension": "1.22.10",
31
+ "@sap-ux/axios-extension": "1.23.0",
32
32
  "@sap-ux/btp-utils": "1.1.4",
33
33
  "@sap-ux/logger": "0.7.0",
34
- "@sap-ux/store": "1.1.5"
34
+ "@sap-ux/store": "1.2.0"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/express": "4.17.21",