az2aws 1.6.2 → 1.7.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.
@@ -9,6 +9,21 @@ const inquirer_1 = __importDefault(require("inquirer"));
9
9
  const debug_1 = __importDefault(require("debug"));
10
10
  const CLIError_1 = require("./CLIError");
11
11
  const debug = (0, debug_1.default)("az2aws");
12
+ async function readTextContent(page, element) {
13
+ if (!element) {
14
+ return "";
15
+ }
16
+ return page.evaluate((node) => { var _a; return (_a = node.textContent) !== null && _a !== void 0 ? _a : ""; }, element);
17
+ }
18
+ const PASSWORD_SELECTOR = 'input[name="Password"]:not(.moveOffScreen),input[name="passwd"]:not(.moveOffScreen)';
19
+ function printPageMessage(message, allowSensitiveOutput = true) {
20
+ if (allowSensitiveOutput) {
21
+ console.log(message);
22
+ }
23
+ }
24
+ function createSensitiveCliError(message, sanitizedMessage, allowSensitiveOutput = true) {
25
+ return new CLIError_1.CLIError(allowSensitiveOutput ? message : sanitizedMessage);
26
+ }
12
27
  /**
13
28
  * To proxy the input/output of the Azure login page, it's easiest to run a loop that
14
29
  * monitors the state of the page and then perform the corresponding CLI behavior.
@@ -20,15 +35,12 @@ exports.states = [
20
35
  {
21
36
  name: "username input",
22
37
  selector: `input[name="loginfmt"]:not(.moveOffScreen)`,
23
- async handler(page, _selected, noPrompt, defaultUsername) {
38
+ async handler(page, _selected, noPrompt, defaultUsername, _defaultPassword, _rememberMe, allowSensitiveOutput) {
24
39
  const error = await page.$(".alert-error");
25
40
  if (error) {
26
41
  debug("Found error message. Displaying");
27
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
28
- const errorMessage = await page.evaluate(
29
- // eslint-disable-next-line
30
- (err) => { var _a; return (_a = err === null || err === void 0 ? void 0 : err.textContent) !== null && _a !== void 0 ? _a : ""; }, error);
31
- console.log(errorMessage);
42
+ const errorMessage = await readTextContent(page, error);
43
+ printPageMessage(errorMessage, allowSensitiveOutput);
32
44
  }
33
45
  let username;
34
46
  if (noPrompt && defaultUsername) {
@@ -37,7 +49,6 @@ exports.states = [
37
49
  }
38
50
  else {
39
51
  debug("Prompting user for username");
40
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
41
52
  ({ username } = await inquirer_1.default.prompt([
42
53
  {
43
54
  type: "input",
@@ -60,7 +71,6 @@ exports.states = [
60
71
  });
61
72
  await page.keyboard.press("Backspace");
62
73
  debug("Typing username");
63
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
64
74
  await page.keyboard.type(username);
65
75
  await (0, promises_1.setTimeout)(500);
66
76
  debug("Waiting for submit button to be visible");
@@ -87,22 +97,16 @@ exports.states = [
87
97
  {
88
98
  name: "account selection",
89
99
  selector: `#aadTile > div > div.table-cell.tile-img > img`,
90
- async handler(page) {
100
+ async handler(page, _selected, noPrompt, _defaultUsername, _defaultPassword, _rememberMe, allowSensitiveOutput) {
91
101
  debug("Multiple accounts associated with username.");
92
102
  const aadTile = await page.$("#aadTileTitle");
93
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
94
- const aadTileMessage = await page.evaluate(
95
- // eslint-disable-next-line
96
- (a) => { var _a; return (_a = a === null || a === void 0 ? void 0 : a.textContent) !== null && _a !== void 0 ? _a : ""; }, aadTile);
103
+ const aadTileMessage = await readTextContent(page, aadTile);
97
104
  const msaTile = await page.$("#msaTileTitle");
98
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
99
- const msaTileMessage = await page.evaluate(
100
- // eslint-disable-next-line
101
- (m) => { var _a; return (_a = m === null || m === void 0 ? void 0 : m.textContent) !== null && _a !== void 0 ? _a : ""; }, msaTile);
105
+ const msaTileMessage = await readTextContent(page, msaTile);
102
106
  const accounts = [
103
107
  aadTile ? { message: aadTileMessage, selector: "#aadTileTitle" } : null,
104
108
  msaTile ? { message: msaTileMessage, selector: "#msaTileTitle" } : null,
105
- ].filter((a) => a !== null);
109
+ ].filter((account) => account !== null);
106
110
  let account;
107
111
  if (accounts.length === 0) {
108
112
  throw new CLIError_1.CLIError("No accounts found on account selection screen.");
@@ -110,10 +114,16 @@ exports.states = [
110
114
  else if (accounts.length === 1) {
111
115
  account = accounts[0];
112
116
  }
117
+ else if (noPrompt) {
118
+ debug("Skipping account prompt and using default account");
119
+ account = accounts.find((candidate) => {
120
+ return candidate.message === aadTileMessage;
121
+ });
122
+ }
113
123
  else {
114
124
  debug("Asking user to choose account");
115
- console.log("It looks like this Username is used with more than one account from Microsoft. Which one do you want to use?");
116
- const answers = await inquirer_1.default.prompt([
125
+ printPageMessage("It looks like this Username is used with more than one account from Microsoft. Which one do you want to use?", allowSensitiveOutput);
126
+ const { account: selectedAccount } = await inquirer_1.default.prompt([
117
127
  {
118
128
  name: "account",
119
129
  message: "Account:",
@@ -122,7 +132,9 @@ exports.states = [
122
132
  default: aadTileMessage,
123
133
  },
124
134
  ]);
125
- account = accounts.find((a) => a.message === answers.account);
135
+ account = accounts.find((candidate) => {
136
+ return candidate.message === selectedAccount;
137
+ });
126
138
  }
127
139
  if (!account) {
128
140
  throw new Error("Unable to find account");
@@ -135,32 +147,22 @@ exports.states = [
135
147
  {
136
148
  name: "passwordless",
137
149
  selector: `input[value='Send notification']`,
138
- async handler(page) {
150
+ async handler(page, _selected, _noPrompt, _defaultUsername, _defaultPassword, _rememberMe, allowSensitiveOutput) {
139
151
  debug("Sending notification");
140
- // eslint-disable-next-line
141
152
  await page.click("input[value='Send notification']");
142
153
  debug("Waiting for auth code");
143
- // eslint-disable-next-line
144
154
  await page.waitForSelector(`#idRemoteNGC_DisplaySign`, {
145
155
  visible: true,
146
156
  timeout: 60000,
147
157
  });
148
158
  debug("Printing the message displayed");
149
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
150
159
  const messageElement = await page.$("#idDiv_RemoteNGC_PollingDescription");
151
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
152
160
  const codeElement = await page.$("#idRemoteNGC_DisplaySign");
153
- // eslint-disable-next-line
154
- const message = await page.evaluate(
155
- // eslint-disable-next-line
156
- (el) => { var _a; return (_a = el === null || el === void 0 ? void 0 : el.textContent) !== null && _a !== void 0 ? _a : ""; }, messageElement);
157
- console.log(message);
161
+ const message = await readTextContent(page, messageElement);
162
+ printPageMessage(message, allowSensitiveOutput);
158
163
  debug("Printing the auth code");
159
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
160
- const authCode = await page.evaluate(
161
- // eslint-disable-next-line
162
- (el) => { var _a; return (_a = el === null || el === void 0 ? void 0 : el.textContent) !== null && _a !== void 0 ? _a : ""; }, codeElement);
163
- console.log(authCode);
164
+ const authCode = await readTextContent(page, codeElement);
165
+ printPageMessage(authCode, allowSensitiveOutput);
164
166
  debug("Waiting for response");
165
167
  await page.waitForSelector(`#idRemoteNGC_DisplaySign`, {
166
168
  hidden: true,
@@ -170,16 +172,13 @@ exports.states = [
170
172
  },
171
173
  {
172
174
  name: "password input",
173
- selector: `input[name="Password"]:not(.moveOffScreen),input[name="passwd"]:not(.moveOffScreen)`,
174
- async handler(page, _selected, noPrompt, _defaultUsername, defaultPassword) {
175
+ selector: PASSWORD_SELECTOR,
176
+ async handler(page, _selected, noPrompt, _defaultUsername, defaultPassword, _rememberMe, allowSensitiveOutput) {
175
177
  const error = await page.$(".alert-error");
176
178
  if (error) {
177
179
  debug("Found error message. Displaying");
178
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
179
- const errorMessage = await page.evaluate(
180
- // eslint-disable-next-line
181
- (err) => { var _a; return (_a = err === null || err === void 0 ? void 0 : err.textContent) !== null && _a !== void 0 ? _a : ""; }, error);
182
- console.log(errorMessage);
180
+ const errorMessage = await readTextContent(page, error);
181
+ printPageMessage(errorMessage, allowSensitiveOutput);
183
182
  defaultPassword = ""; // Password error. Unset the default and allow user to enter it.
184
183
  }
185
184
  let password;
@@ -189,7 +188,6 @@ exports.states = [
189
188
  }
190
189
  else {
191
190
  debug("Prompting user for password");
192
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
193
191
  ({ password } = await inquirer_1.default.prompt([
194
192
  {
195
193
  name: "password",
@@ -199,9 +197,13 @@ exports.states = [
199
197
  ]));
200
198
  }
201
199
  debug("Focusing on password input");
202
- await page.focus(`input[name="Password"],input[name="passwd"]`);
200
+ await page.focus(PASSWORD_SELECTOR);
201
+ debug("Clearing input");
202
+ await page.$eval(PASSWORD_SELECTOR, (el) => {
203
+ el.select();
204
+ });
205
+ await page.keyboard.press("Backspace");
203
206
  debug("Typing password");
204
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
205
207
  await page.keyboard.type(password);
206
208
  debug("Submitting form");
207
209
  await page.click("span[class=submit],input[type=submit]");
@@ -212,11 +214,9 @@ exports.states = [
212
214
  {
213
215
  name: "TFA instructions",
214
216
  selector: `#idDiv_SAOTCAS_Description`,
215
- async handler(page, selected) {
216
- const descriptionMessage = await page.evaluate(
217
- // eslint-disable-next-line
218
- (description) => { var _a; return (_a = description === null || description === void 0 ? void 0 : description.textContent) !== null && _a !== void 0 ? _a : ""; }, selected);
219
- console.log(descriptionMessage);
217
+ async handler(page, selected, _noPrompt, _defaultUsername, _defaultPassword, _rememberMe, allowSensitiveOutput) {
218
+ const descriptionMessage = await readTextContent(page, selected);
219
+ printPageMessage(descriptionMessage, allowSensitiveOutput);
220
220
  try {
221
221
  debug("Waiting for authentication code to be displayed");
222
222
  await page.waitForSelector("#idRichContext_DisplaySign", {
@@ -226,12 +226,9 @@ exports.states = [
226
226
  debug("Checking if authentication code is displayed");
227
227
  const authenticationCodeElement = await page.$("#idRichContext_DisplaySign");
228
228
  debug("Reading the authentication code");
229
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
230
- const authenticationCode = await page.evaluate(
231
- // eslint-disable-next-line
232
- (d) => { var _a; return (_a = d === null || d === void 0 ? void 0 : d.textContent) !== null && _a !== void 0 ? _a : ""; }, authenticationCodeElement);
229
+ const authenticationCode = await readTextContent(page, authenticationCodeElement);
233
230
  debug("Printing the authentication code to console");
234
- console.log(authenticationCode);
231
+ printPageMessage(authenticationCode, allowSensitiveOutput);
235
232
  }
236
233
  catch (_a) {
237
234
  debug("No authentication code found on page");
@@ -246,36 +243,26 @@ exports.states = [
246
243
  {
247
244
  name: "TFA failed",
248
245
  selector: `#idDiv_SAASDS_Description,#idDiv_SAASTO_Description`,
249
- async handler(page, selected) {
250
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
251
- const descriptionMessage = await page.evaluate(
252
- // eslint-disable-next-line
253
- (description) => { var _a; return (_a = description === null || description === void 0 ? void 0 : description.textContent) !== null && _a !== void 0 ? _a : ""; }, selected);
254
- throw new CLIError_1.CLIError(descriptionMessage);
246
+ async handler(page, selected, _noPrompt, _defaultUsername, _defaultPassword, _rememberMe, allowSensitiveOutput) {
247
+ const descriptionMessage = await readTextContent(page, selected);
248
+ throw createSensitiveCliError(descriptionMessage, "Authentication failed during MFA challenge.", allowSensitiveOutput);
255
249
  },
256
250
  },
257
251
  {
258
252
  name: "TFA code input",
259
253
  selector: "input[name=otc]:not(.moveOffScreen)",
260
- async handler(page) {
254
+ async handler(page, _selected, _noPrompt, _defaultUsername, _defaultPassword, _rememberMe, allowSensitiveOutput) {
261
255
  const error = await page.$(".alert-error");
262
256
  if (error) {
263
257
  debug("Found error message. Displaying");
264
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
265
- const errorMessage = await page.evaluate(
266
- // eslint-disable-next-line
267
- (err) => { var _a; return (_a = err === null || err === void 0 ? void 0 : err.textContent) !== null && _a !== void 0 ? _a : ""; }, error);
268
- console.log(errorMessage);
258
+ const errorMessage = await readTextContent(page, error);
259
+ printPageMessage(errorMessage, allowSensitiveOutput);
269
260
  }
270
261
  else {
271
262
  const description = await page.$("#idDiv_SAOTCC_Description");
272
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
273
- const descriptionMessage = await page.evaluate(
274
- // eslint-disable-next-line
275
- (d) => { var _a; return (_a = d === null || d === void 0 ? void 0 : d.textContent) !== null && _a !== void 0 ? _a : ""; }, description);
276
- console.log(descriptionMessage);
263
+ const descriptionMessage = await readTextContent(page, description);
264
+ printPageMessage(descriptionMessage, allowSensitiveOutput);
277
265
  }
278
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
279
266
  const { verificationCode } = await inquirer_1.default.prompt([
280
267
  {
281
268
  type: "input",
@@ -291,7 +278,6 @@ exports.states = [
291
278
  });
292
279
  await page.keyboard.press("Backspace");
293
280
  debug("Typing verification code");
294
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
295
281
  await page.keyboard.type(verificationCode);
296
282
  debug("Submitting form");
297
283
  await page.click("input[type=submit]");
@@ -327,12 +313,9 @@ exports.states = [
327
313
  {
328
314
  name: "Service exception",
329
315
  selector: "#service_exception_message",
330
- async handler(page, selected) {
331
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
332
- const descriptionMessage = await page.evaluate(
333
- // eslint-disable-next-line
334
- (description) => { var _a; return (_a = description === null || description === void 0 ? void 0 : description.textContent) !== null && _a !== void 0 ? _a : ""; }, selected);
335
- throw new CLIError_1.CLIError(descriptionMessage);
316
+ async handler(page, selected, _noPrompt, _defaultUsername, _defaultPassword, _rememberMe, allowSensitiveOutput) {
317
+ const descriptionMessage = await readTextContent(page, selected);
318
+ throw createSensitiveCliError(descriptionMessage, "Login provider returned a service exception.", allowSensitiveOutput);
336
319
  },
337
320
  },
338
321
  ];
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.shouldAllowSensitiveOutput = shouldAllowSensitiveOutput;
4
+ exports.redactUrlForLogs = redactUrlForLogs;
5
+ exports.sanitizeMessage = sanitizeMessage;
6
+ exports.formatCliErrorMessage = formatCliErrorMessage;
7
+ exports.formatUnexpectedErrorMessage = formatUnexpectedErrorMessage;
8
+ exports.formatDebugErrorMessage = formatDebugErrorMessage;
9
+ const REDACTED = "[redacted]";
10
+ const SAFE_MICROSOFT_LOGIN_PATH_SEGMENTS = new Set([
11
+ "common",
12
+ "consumers",
13
+ "organizations",
14
+ "favicon.ico",
15
+ "kmsi",
16
+ ]);
17
+ const URL_PATTERN = /\bhttps?:\/\/[^\s"'`<>]+/gi;
18
+ const AWS_ACCESS_KEY_ID_PATTERN = /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g;
19
+ const SENSITIVE_FIELD_NAMES = [
20
+ "AZURE_DEFAULT_PASSWORD",
21
+ "password",
22
+ "aws_access_key_id",
23
+ "aws_secret_access_key",
24
+ "aws_session_token",
25
+ "AccessKeyId",
26
+ "SecretAccessKey",
27
+ "SessionToken",
28
+ "SAMLAssertion",
29
+ "SAMLResponse",
30
+ "Authorization",
31
+ "Cookie",
32
+ "Set-Cookie",
33
+ ];
34
+ const SENSITIVE_ASSIGNMENT_PATTERN = new RegExp(`((?:${SENSITIVE_FIELD_NAMES.join("|")})\\s*[=:]\\s*)(?:"[^"]*"|'[^']*'|.+)`, "gi");
35
+ const SENSITIVE_JSON_PATTERN = new RegExp(`((?:"(?:${SENSITIVE_FIELD_NAMES.join("|")})"\\s*:\\s*))(?:"[^"]*"|null|[^\\s,}]+)`, "gi");
36
+ function shouldAllowSensitiveOutput(env = process.env) {
37
+ return !env.CI && !env.GITHUB_ACTIONS;
38
+ }
39
+ function redactUrlForLogs(url) {
40
+ try {
41
+ const parsedUrl = new URL(url);
42
+ const pathSegments = parsedUrl.pathname.split("/");
43
+ if (parsedUrl.hostname === "login.microsoftonline.com" &&
44
+ pathSegments[1] &&
45
+ !SAFE_MICROSOFT_LOGIN_PATH_SEGMENTS.has(pathSegments[1])) {
46
+ pathSegments[1] = REDACTED;
47
+ parsedUrl.pathname = pathSegments.join("/");
48
+ }
49
+ if (parsedUrl.username || parsedUrl.password) {
50
+ parsedUrl.username = REDACTED;
51
+ parsedUrl.password = REDACTED;
52
+ }
53
+ for (const key of new Set(parsedUrl.searchParams.keys())) {
54
+ parsedUrl.searchParams.set(key, REDACTED);
55
+ }
56
+ if (parsedUrl.hash) {
57
+ parsedUrl.hash = REDACTED;
58
+ }
59
+ return parsedUrl.toString();
60
+ }
61
+ catch (_a) {
62
+ const questionMarkIndex = url.indexOf("?");
63
+ if (questionMarkIndex === -1) {
64
+ return url;
65
+ }
66
+ return `${url.slice(0, questionMarkIndex)}?${REDACTED}`;
67
+ }
68
+ }
69
+ function sanitizeMessage(message) {
70
+ return message
71
+ .replace(URL_PATTERN, (url) => redactUrlForLogs(url))
72
+ .replace(AWS_ACCESS_KEY_ID_PATTERN, REDACTED)
73
+ .replace(SENSITIVE_ASSIGNMENT_PATTERN, `$1${REDACTED}`)
74
+ .replace(SENSITIVE_JSON_PATTERN, `$1"${REDACTED}"`);
75
+ }
76
+ function formatCliErrorMessage(message, env = process.env) {
77
+ return shouldAllowSensitiveOutput(env) ? message : sanitizeMessage(message);
78
+ }
79
+ function formatUnexpectedErrorMessage(error, env = process.env) {
80
+ const message = error instanceof Error ? error.message : String(error);
81
+ return shouldAllowSensitiveOutput(env) ? message : sanitizeMessage(message);
82
+ }
83
+ function formatDebugErrorMessage(error, env = process.env) {
84
+ return formatUnexpectedErrorMessage(error, env);
85
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sessionDurationHoursValidationMessage = void 0;
4
+ exports.parseSessionDurationHours = parseSessionDurationHours;
5
+ exports.validateSessionDurationHours = validateSessionDurationHours;
6
+ exports.sessionDurationHoursValidationMessage = "Duration hours must be a whole number between 1 and 12";
7
+ function parseSessionDurationHours(input) {
8
+ if (input === undefined) {
9
+ return null;
10
+ }
11
+ if (typeof input === "number") {
12
+ return Number.isInteger(input) && input > 0 && input <= 12 ? input : null;
13
+ }
14
+ const trimmed = input.trim();
15
+ if (!/^\d+$/.test(trimmed)) {
16
+ return null;
17
+ }
18
+ const parsed = Number(trimmed);
19
+ return parsed > 0 && parsed <= 12 ? parsed : null;
20
+ }
21
+ function validateSessionDurationHours(input) {
22
+ // Inquirer types `validate` input as string, but it may validate a numeric
23
+ // `default` value before coercing it to user input.
24
+ return parseSessionDurationHours(input) === null
25
+ ? exports.sessionDurationHoursValidationMessage
26
+ : true;
27
+ }
@@ -13,12 +13,19 @@ const CACHE_TTL_MS = 1000 * 60 * 60 * 24; // 24 hours
13
13
  const FAKE_LATEST_VERSION_ENV = "AZ2AWS_FAKE_LATEST_VERSION";
14
14
  const ANSI_YELLOW = "\u001b[33m";
15
15
  const ANSI_RESET = "\u001b[0m";
16
- function getCachePath() {
17
- return path_1.default.join(os_1.default.homedir(), ".config", "az2aws", "update-check.json");
16
+ const CONFIG_DIR_MODE = 0o700;
17
+ const CACHE_FILE_MODE = 0o600;
18
+ function getCachePath(env = process.env) {
19
+ var _a, _b;
20
+ if (process.platform === "win32") {
21
+ const cacheRoot = ((_a = env.LOCALAPPDATA) === null || _a === void 0 ? void 0 : _a.trim()) || ((_b = env.APPDATA) === null || _b === void 0 ? void 0 : _b.trim()) || os_1.default.homedir();
22
+ return path_1.default.win32.join(cacheRoot, PACKAGE_NAME, "update-check.json");
23
+ }
24
+ return path_1.default.join(os_1.default.homedir(), ".config", PACKAGE_NAME, "update-check.json");
18
25
  }
19
- function readCache() {
26
+ function readCache(env = process.env) {
20
27
  try {
21
- const data = fs_1.default.readFileSync(getCachePath(), "utf-8");
28
+ const data = fs_1.default.readFileSync(getCachePath(env), "utf-8");
22
29
  const cache = JSON.parse(data);
23
30
  if (Date.now() - cache.checkedAt < CACHE_TTL_MS) {
24
31
  return cache;
@@ -29,12 +36,19 @@ function readCache() {
29
36
  }
30
37
  return null;
31
38
  }
32
- function writeCache(latestVersion) {
39
+ function writeCache(latestVersion, env = process.env) {
33
40
  try {
34
- const cachePath = getCachePath();
35
- const dir = path_1.default.dirname(cachePath);
36
- fs_1.default.mkdirSync(dir, { recursive: true });
37
- fs_1.default.writeFileSync(cachePath, JSON.stringify({ latestVersion, checkedAt: Date.now() }));
41
+ const cachePath = getCachePath(env);
42
+ const pathModule = process.platform === "win32" ? path_1.default.win32 : path_1.default;
43
+ const dir = pathModule.dirname(cachePath);
44
+ fs_1.default.mkdirSync(dir, { recursive: true, mode: CONFIG_DIR_MODE });
45
+ if (process.platform !== "win32") {
46
+ fs_1.default.chmodSync(dir, CONFIG_DIR_MODE);
47
+ }
48
+ fs_1.default.writeFileSync(cachePath, JSON.stringify({ latestVersion, checkedAt: Date.now() }), { mode: CACHE_FILE_MODE });
49
+ if (process.platform !== "win32") {
50
+ fs_1.default.chmodSync(cachePath, CACHE_FILE_MODE);
51
+ }
38
52
  }
39
53
  catch (_a) {
40
54
  // Ignore cache write failures
@@ -126,13 +140,13 @@ async function checkForUpdate(currentVersion, options = {}) {
126
140
  latestVersion = forcedLatestVersion;
127
141
  }
128
142
  else {
129
- const cache = readCache();
143
+ const cache = readCache(env);
130
144
  if (cache) {
131
145
  latestVersion = cache.latestVersion;
132
146
  }
133
147
  else {
134
148
  latestVersion = await fetchLatestVersion();
135
- writeCache(latestVersion);
149
+ writeCache(latestVersion, env);
136
150
  }
137
151
  }
138
152
  if (compareVersions(currentVersion, latestVersion) > 0) {
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.validateCliOptions = validateCliOptions;
4
+ const CLIError_1 = require("./CLIError");
5
+ function validateCliOptions(options) {
6
+ if (options.allProfiles && options.credentialProcess) {
7
+ throw new CLIError_1.CLIError("--credential-process cannot be used with --all-profiles.");
8
+ }
9
+ if (options.configure && options.credentialProcess) {
10
+ throw new CLIError_1.CLIError("--credential-process cannot be used with --configure.");
11
+ }
12
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "az2aws",
3
- "version": "1.6.2",
3
+ "version": "1.7.0",
4
4
  "description": "Use Azure AD SSO to log into the AWS CLI. A modern, actively maintained alternative to aws-azure-login.",
5
5
  "main": "lib/index.js",
6
6
  "author": {
@@ -44,6 +44,8 @@
44
44
  "puppeteer"
45
45
  ],
46
46
  "overrides": {
47
+ "basic-ftp@<5.2.1": "5.2.2",
48
+ "brace-expansion@<1.1.13": "1.1.13",
47
49
  "yauzl@<3.2.1": "3.2.1"
48
50
  }
49
51
  },
@@ -58,6 +60,7 @@
58
60
  "prettier:write": "prettier --write \"src/**/*.{ts,json}\"",
59
61
  "prettier:check": "prettier --check \"src/**/*.ts\"",
60
62
  "test": "vitest run",
63
+ "test:e2e": "vitest run --config vitest.e2e.config.ts",
61
64
  "test:watch": "vitest",
62
65
  "test:coverage": "vitest run --coverage",
63
66
  "lint": "pnpm eslint && pnpm prettier:check"