@mablhq/mabl-cli 1.18.3 → 1.20.9

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.
Files changed (51) hide show
  1. package/api/basicApiClient.js +17 -13
  2. package/api/mablApiClient.js +11 -7
  3. package/api/mablApiClientFactory.js +20 -19
  4. package/api/types.js +8 -0
  5. package/auth/AuthClient.js +1 -0
  6. package/auth/OktaClient.js +66 -21
  7. package/browserLauncher/playwrightBrowserLauncher/playwrightBrowser.js +12 -0
  8. package/browserLauncher/playwrightBrowserLauncher/playwrightBrowserLauncher.js +2 -6
  9. package/browserLauncher/playwrightBrowserLauncher/playwrightDom.js +11 -4
  10. package/browserLauncher/playwrightBrowserLauncher/playwrightFrame.js +1 -1
  11. package/browserLauncher/playwrightBrowserLauncher/playwrightPage.js +0 -2
  12. package/browserLauncher/types.js +3 -2
  13. package/cli.js +1 -3
  14. package/commands/applications/applications_cmds/list.js +1 -1
  15. package/commands/auth/auth_cmds/activate-key.js +2 -2
  16. package/commands/auth/auth_cmds/clear.js +1 -1
  17. package/commands/auth/auth_cmds/info.js +1 -1
  18. package/commands/branches/branches_cmds/create.js +1 -1
  19. package/commands/branches/branches_cmds/describe.js +1 -1
  20. package/commands/branches/branches_cmds/list.js +1 -1
  21. package/commands/branches/branches_cmds/merge.js +1 -1
  22. package/commands/commandUtil/util.js +3 -3
  23. package/commands/config/config_cmds/configKeys.js +11 -0
  24. package/commands/config/config_cmds/delete.js +6 -5
  25. package/commands/config/config_cmds/get.js +6 -5
  26. package/commands/config/config_cmds/list.js +7 -7
  27. package/commands/config/config_cmds/set.js +14 -21
  28. package/commands/credentials/credentials_cmds/list.js +1 -1
  29. package/commands/deploy/deploy_cmds/create.js +2 -2
  30. package/commands/deploy/deploy_cmds/list.js +1 -1
  31. package/commands/environments/environments_cmds/create.js +8 -4
  32. package/commands/environments/environments_cmds/list.js +1 -1
  33. package/commands/flows/flows_cmds/list.js +1 -1
  34. package/commands/link-agents/link-agents_cmds/delete.js +1 -6
  35. package/commands/plans/plans_cmds/list.js +1 -1
  36. package/commands/tests/testsUtil.js +8 -8
  37. package/commands/tests/tests_cmds/create.js +1 -1
  38. package/commands/tests/tests_cmds/import.js +2 -2
  39. package/commands/tests/tests_cmds/list.js +1 -1
  40. package/commands/tests/tests_cmds/run-cloud.js +3 -7
  41. package/commands/tests/tests_cmds/run.js +8 -4
  42. package/commands/tests/tests_cmds/trainer_cmds/trainerUtil.js +2 -2
  43. package/execution/index.js +1 -1
  44. package/mablscript/diffing/diffingUtil.js +9 -9
  45. package/package.json +3 -2
  46. package/providers/authenticationProvider.js +106 -60
  47. package/providers/cliConfigProvider.js +159 -61
  48. package/providers/types.js +9 -0
  49. package/util/analytics.js +8 -8
  50. package/util/httpUtil.js +6 -9
  51. package/utilities.js +7 -0
@@ -63,9 +63,7 @@ function flattenTestFlowsIntoSteps(flows, flowConfig) {
63
63
  }
64
64
  function flattenTestFlowsIntoLineDiffingFormat(flows, flowConfig) {
65
65
  const flattenedSteps = flattenTestFlowsIntoSteps(flows, flowConfig);
66
- const diffingFormat = flattenedSteps
67
- .map((step) => step.toLineDiffFormat())
68
- .join('\n');
66
+ const diffingFormat = formatLineDiffString(flattenedSteps.map((step) => step.toLineDiffFormat()).join('\n'));
69
67
  return { flattenedSteps, diffingFormat };
70
68
  }
71
69
  exports.flattenTestFlowsIntoLineDiffingFormat = flattenTestFlowsIntoLineDiffingFormat;
@@ -112,13 +110,9 @@ exports.diffTests = diffTests;
112
110
  function diffFlows(flow1, flow2) {
113
111
  var _a, _b;
114
112
  const flow1Steps = (0, importer_1.parseMablScriptIntoSteps)(flow1);
115
- const formattedFlow1Steps = flow1Steps
116
- .map((step) => step.toLineDiffFormat())
117
- .join('\n');
113
+ const formattedFlow1Steps = formatLineDiffString(flow1Steps.map((step) => step.toLineDiffFormat()).join('\n'));
118
114
  const flow2Steps = (0, importer_1.parseMablScriptIntoSteps)(flow2);
119
- const formattedFlow2Steps = flow2Steps
120
- .map((step) => step.toLineDiffFormat())
121
- .join('\n');
115
+ const formattedFlow2Steps = formatLineDiffString(flow2Steps.map((step) => step.toLineDiffFormat()).join('\n'));
122
116
  const flattenedDiffs = lineModeDiff(formattedFlow1Steps, formattedFlow2Steps);
123
117
  const stepDiffs = convertDiffingFormatIntoDiffingSteps(flattenedDiffs, flow1Steps, flow2Steps);
124
118
  const parametersDiff = diffFlowVariables(flow1.parameters, flow2.parameters);
@@ -144,3 +138,9 @@ function flattenFlowVariables(flowVariables) {
144
138
  var _a;
145
139
  return ((_a = flowVariables === null || flowVariables === void 0 ? void 0 : flowVariables.sort((a, b) => a.name.localeCompare(b.name)).map((parameter) => (0, fast_json_stable_stringify_1.default)(parameter)).join('\n')) !== null && _a !== void 0 ? _a : '');
146
140
  }
141
+ function formatLineDiffString(lineDiff) {
142
+ if (!lineDiff) {
143
+ return lineDiff;
144
+ }
145
+ return lineDiff + '\n';
146
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mablhq/mabl-cli",
3
- "version": "1.18.3",
3
+ "version": "1.20.9",
4
4
  "license": "SEE LICENSE IN LICENSE.txt",
5
5
  "description": "The official mabl command line interface tool",
6
6
  "main": "index.js",
@@ -58,6 +58,7 @@
58
58
  "js-yaml": "4.1.0",
59
59
  "jsesc": "3.0.2",
60
60
  "jwt-decode": "2.2.0",
61
+ "keytar": "7.7.0",
61
62
  "lodash.get": "4.4.2",
62
63
  "markdown-table": "2.0.0",
63
64
  "mime-types": "2.1.27",
@@ -77,7 +78,7 @@
77
78
  "retry": "0.13.1",
78
79
  "sanitize-html": "2.3.3",
79
80
  "serve-handler": "6.1.3",
80
- "socks-proxy-agent": "5.0.0",
81
+ "socks-proxy-agent": "6.1.1",
81
82
  "stoppable": "1.1.0",
82
83
  "strip-ansi": "6.0.0",
83
84
  "tmp-promise": "3.0.2",
@@ -3,39 +3,39 @@ 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.AuthenticationProvider = exports.AuthProviderType = void 0;
6
+ exports.isOidcError = exports.AuthenticationProvider = void 0;
7
7
  const open_1 = __importDefault(require("open"));
8
8
  const axios_1 = __importDefault(require("axios"));
9
9
  const env_1 = require("../env/env");
10
10
  const cliConfigProvider_1 = require("./cliConfigProvider");
11
- const basicApiClient_1 = require("../api/basicApiClient");
11
+ const types_1 = require("../api/types");
12
12
  const mablApiClientFactory_1 = require("../api/mablApiClientFactory");
13
13
  const loggingProvider_1 = require("./logging/loggingProvider");
14
14
  const pureUtil_1 = require("../util/pureUtil");
15
15
  const OktaClient_1 = require("../auth/OktaClient");
16
16
  const httpUtil_1 = require("../util/httpUtil");
17
+ const types_2 = require("./types");
17
18
  const humanizeDuration = require('humanize-duration');
18
19
  const inquirer = require('inquirer');
19
20
  const chalk = require('chalk');
20
- var AuthProviderType;
21
- (function (AuthProviderType) {
22
- AuthProviderType["Auth0"] = "auth0";
23
- AuthProviderType["Mabl"] = "mabl";
24
- AuthProviderType["Okta"] = "okta";
25
- })(AuthProviderType = exports.AuthProviderType || (exports.AuthProviderType = {}));
26
21
  class AuthenticationProvider {
27
22
  constructor() {
28
23
  this.verbose = false;
29
- const client = axios_1.default.create((0, httpUtil_1.currentProxyConfig)());
30
- this.oktaClient = new OktaClient_1.OktaClient(client);
24
+ }
25
+ async getOktaClient() {
26
+ if (!this.oktaClient) {
27
+ const client = axios_1.default.create(await (0, httpUtil_1.currentProxyConfig)());
28
+ this.oktaClient = new OktaClient_1.OktaClient(client);
29
+ }
30
+ return this.oktaClient;
31
31
  }
32
32
  async getAuthConfigWithAutoRenew() {
33
- let authConfig = cliConfigProvider_1.CliConfigProvider.getCliConfig().authentication;
33
+ const authConfig = (await cliConfigProvider_1.CliConfigProvider.getCliConfig()).authentication;
34
34
  if (authConfig.accessToken) {
35
35
  if (this.verbose) {
36
36
  loggingProvider_1.logger.info('Found existing access token');
37
37
  }
38
- authConfig = await this.maybeRenewAuthentication(authConfig);
38
+ return this.maybeRenewAuthentication(authConfig);
39
39
  }
40
40
  return authConfig;
41
41
  }
@@ -46,45 +46,71 @@ class AuthenticationProvider {
46
46
  }
47
47
  return authConfig;
48
48
  }
49
- if (authConfig.authProvider === AuthProviderType.Auth0) {
49
+ if (authConfig.authProvider === types_2.AuthProviderType.Auth0) {
50
50
  if (this.verbose) {
51
51
  loggingProvider_1.logger.info(`Authentication refresh token ${chalk.yellow.bold('not valid')}`);
52
52
  }
53
53
  return authConfig;
54
54
  }
55
+ const nowMilliseconds = Date.now();
56
+ const refreshTokenValidMilliseconds = authConfig.refreshTokenExpirationTimeMilliseconds
57
+ ? authConfig.refreshTokenExpirationTimeMilliseconds - nowMilliseconds
58
+ : undefined;
59
+ if (refreshTokenValidMilliseconds !== undefined &&
60
+ refreshTokenValidMilliseconds <= 0) {
61
+ loggingProvider_1.logger.info(`Login has ${chalk.yellow.bold('expired')}. Please run ${chalk.magenta('mabl auth login')} to log in with your mabl account`);
62
+ process.exit(1);
63
+ }
55
64
  if (this.verbose) {
56
- loggingProvider_1.logger.info('Found refresh token');
65
+ loggingProvider_1.logger.info('Found valid refresh token');
57
66
  }
58
- const RefreshAccessTokenWindowMilliseconds = 60 * 60 * 1000;
59
- const nowMilliseconds = Date.now();
60
- const validMilliseconds = authConfig.accessTokenExpirationTimeMilliseconds - nowMilliseconds;
67
+ const RefreshAccessTokenWindowMilliseconds = 10 * 60 * 1000;
68
+ const accessTokenValidMilliseconds = authConfig.accessTokenExpirationTimeMilliseconds - nowMilliseconds;
61
69
  if (this.verbose) {
62
- loggingProvider_1.logger.info(`Existing token expires in ${chalk.yellow.bold(humanizeExpirationTime(validMilliseconds))}`);
70
+ if (accessTokenValidMilliseconds > 0) {
71
+ loggingProvider_1.logger.info(`Existing access token expires in [${chalk.magenta.bold(humanizeExpirationTime(accessTokenValidMilliseconds))}]`);
72
+ }
73
+ else {
74
+ loggingProvider_1.logger.info(`Access token has ${chalk.yellow.bold('expired')}`);
75
+ }
63
76
  }
64
- if (validMilliseconds < RefreshAccessTokenWindowMilliseconds) {
77
+ if (accessTokenValidMilliseconds < RefreshAccessTokenWindowMilliseconds) {
65
78
  if (this.verbose) {
66
79
  loggingProvider_1.logger.info(`Renewing authorization...`);
67
80
  }
68
- const newAuthInfo = await this.oktaClient.exchangeRefreshTokenForAccessToken(authConfig.refreshToken);
81
+ const oktaClient = await this.getOktaClient();
82
+ let newAuthInfo;
83
+ try {
84
+ newAuthInfo = await oktaClient.exchangeRefreshTokenForAccessToken(authConfig.refreshToken);
85
+ }
86
+ catch (error) {
87
+ processAuthorizationError(error, true);
88
+ process.exit(1);
89
+ }
69
90
  if (newAuthInfo.error) {
70
91
  loggingProvider_1.logger.error(chalk.red.bold(`Could not refresh authentication due to error: ${newAuthInfo.error_description}`));
71
92
  process.exit(1);
72
93
  }
73
- newAuthInfo.refresh_token = authConfig.refreshToken;
74
- cliConfigProvider_1.CliConfigProvider.setCliAuthInfo(newAuthInfo, nowMilliseconds);
75
- return cliConfigProvider_1.CliConfigProvider.getCliConfig().authentication;
94
+ if (!newAuthInfo.refresh_token_expires_at &&
95
+ authConfig.refreshTokenExpirationTimeMilliseconds) {
96
+ newAuthInfo.refresh_token_expires_at =
97
+ authConfig.refreshTokenExpirationTimeMilliseconds / 1000;
98
+ }
99
+ await cliConfigProvider_1.CliConfigProvider.setCliAuthInfo(newAuthInfo, nowMilliseconds);
100
+ return (await cliConfigProvider_1.CliConfigProvider.getCliConfig()).authentication;
76
101
  }
77
102
  return authConfig;
78
103
  }
79
- static getAuthType() {
80
- const config = cliConfigProvider_1.CliConfigProvider.getCliConfig();
104
+ static async getAuthType() {
105
+ const config = await cliConfigProvider_1.CliConfigProvider.getCliConfig();
81
106
  return config.authentication.authType;
82
107
  }
83
- displayInfo() {
108
+ async displayInfo() {
109
+ var _a;
84
110
  try {
85
- const config = cliConfigProvider_1.CliConfigProvider.getCliConfig();
86
- if (config.authentication.authType === basicApiClient_1.AuthType.ApiKey) {
87
- loggingProvider_1.logger.info('You are authenticated by API key');
111
+ const config = await cliConfigProvider_1.CliConfigProvider.getCliConfig();
112
+ if (config.authentication.authType === types_1.AuthType.ApiKey) {
113
+ loggingProvider_1.logger.info(`You are authenticated by ${chalk.magenta.bold('API key')}`);
88
114
  return;
89
115
  }
90
116
  if (!config.email || config.authentication.authType === undefined) {
@@ -92,7 +118,7 @@ class AuthenticationProvider {
92
118
  return;
93
119
  }
94
120
  loggingProvider_1.logger.info(`Logged in as user [${chalk.magenta.bold(config.email)}]`);
95
- const expirationMilliseconds = config.authentication.accessTokenExpirationTimeMilliseconds -
121
+ const expirationMilliseconds = ((_a = config.authentication.refreshTokenExpirationTimeMilliseconds) !== null && _a !== void 0 ? _a : config.authentication.accessTokenExpirationTimeMilliseconds) -
96
122
  Date.now();
97
123
  if (expirationMilliseconds > 0) {
98
124
  loggingProvider_1.logger.info(`Login expires in [${chalk.magenta.bold(humanizeExpirationTime(expirationMilliseconds))}]`);
@@ -106,36 +132,41 @@ class AuthenticationProvider {
106
132
  process.exit(1);
107
133
  }
108
134
  }
109
- clearAuthentication() {
135
+ async clearAuthentication() {
110
136
  try {
111
- const config = cliConfigProvider_1.CliConfigProvider.getCliConfig();
112
- if (!config.email) {
137
+ const config = await cliConfigProvider_1.CliConfigProvider.getCliConfig();
138
+ if (!config.email && config.authentication.authType !== types_1.AuthType.ApiKey) {
113
139
  loggingProvider_1.logger.info('You are not logged in');
114
140
  return;
115
141
  }
116
- loggingProvider_1.logger.info(`Logged out user [${chalk.magenta.bold(config.email)}]`);
117
- cliConfigProvider_1.CliConfigProvider.clearAuthConfig();
142
+ await cliConfigProvider_1.CliConfigProvider.clearAuthConfig();
143
+ if (config.email) {
144
+ loggingProvider_1.logger.info(`Logged out user [${chalk.magenta.bold(config.email)}]`);
145
+ }
146
+ else {
147
+ loggingProvider_1.logger.info(`Removed ${chalk.magenta.bold('API key')}`);
148
+ }
118
149
  }
119
150
  catch (error) {
120
151
  loggingProvider_1.logger.error(chalk.red.bold(error));
121
152
  process.exit(1);
122
153
  }
123
154
  }
124
- activateApiKey(apiKey) {
155
+ async activateApiKey(apiKey) {
125
156
  const authInfo = {
126
- auth_provider: AuthProviderType.Mabl,
127
- auth_type: basicApiClient_1.AuthType.ApiKey,
157
+ auth_provider: types_2.AuthProviderType.Mabl,
158
+ auth_type: types_1.AuthType.ApiKey,
128
159
  api_key: apiKey,
129
160
  };
130
161
  const requestTimeMilliseconds = Date.now();
131
- cliConfigProvider_1.CliConfigProvider.setCliAuthInfo(authInfo, requestTimeMilliseconds);
162
+ await cliConfigProvider_1.CliConfigProvider.setCliAuthInfo(authInfo, requestTimeMilliseconds);
132
163
  }
133
164
  async authenticate() {
134
- var _a;
165
+ const oktaClient = await this.getOktaClient();
135
166
  try {
136
- const { codeChallenge, codeVerifier } = this.oktaClient.generateCodeChallenge();
167
+ const { codeChallenge, codeVerifier } = oktaClient.generateCodeChallenge();
137
168
  const redirectUri = `${env_1.BASE_APP_URL}/app-code`;
138
- const authUrl = this.oktaClient.buildAuthorizationUrl(codeChallenge, redirectUri);
169
+ const authUrl = oktaClient.buildAuthorizationUrl(codeChallenge, redirectUri);
139
170
  loggingProvider_1.logger.info(`Your browser has been opened to the following URL for obtaining an authorization code:
140
171
 
141
172
  ${authUrl}
@@ -152,34 +183,23 @@ ${authUrl}
152
183
  const requestTimeMilliseconds = Date.now();
153
184
  let authInfo;
154
185
  try {
155
- authInfo = await this.oktaClient.validateAuthCode(response.authCode, codeVerifier, redirectUri);
186
+ authInfo = await oktaClient.validateAuthCode(response.authCode, codeVerifier, redirectUri);
156
187
  }
157
188
  catch (error) {
158
- loggingProvider_1.logger.error(chalk.red.bold(`Authorization failed.`));
159
- loggingProvider_1.logger.error(chalk.red.bold(error.toString()));
160
- const data = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
161
- if (isOidcError(data)) {
162
- loggingProvider_1.logger.error(chalk.red.bold(`Authorization failed: ${data.error_description} [${data.error}]`));
163
- }
164
- else if (data) {
165
- loggingProvider_1.logger.error(chalk.red.bold(`Response data: ${JSON.stringify(data)}`));
166
- }
167
- else {
168
- loggingProvider_1.logger.error(chalk.red.bold('No response data'));
169
- }
189
+ processAuthorizationError(error, false);
170
190
  process.exit(1);
171
191
  }
172
192
  if (authInfo.error) {
173
193
  loggingProvider_1.logger.error(chalk.red.bold(`Could not login due to error: ${authInfo.error_description}`));
174
194
  process.exit(1);
175
195
  }
176
- cliConfigProvider_1.CliConfigProvider.setCliAuthInfo(authInfo, requestTimeMilliseconds);
196
+ await cliConfigProvider_1.CliConfigProvider.setCliAuthInfo(authInfo, requestTimeMilliseconds);
177
197
  const userData = await AuthenticationProvider.requestUserInfo(authInfo.access_token);
178
- const config = cliConfigProvider_1.CliConfigProvider.getCliConfig();
198
+ const config = await cliConfigProvider_1.CliConfigProvider.getCliConfig();
179
199
  config.userId = userData.id;
180
200
  config.email = userData.email;
181
201
  config.userFullName = userData.name;
182
- cliConfigProvider_1.CliConfigProvider.setCliConfig(config);
202
+ await cliConfigProvider_1.CliConfigProvider.setCliConfig(config);
183
203
  loggingProvider_1.logger.info(chalk.green.bold(`Login successful for: ${userData.email}`));
184
204
  }
185
205
  catch (error) {
@@ -192,11 +212,35 @@ ${authUrl}
192
212
  return (0, open_1.default)(path);
193
213
  }
194
214
  static async requestUserInfo(accessToken) {
195
- const apiClient = mablApiClientFactory_1.MablApiClientFactory.createApiClientForAccessToken(accessToken);
215
+ const apiClient = await mablApiClientFactory_1.MablApiClientFactory.createApiClientForAccessToken(accessToken);
196
216
  return apiClient.getSelf();
197
217
  }
198
218
  }
199
219
  exports.AuthenticationProvider = AuthenticationProvider;
220
+ function processAuthorizationError(error, isTokenRefresh) {
221
+ var _a;
222
+ const mainErrorMessage = isTokenRefresh ? 'Token refresh' : 'Authorization';
223
+ loggingProvider_1.logger.error(chalk.red.bold(`${mainErrorMessage} failed.`));
224
+ loggingProvider_1.logger.error(chalk.red.bold(error.toString()));
225
+ let hasResponseData = false;
226
+ if (axios_1.default.isAxiosError(error)) {
227
+ const data = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data;
228
+ if (isOidcError(data)) {
229
+ loggingProvider_1.logger.error(chalk.red.bold(`${mainErrorMessage} failed: ${data.error_description} [${data.error}]`));
230
+ hasResponseData = true;
231
+ }
232
+ else if (data) {
233
+ loggingProvider_1.logger.error(chalk.red.bold(`Response data: ${JSON.stringify(data)}`));
234
+ hasResponseData = true;
235
+ }
236
+ }
237
+ if (!hasResponseData) {
238
+ loggingProvider_1.logger.error(chalk.red.bold('No response data'));
239
+ }
240
+ if (isTokenRefresh) {
241
+ loggingProvider_1.logger.error(`Please try again. If the issue persists authenticate again with ${chalk.magenta('mabl auth login')}.`);
242
+ }
243
+ }
200
244
  function humanizeExpirationTime(milliseconds) {
201
245
  return humanizeDuration(milliseconds, {
202
246
  maxDecimalPoints: 0,
@@ -204,5 +248,7 @@ function humanizeExpirationTime(milliseconds) {
204
248
  });
205
249
  }
206
250
  function isOidcError(err) {
207
- return (0, pureUtil_1.isString)(err === null || err === void 0 ? void 0 : err.error) && (0, pureUtil_1.isString)(err === null || err === void 0 ? void 0 : err.error_description);
251
+ return ((0, pureUtil_1.isString)(err === null || err === void 0 ? void 0 : err.error) &&
252
+ (0, pureUtil_1.isString)(err === null || err === void 0 ? void 0 : err.error_description));
208
253
  }
254
+ exports.isOidcError = isOidcError;
@@ -1,15 +1,41 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
5
28
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.CliConfigProvider = exports.getAuthConfigFile = void 0;
29
+ exports.__resetIsKeytarAvailable = exports.CliConfigProvider = exports.getAuthConfigFile = exports.getEncryptionKey = exports.AUTH_KEY_NAMES = exports.IS_CONFIG_ENCRYPTED_KEY_NAME = void 0;
7
30
  const env_1 = require("../env/env");
8
31
  const conf_1 = __importDefault(require("conf"));
9
- const authenticationProvider_1 = require("./authenticationProvider");
10
- const basicApiClient_1 = require("../api/basicApiClient");
11
- const set_1 = require("../commands/config/config_cmds/set");
32
+ const types_1 = require("./types");
33
+ const types_2 = require("../api/types");
34
+ const configKeys_1 = require("../commands/config/config_cmds/configKeys");
12
35
  const httpUtil_1 = require("../util/httpUtil");
36
+ const crypto = __importStar(require("crypto"));
37
+ const loggingProvider_1 = require("./logging/loggingProvider");
38
+ const utilities_1 = require("../utilities");
13
39
  const USER_ID_NAME = 'userId';
14
40
  const USER_FULL_NAME_NAME = 'userFullName';
15
41
  const EMAIL_NAME = 'email';
@@ -19,17 +45,71 @@ const AUTH_TYPE = 'authType';
19
45
  const ACCESS_TOKEN_NAME = 'accessToken';
20
46
  const REFRESH_TOKEN_NAME = 'refreshToken';
21
47
  const ACCESS_TOKEN_EXPIRATION_MILLISECONDS_NAME = 'accessTokenExpirationTimeMilliseconds';
22
- const AUTH_KEY_NAMES = [
48
+ const REFRESH_TOKEN_EXPIRATION_MILLISECONDS_NAME = `${REFRESH_TOKEN_NAME}ExpirationTimeMilliseconds`;
49
+ exports.IS_CONFIG_ENCRYPTED_KEY_NAME = '_isConfigEncrypted';
50
+ exports.AUTH_KEY_NAMES = [
23
51
  AUTH_PROVIDER,
24
52
  AUTH_TYPE,
25
53
  ACCESS_TOKEN_NAME,
26
54
  ACCESS_TOKEN_EXPIRATION_MILLISECONDS_NAME,
27
55
  REFRESH_TOKEN_NAME,
56
+ REFRESH_TOKEN_EXPIRATION_MILLISECONDS_NAME,
28
57
  USER_FULL_NAME_NAME,
29
58
  USER_ID_NAME,
30
59
  EMAIL_NAME,
31
60
  ];
32
- function getAuthConfigFile() {
61
+ let isKeytarAvailable = true;
62
+ async function getEncryptionKey() {
63
+ var _a;
64
+ if ((0, utilities_1.areWeTestingInJest)()) {
65
+ return;
66
+ }
67
+ let maybeEncryptionKey;
68
+ if (isKeytarAvailable) {
69
+ try {
70
+ const keytar = require('keytar');
71
+ maybeEncryptionKey =
72
+ (_a = (await keytar.getPassword(env_1.CONF_FILE_PROJECT_NAME, env_1.ENV))) !== null && _a !== void 0 ? _a : undefined;
73
+ if (!maybeEncryptionKey) {
74
+ maybeEncryptionKey = crypto
75
+ .randomFillSync(Buffer.alloc(48))
76
+ .toString('base64');
77
+ await keytar.setPassword(env_1.CONF_FILE_PROJECT_NAME, env_1.ENV, maybeEncryptionKey);
78
+ }
79
+ }
80
+ catch (error) {
81
+ loggingProvider_1.logger.warn(`Creating finite login session because login auto-renewal is unsupported on this system.`);
82
+ isKeytarAvailable = false;
83
+ }
84
+ }
85
+ return maybeEncryptionKey;
86
+ }
87
+ exports.getEncryptionKey = getEncryptionKey;
88
+ async function getAuthConfigFile() {
89
+ const maybeEncryptionKey = await getEncryptionKey();
90
+ if (!isKeytarAvailable || (0, utilities_1.areWeTestingInJest)()) {
91
+ return getNonEncryptedConfig();
92
+ }
93
+ const conf = new conf_1.default({
94
+ configName: 'access-enc',
95
+ projectName: env_1.CONF_FILE_PROJECT_NAME,
96
+ projectVersion: env_1.CONF_FILE_VERSION,
97
+ accessPropertiesByDotNotation: false,
98
+ encryptionKey: maybeEncryptionKey,
99
+ });
100
+ if (conf.has(exports.IS_CONFIG_ENCRYPTED_KEY_NAME)) {
101
+ return conf;
102
+ }
103
+ const oldConf = getNonEncryptedConfig();
104
+ copyConf(oldConf, conf);
105
+ conf.set(exports.IS_CONFIG_ENCRYPTED_KEY_NAME, true);
106
+ return conf;
107
+ }
108
+ exports.getAuthConfigFile = getAuthConfigFile;
109
+ function shouldStoreRefreshTokens() {
110
+ return isKeytarAvailable || (0, utilities_1.areWeTestingInJest)();
111
+ }
112
+ function getNonEncryptedConfig() {
33
113
  return new conf_1.default({
34
114
  configName: 'access',
35
115
  projectName: env_1.CONF_FILE_PROJECT_NAME,
@@ -37,56 +117,62 @@ function getAuthConfigFile() {
37
117
  accessPropertiesByDotNotation: false,
38
118
  });
39
119
  }
40
- exports.getAuthConfigFile = getAuthConfigFile;
120
+ function copyConf(confFrom, confTo) {
121
+ for (const key of [...exports.AUTH_KEY_NAMES, ...configKeys_1.validConfigKeyChoices]) {
122
+ const value = confFrom.get(key);
123
+ if (value !== undefined) {
124
+ confTo.set(key, value);
125
+ }
126
+ }
127
+ }
41
128
  class CliConfigProvider {
42
129
  static setWorkspace(workspaceId) {
43
- setValue(WORKSPACE, workspaceId);
130
+ return setValue(WORKSPACE, workspaceId);
44
131
  }
45
132
  static clearWorkspace() {
46
- clearValue(WORKSPACE);
133
+ return clearValue(WORKSPACE);
47
134
  }
48
- static getWorkspace() {
49
- return getAuthConfigFile().get(WORKSPACE);
135
+ static async getWorkspace() {
136
+ return (await getAuthConfigFile()).get(WORKSPACE);
50
137
  }
51
138
  static getConfigProperty(key) {
52
- return getValue(this.propertyKeyToStoredKey(key));
139
+ return getValue(propertyKeyToStoredKey(key));
53
140
  }
54
141
  static clearConfigProperty(key) {
55
- return clearValue(this.propertyKeyToStoredKey(key));
142
+ return clearValue(propertyKeyToStoredKey(key));
56
143
  }
57
144
  static setConfigProperty(key, value) {
58
- return setValue(this.propertyKeyToStoredKey(key), value);
145
+ return setValue(propertyKeyToStoredKey(key), value);
59
146
  }
60
- static propertyKeyToStoredKey(key) {
61
- return `properties.${key}`;
62
- }
63
- static getCliConfig() {
64
- const authType = getAuthConfigFile().get(AUTH_TYPE);
65
- let authProvider = getAuthConfigFile().get(AUTH_PROVIDER);
147
+ static async getCliConfig() {
148
+ const config = await getAuthConfigFile();
149
+ const authType = config.get(AUTH_TYPE);
150
+ let authProvider = config.get(AUTH_PROVIDER);
66
151
  if (!authProvider && authType !== undefined) {
67
152
  authProvider =
68
- authType === basicApiClient_1.AuthType.ApiKey
69
- ? authenticationProvider_1.AuthProviderType.Mabl
70
- : authenticationProvider_1.AuthProviderType.Auth0;
153
+ authType === types_2.AuthType.ApiKey
154
+ ? types_1.AuthProviderType.Mabl
155
+ : types_1.AuthProviderType.Auth0;
71
156
  }
72
157
  const authentication = {
73
158
  authProvider,
74
159
  authType,
75
- accessToken: getAuthConfigFile().get(ACCESS_TOKEN_NAME),
76
- refreshToken: getAuthConfigFile().get(REFRESH_TOKEN_NAME),
77
- accessTokenExpirationTimeMilliseconds: getAuthConfigFile().get(ACCESS_TOKEN_EXPIRATION_MILLISECONDS_NAME),
160
+ accessToken: config.get(ACCESS_TOKEN_NAME),
161
+ refreshToken: config.get(REFRESH_TOKEN_NAME),
162
+ accessTokenExpirationTimeMilliseconds: config.get(ACCESS_TOKEN_EXPIRATION_MILLISECONDS_NAME),
163
+ refreshTokenExpirationTimeMilliseconds: config.get(REFRESH_TOKEN_EXPIRATION_MILLISECONDS_NAME),
78
164
  };
79
165
  const httpConfig = {
80
166
  sslVerify: httpUtil_1.EXECUTION_ENGINE_SSL_VERIFY,
81
167
  };
82
- const proxyHostValue = this.getConfigProperty(set_1.configKeys.proxy);
168
+ const proxyHostValue = await this.getConfigProperty(configKeys_1.configKeys.proxy);
83
169
  if (proxyHostValue) {
84
170
  if (typeof proxyHostValue !== 'string') {
85
171
  throw new Error('Invalid proxy host value');
86
172
  }
87
173
  httpConfig.proxyHost = new URL(proxyHostValue);
88
174
  }
89
- const sslVerifyValue = this.getConfigProperty(set_1.configKeys.sslVerify);
175
+ const sslVerifyValue = await this.getConfigProperty(configKeys_1.configKeys.sslVerify);
90
176
  if (sslVerifyValue !== undefined) {
91
177
  if (typeof sslVerifyValue !== 'boolean') {
92
178
  throw new Error(`Invalid proxy sslVerify value`);
@@ -95,60 +181,72 @@ class CliConfigProvider {
95
181
  }
96
182
  return {
97
183
  authentication,
98
- userId: getAuthConfigFile().get(USER_ID_NAME),
99
- email: getAuthConfigFile().get(EMAIL_NAME),
100
- userFullName: getAuthConfigFile().get(USER_FULL_NAME_NAME),
101
- workspace: getAuthConfigFile().get(WORKSPACE),
184
+ userId: config.get(USER_ID_NAME),
185
+ email: config.get(EMAIL_NAME),
186
+ userFullName: config.get(USER_FULL_NAME_NAME),
187
+ workspace: config.get(WORKSPACE),
102
188
  http: httpConfig,
103
189
  };
104
190
  }
105
191
  static clearAuthConfig() {
106
- AUTH_KEY_NAMES.forEach((keyName) => clearValue(keyName));
192
+ exports.AUTH_KEY_NAMES.forEach((keyName) => clearValue(keyName));
107
193
  return this.getCliConfig();
108
194
  }
109
- static setCliConfig(config) {
110
- var _a, _b, _c, _d, _e;
111
- setValue(AUTH_PROVIDER, (_a = config === null || config === void 0 ? void 0 : config.authentication) === null || _a === void 0 ? void 0 : _a.authProvider);
112
- setValue(AUTH_TYPE, (_b = config === null || config === void 0 ? void 0 : config.authentication) === null || _b === void 0 ? void 0 : _b.authType);
113
- setValue(ACCESS_TOKEN_NAME, (_c = config === null || config === void 0 ? void 0 : config.authentication) === null || _c === void 0 ? void 0 : _c.accessToken);
114
- setValue(REFRESH_TOKEN_NAME, (_d = config === null || config === void 0 ? void 0 : config.authentication) === null || _d === void 0 ? void 0 : _d.refreshToken);
115
- setValue(ACCESS_TOKEN_EXPIRATION_MILLISECONDS_NAME, (_e = config === null || config === void 0 ? void 0 : config.authentication) === null || _e === void 0 ? void 0 : _e.accessTokenExpirationTimeMilliseconds);
116
- setValue(USER_ID_NAME, config.userId);
117
- setValue(EMAIL_NAME, config.email);
118
- setValue(USER_FULL_NAME_NAME, config.userFullName);
195
+ static async setCliConfig(config) {
196
+ var _a, _b, _c, _d, _e, _f;
197
+ await setValue(AUTH_PROVIDER, (_a = config === null || config === void 0 ? void 0 : config.authentication) === null || _a === void 0 ? void 0 : _a.authProvider);
198
+ await setValue(AUTH_TYPE, (_b = config === null || config === void 0 ? void 0 : config.authentication) === null || _b === void 0 ? void 0 : _b.authType);
199
+ await setValue(ACCESS_TOKEN_NAME, (_c = config === null || config === void 0 ? void 0 : config.authentication) === null || _c === void 0 ? void 0 : _c.accessToken);
200
+ await setValue(REFRESH_TOKEN_NAME, (_d = config === null || config === void 0 ? void 0 : config.authentication) === null || _d === void 0 ? void 0 : _d.refreshToken);
201
+ await setValue(ACCESS_TOKEN_EXPIRATION_MILLISECONDS_NAME, (_e = config === null || config === void 0 ? void 0 : config.authentication) === null || _e === void 0 ? void 0 : _e.accessTokenExpirationTimeMilliseconds);
202
+ await setValue(REFRESH_TOKEN_EXPIRATION_MILLISECONDS_NAME, (_f = config === null || config === void 0 ? void 0 : config.authentication) === null || _f === void 0 ? void 0 : _f.refreshTokenExpirationTimeMilliseconds);
203
+ await setValue(USER_ID_NAME, config.userId);
204
+ await setValue(EMAIL_NAME, config.email);
205
+ await setValue(USER_FULL_NAME_NAME, config.userFullName);
119
206
  return config;
120
207
  }
121
- static setCliAuthInfo(authInfo, updateMilliseconds) {
122
- setValue(AUTH_TYPE, authInfo === null || authInfo === void 0 ? void 0 : authInfo.auth_type);
208
+ static async setCliAuthInfo(authInfo, updateMilliseconds) {
209
+ await setValue(AUTH_TYPE, authInfo === null || authInfo === void 0 ? void 0 : authInfo.auth_type);
123
210
  switch (authInfo.auth_type) {
124
- case basicApiClient_1.AuthType.Bearer:
211
+ case types_2.AuthType.Bearer:
125
212
  const bearerAuthInfo = authInfo;
126
213
  const expirationTimeMilliseconds = updateMilliseconds + bearerAuthInfo.expires_in * 1000;
127
- setValue(AUTH_PROVIDER, bearerAuthInfo.auth_provider);
128
- setValue(ACCESS_TOKEN_NAME, bearerAuthInfo === null || bearerAuthInfo === void 0 ? void 0 : bearerAuthInfo.access_token);
129
- setValue(REFRESH_TOKEN_NAME, bearerAuthInfo === null || bearerAuthInfo === void 0 ? void 0 : bearerAuthInfo.refresh_token);
130
- setValue(ACCESS_TOKEN_EXPIRATION_MILLISECONDS_NAME, expirationTimeMilliseconds);
214
+ await setValue(AUTH_PROVIDER, bearerAuthInfo.auth_provider);
215
+ await setValue(ACCESS_TOKEN_NAME, bearerAuthInfo === null || bearerAuthInfo === void 0 ? void 0 : bearerAuthInfo.access_token);
216
+ await setValue(REFRESH_TOKEN_NAME, bearerAuthInfo === null || bearerAuthInfo === void 0 ? void 0 : bearerAuthInfo.refresh_token);
217
+ await setValue(ACCESS_TOKEN_EXPIRATION_MILLISECONDS_NAME, expirationTimeMilliseconds);
218
+ if (bearerAuthInfo.refresh_token_expires_at) {
219
+ await setValue(REFRESH_TOKEN_EXPIRATION_MILLISECONDS_NAME, bearerAuthInfo.refresh_token_expires_at * 1000);
220
+ }
131
221
  return;
132
- case basicApiClient_1.AuthType.ApiKey:
222
+ case types_2.AuthType.ApiKey:
133
223
  const apiKeyAuthInfo = authInfo;
134
- setValue(AUTH_PROVIDER, apiKeyAuthInfo.auth_provider);
135
- setValue(ACCESS_TOKEN_NAME, apiKeyAuthInfo.api_key);
224
+ await setValue(AUTH_PROVIDER, apiKeyAuthInfo.auth_provider);
225
+ await setValue(ACCESS_TOKEN_NAME, apiKeyAuthInfo.api_key);
136
226
  return;
137
227
  }
138
228
  }
139
229
  }
140
230
  exports.CliConfigProvider = CliConfigProvider;
141
- function setValue(key, value) {
231
+ function propertyKeyToStoredKey(key) {
232
+ return `properties.${key}`;
233
+ }
234
+ async function setValue(key, value) {
142
235
  if (value === undefined) {
143
- clearValue(key);
236
+ return clearValue(key);
144
237
  }
145
- else {
146
- getAuthConfigFile().set(key, value);
238
+ if (!shouldStoreRefreshTokens() && key.includes(REFRESH_TOKEN_NAME)) {
239
+ return;
147
240
  }
241
+ (await getAuthConfigFile()).set(key, value);
242
+ }
243
+ async function getValue(key) {
244
+ return (await getAuthConfigFile()).get(key);
148
245
  }
149
- function getValue(key) {
150
- return getAuthConfigFile().get(key);
246
+ async function clearValue(key) {
247
+ (await getAuthConfigFile()).delete(key);
151
248
  }
152
- function clearValue(key) {
153
- getAuthConfigFile().delete(key);
249
+ function __resetIsKeytarAvailable() {
250
+ isKeytarAvailable = true;
154
251
  }
252
+ exports.__resetIsKeytarAvailable = __resetIsKeytarAvailable;