@sap-ux/odata-service-inquirer 0.5.3 → 0.5.5

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.
@@ -21,6 +21,7 @@ type ValidationResult = string | boolean | IValidationLink;
21
21
  export declare class ConnectionValidator {
22
22
  readonly validity: Validity;
23
23
  private _validatedUrl;
24
+ private _validatedClient;
24
25
  private _odataService;
25
26
  private _serviceProvider;
26
27
  private _axiosConfig;
@@ -93,7 +94,7 @@ export declare class ConnectionValidator {
93
94
  * @param serviceUrl the odata service url to validate
94
95
  * @param options options for the connection validation
95
96
  * @param options.ignoreCertError ignore some certificate errors
96
- * @param options.forceReValidation force re-validation of the url
97
+ * @param options.forceReValidation force re-validation of the url even if the same url has been prevously validated
97
98
  * @param options.isSystem if true, the url will be treated as a system url rather than a service url
98
99
  * @param options.odataVersion if specified will restrict catalog requests to only the specified odata version
99
100
  * @returns true if the url is reachable, false if not, or an error message string
@@ -126,6 +127,16 @@ export declare class ConnectionValidator {
126
127
  * @returns true if the url has already been validated
127
128
  */
128
129
  private isUrlValidated;
130
+ /**
131
+ * Check whether basic auth is required for the given url, or for the previously validated url if none specified.
132
+ * This will also set the validity state for the url. This will not validate the URL.
133
+ *
134
+ * @param urlString - the url to validate, if not provided the previously validated url will be used
135
+ * @param client - optional, sap client code, if not provided the previously validated client will be used
136
+ * @param ignoreCertError
137
+ * @returns true if basic auth is required, false if not
138
+ */
139
+ isAuthRequired(urlString?: string | undefined, client?: string | undefined, ignoreCertError?: boolean): Promise<boolean>;
129
140
  /**
130
141
  * Test the connectivity with the specified service url using the provided credentials.
131
142
  *
@@ -22,7 +22,10 @@ const ignorableCertErrors = [error_handler_1.ERROR_TYPE.CERT_SELF_SIGNED, error_
22
22
  */
23
23
  class ConnectionValidator {
24
24
  validity = {};
25
+ // The current valid url (not necessarily authenticated but the url is in a valid format)
25
26
  _validatedUrl;
27
+ // The current client code used for requests, the client code has been validated by a successful request
28
+ _validatedClient;
26
29
  _odataService;
27
30
  _serviceProvider;
28
31
  _axiosConfig;
@@ -97,6 +100,7 @@ class ConnectionValidator {
97
100
  // Full service URL
98
101
  await this.createServiceConnection(axiosConfig, url.pathname);
99
102
  }
103
+ this._validatedClient = url.searchParams.get(types_1.SAP_CLIENT_KEY) ?? undefined;
100
104
  return 200;
101
105
  }
102
106
  catch (e) {
@@ -191,7 +195,7 @@ class ConnectionValidator {
191
195
  * @param serviceUrl the odata service url to validate
192
196
  * @param options options for the connection validation
193
197
  * @param options.ignoreCertError ignore some certificate errors
194
- * @param options.forceReValidation force re-validation of the url
198
+ * @param options.forceReValidation force re-validation of the url even if the same url has been prevously validated
195
199
  * @param options.isSystem if true, the url will be treated as a system url rather than a service url
196
200
  * @param options.odataVersion if specified will restrict catalog requests to only the specified odata version
197
201
  * @returns true if the url is reachable, false if not, or an error message string
@@ -224,7 +228,7 @@ class ConnectionValidator {
224
228
  // More helpful context specific error
225
229
  if (error_handler_1.ErrorHandler.getErrorType(error) === error_handler_1.ERROR_TYPE.CONNECTION) {
226
230
  this.validity.reachable = false;
227
- return prompt_helpers_1.errorHandler.logErrorMsgs((0, i18n_1.t)('errors.serviceUrlNotFound', { url: serviceUrl }));
231
+ return prompt_helpers_1.errorHandler.logErrorMsgs((0, i18n_1.t)('errors.systemOrserviceUrlNotFound', { url: serviceUrl }));
228
232
  }
229
233
  this.resetValidity();
230
234
  const errorMsg = prompt_helpers_1.errorHandler.getErrorMsg(error);
@@ -240,10 +244,10 @@ class ConnectionValidator {
240
244
  */
241
245
  getValidationResultFromStatusCode(status) {
242
246
  if (status === 200) {
247
+ this.validity.reachable = true;
243
248
  this.validity.authenticated = true;
244
- this.validity.authRequired = false;
245
249
  }
246
- else if (status === 404) {
250
+ else if (error_handler_1.ErrorHandler.getErrorType(status) === error_handler_1.ERROR_TYPE.NOT_FOUND) {
247
251
  this.validity.reachable = false;
248
252
  return error_handler_1.ErrorHandler.getErrorMsgFromType(error_handler_1.ERROR_TYPE.NOT_FOUND) ?? false;
249
253
  }
@@ -255,12 +259,13 @@ class ConnectionValidator {
255
259
  else if (error_handler_1.ErrorHandler.getErrorType(status) === error_handler_1.ERROR_TYPE.AUTH) {
256
260
  this.validity.reachable = true;
257
261
  this.validity.authRequired = true;
262
+ this.validity.authenticated = false;
258
263
  }
259
264
  else if (error_handler_1.ErrorHandler.getErrorType(status) === error_handler_1.ERROR_TYPE.REDIRECT) {
260
265
  this.validity.reachable = true;
261
266
  return (0, i18n_1.t)('errors.urlRedirect');
262
267
  }
263
- else if (status !== 404) {
268
+ else if (error_handler_1.ErrorHandler.getErrorType(status) === error_handler_1.ERROR_TYPE.CONNECTION) {
264
269
  this.validity.reachable = false;
265
270
  return error_handler_1.ErrorHandler.getErrorMsgFromType(error_handler_1.ERROR_TYPE.CONNECTION, `http code: ${status}`) ?? false;
266
271
  }
@@ -289,6 +294,40 @@ class ConnectionValidator {
289
294
  this.resetValidity();
290
295
  return false;
291
296
  }
297
+ /**
298
+ * Check whether basic auth is required for the given url, or for the previously validated url if none specified.
299
+ * This will also set the validity state for the url. This will not validate the URL.
300
+ *
301
+ * @param urlString - the url to validate, if not provided the previously validated url will be used
302
+ * @param client - optional, sap client code, if not provided the previously validated client will be used
303
+ * @param ignoreCertError
304
+ * @returns true if basic auth is required, false if not
305
+ */
306
+ async isAuthRequired(urlString = this._validatedUrl, client = this._validatedClient, ignoreCertError = false) {
307
+ if (!urlString) {
308
+ return false;
309
+ }
310
+ // Dont re-request if already validated
311
+ if (this._validatedUrl === urlString &&
312
+ this._validatedClient === client &&
313
+ this.validity.authRequired !== undefined) {
314
+ return this.validity.authRequired;
315
+ }
316
+ // New URL or client so we need to re-request
317
+ try {
318
+ const url = new URL(urlString);
319
+ if (client) {
320
+ url.searchParams.append(types_1.SAP_CLIENT_KEY, client);
321
+ }
322
+ this.validity.authRequired = this.validity.reachable =
323
+ error_handler_1.ErrorHandler.getErrorType(await this.checkSapService(url, undefined, undefined, { ignoreCertError })) === error_handler_1.ERROR_TYPE.AUTH;
324
+ return this.validity.authRequired;
325
+ }
326
+ catch (error) {
327
+ prompt_helpers_1.errorHandler.logErrorMsgs(error);
328
+ return false; // Cannot determine if auth required
329
+ }
330
+ }
292
331
  /**
293
332
  * Test the connectivity with the specified service url using the provided credentials.
294
333
  *
@@ -316,9 +355,18 @@ class ConnectionValidator {
316
355
  isSystem,
317
356
  odataVersion
318
357
  });
358
+ logger_helper_1.default.logger.debug(`ConnectionValidator.validateUrl() - status: ${status}; url: ${url}`);
359
+ // Since an exception was not thrown, this is a valid url
360
+ this.validity.urlFormat = true;
361
+ this._validatedUrl = url;
319
362
  const valResult = this.getValidationResultFromStatusCode(status);
320
- if (valResult === true && this.validity.authenticated === true) {
321
- return true;
363
+ if (valResult === true) {
364
+ if (this.validity.authenticated === true) {
365
+ return true;
366
+ }
367
+ else if (this.validity.authenticated === false) {
368
+ return (0, i18n_1.t)('errors.authenticationFailed');
369
+ }
322
370
  }
323
371
  return valResult;
324
372
  }
@@ -149,6 +149,7 @@ exports.getAbapOnPremQuestions = getAbapOnPremQuestions;
149
149
  */
150
150
  function getAbapOnPremSystemQuestions(systemNamePromptOptions, connectionValidator, requiredOdataVersion) {
151
151
  const connectValidator = connectionValidator ?? new connectionValidator_1.ConnectionValidator();
152
+ let validClient = true;
152
153
  const questions = [
153
154
  {
154
155
  type: 'input',
@@ -179,10 +180,18 @@ function getAbapOnPremSystemQuestions(systemNamePromptOptions, connectionValidat
179
180
  guiOptions: {
180
181
  breadcrumb: (0, i18n_1.t)('prompts.sapClient.breadcrumb')
181
182
  },
182
- validate: project_input_validator_1.validateClient
183
+ validate: (client) => {
184
+ const valRes = (0, project_input_validator_1.validateClient)(client);
185
+ if (valRes === true) {
186
+ validClient = true;
187
+ return true;
188
+ }
189
+ validClient = false;
190
+ return valRes;
191
+ }
183
192
  },
184
193
  {
185
- when: () => (connectValidator.validity.reachable ? connectValidator.validity.authRequired === true : false),
194
+ when: () => connectValidator.isAuthRequired(),
186
195
  type: 'input',
187
196
  name: abapOnPremInternalPromptNames.systemUsername,
188
197
  message: (0, i18n_1.t)('prompts.systemUsername.message'),
@@ -192,7 +201,7 @@ function getAbapOnPremSystemQuestions(systemNamePromptOptions, connectionValidat
192
201
  validate: (user) => user?.length > 0
193
202
  },
194
203
  {
195
- when: () => (connectValidator.validity.reachable ? connectValidator.validity.authRequired === true : false),
204
+ when: () => connectValidator.isAuthRequired(),
196
205
  type: 'password',
197
206
  guiOptions: {
198
207
  mandatory: true
@@ -202,7 +211,7 @@ function getAbapOnPremSystemQuestions(systemNamePromptOptions, connectionValidat
202
211
  guiType: 'login',
203
212
  mask: '*',
204
213
  validate: async (password, { systemUrl, abapSystemUsername, sapClient }) => {
205
- if (!(systemUrl && abapSystemUsername && password)) {
214
+ if (!(systemUrl && abapSystemUsername && password && validClient)) {
206
215
  return false;
207
216
  }
208
217
  const valResult = await connectValidator.validateAuth(systemUrl, abapSystemUsername, password, {
@@ -64,6 +64,7 @@ exports.getNewSystemQuestions = getNewSystemQuestions;
64
64
  */
65
65
  function getUserSystemNameQuestion() {
66
66
  let defaultSystemName;
67
+ let userModifiedSystemName = false;
67
68
  const newSystemNamePrompt = {
68
69
  type: 'input',
69
70
  guiOptions: {
@@ -74,19 +75,21 @@ function getUserSystemNameQuestion() {
74
75
  name: types_1.promptNames.userSystemName,
75
76
  message: (0, i18n_1.t)('prompts.systemName.message'),
76
77
  default: async (answers) => {
77
- if (answers.newSystemType === 'abapOnPrem' && answers.systemUrl) {
78
+ if (answers.newSystemType === 'abapOnPrem' && answers.systemUrl && !userModifiedSystemName) {
78
79
  defaultSystemName = await (0, prompt_helpers_1.suggestSystemName)(answers.systemUrl, answers.sapClient);
80
+ return defaultSystemName;
79
81
  }
80
- return defaultSystemName;
82
+ return answers.userSystemName;
81
83
  },
82
84
  validate: async (systemName, answers) => {
83
- let validationResult = false;
84
85
  // Dont validate the suggested default system name
85
86
  if (systemName === defaultSystemName) {
86
- validationResult = true;
87
+ return true;
87
88
  }
88
- validationResult = await (0, validators_1.validateSystemName)(systemName);
89
+ const validationResult = await (0, validators_1.validateSystemName)(systemName);
89
90
  if (validationResult === true) {
91
+ // Not the default system name, so the user modified
92
+ userModifiedSystemName = true;
90
93
  const backendSystem = new store_1.BackendSystem({
91
94
  name: systemName,
92
95
  url: answers.systemUrl,
@@ -3,6 +3,5 @@
3
3
  *
4
4
  * @param systemName a system name to validate
5
5
  * @returns true if the name is valid, otherwise an error message
6
- */
7
- export declare function validateSystemName(systemName: string): Promise<boolean | string>;
6
+ */ export declare function validateSystemName(systemName: string): Promise<boolean | string>;
8
7
  //# sourceMappingURL=validators.d.ts.map
@@ -22,8 +22,10 @@ async function isSystemNameInUse(systemName) {
22
22
  *
23
23
  * @param systemName a system name to validate
24
24
  * @returns true if the name is valid, otherwise an error message
25
- */
26
- async function validateSystemName(systemName) {
25
+ */ async function validateSystemName(systemName) {
26
+ if (!systemName) {
27
+ return (0, i18n_1.t)('prompts.systemName.emptySystemNameWarning');
28
+ }
27
29
  const systemExists = await isSystemNameInUse(systemName);
28
30
  if (systemExists) {
29
31
  return (0, i18n_1.t)('prompts.systemName.systemNameExistsWarning');
@@ -95,7 +95,8 @@
95
95
  "message": "System name",
96
96
  "hint": "Entering a system name will save the connection for re-use.",
97
97
  "systemNameExistsWarning": "A system with that name already exists in the secure storage. Please try a different name.",
98
- "reservedSystemNameWarning": "'{{ systemName }}' is a reserved system name. Please try a different name."
98
+ "reservedSystemNameWarning": "'{{ systemName }}' is a reserved system name. Please try a different name.",
99
+ "emptySystemNameWarning": "System name cannot be empty."
99
100
  },
100
101
  "systemSelection": {
101
102
  "newSystemChoiceLabel": "New system"
@@ -128,7 +129,7 @@
128
129
  "noSuchHostError": "No such host is known",
129
130
  "odataServiceVersionMismatch": "The template you have chosen supports V{{requiredVersion}} OData services only. The provided version is V{{serviceVersion}}.",
130
131
  "destinationAuthError": "The selected system is returning an authentication error. Please verify the destination configuration",
131
- "serviceUrlNotFound": "Please verify the service url: {{- url}}, target system configuration and network connectivity",
132
+ "systemOrserviceUrlNotFound": "Please verify the url: {{- url}}, target system configuration and network connectivity",
132
133
  "urlRedirect": "The service URL is redirecting",
133
134
  "certValidationRequired": "Certificate validation is required to continue.",
134
135
  "exitingGeneration": "Exiting generation. {{exitReason}}",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sap-ux/odata-service-inquirer",
3
3
  "description": "Prompts module that can prompt users for inputs required for odata service writing",
4
- "version": "0.5.3",
4
+ "version": "0.5.5",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/SAP/open-ux-tools.git",
@@ -25,7 +25,7 @@
25
25
  "i18next": "23.5.1",
26
26
  "inquirer-autocomplete-prompt": "2.0.1",
27
27
  "os-name": "4.0.1",
28
- "@sap-ux/axios-extension": "1.16.0",
28
+ "@sap-ux/axios-extension": "1.16.1",
29
29
  "@sap-ux/btp-utils": "0.15.0",
30
30
  "@sap-ux/telemetry": "0.5.9",
31
31
  "@sap-ux/inquirer-common": "0.4.2",