switch-profile 1.1.0 → 2.0.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.
package/src/aws/index.js DELETED
@@ -1,574 +0,0 @@
1
- const { error: { catchErrors, wrapErrors }, promise: { delay } } = require('puffy')
2
- const { homedir, EOL } = require('os')
3
- const { join } = require('path')
4
- const { exec, isCommandExist } = require('../core')
5
- const { spawn } = require('child_process')
6
- const fileHelper = require('../fileHelper')
7
- const regions = require('./regions')
8
-
9
- const IS_WINDOWS = process.platform === 'win32'
10
- const LINE_SEP = IS_WINDOWS ? /\r?\n/ : EOL
11
- const NL = IS_WINDOWS ? '\n' : EOL
12
- const SSO_GET_CREDS_TIMEOUT = 5*60*1000 // 5 minutes to complete the SSO login
13
- const AWS_CONFIG_FILE = join(homedir(), '.aws', 'config')
14
- const AWS_CREDS_FILE = join(homedir(), '.aws', 'credentials')
15
- const AWS_SSO_FOLDER = join(homedir(), '.aws', 'sso', 'cache')
16
- const AWS_CLI_FOLDER = join(homedir(), '.aws', 'cli', 'cache')
17
- const DEFAULT_CONFIG =
18
- `[default]
19
- region = ap-southeast-1
20
- output = json
21
-
22
- `
23
- const DEFAULT_CREDS =
24
- `[default]
25
- aws_access_key_id = 1234_DUMMY
26
- aws_secret_access_key = 4567_DUMMY
27
-
28
- `
29
-
30
- const awsExists = isCommandExist('aws')
31
- const awsCliV2Exists = noFailIfMissing => catchErrors((async () => {
32
- const [awsCliErrors] = await awsExists()
33
- if (awsCliErrors) {
34
- if (noFailIfMissing)
35
- return false
36
- throw wrapErrors('AWS CLI error', awsCliErrors)
37
- }
38
-
39
- try {
40
- const data = await exec('aws --version') || ''
41
- const [majorVersion] = ((data.match(/aws-cli\/(.*?)\s/g)||[])[0]||'').replace('aws-cli/','').split('.')
42
- const version = majorVersion*1
43
- if (isNaN(version))
44
- throw new Error('Fail to test the AWS CLI version. Please try to run "aws --version" manually to try to debug this issue.')
45
- if (version <= 1)
46
- throw new Error(`AWS CLI version ${version} is not supported. Please upgrade to AWS CLI v2 or greater.`)
47
-
48
- return true
49
- } catch(err) {
50
- throw wrapErrors('Fail to check AWS CLI\'s version', [err])
51
- }
52
- })())
53
-
54
- const getParam = (params, paramName) => {
55
- if (!params || !params.length || !paramName)
56
- return null
57
-
58
- const regexp = new RegExp(`\\s*${paramName}\\s*=\\s*`)
59
- return params.filter(p => regexp.test(p)).map(p => p.replace(regexp,'').trim())[0]
60
- }
61
-
62
- const getCredsFile = () => catchErrors((async () => {
63
- const credsExist = await fileHelper.exists(AWS_CREDS_FILE)
64
- if (!credsExist)
65
- return ''
66
- const credsStr = (await fileHelper.read(AWS_CREDS_FILE) || '').toString()
67
-
68
- return credsStr
69
- })())
70
-
71
- const getConfigFile = () => catchErrors((async () => {
72
- const credsExist = await fileHelper.exists(AWS_CONFIG_FILE)
73
- if (!credsExist)
74
- return ''
75
- const credsStr = (await fileHelper.read(AWS_CONFIG_FILE) || '').toString()
76
-
77
- return credsStr
78
- })())
79
-
80
- /**
81
- * Gets all the profiles stored in the ~/.aws/config file.
82
- *
83
- * @return {[Error]}
84
- * @return {String} profiles[].name e.g., 'hello'
85
- * @return {String} profiles[].friendlyName e.g., 'hello (SSO [role:"god" account:1234])'
86
- * @return {String} profiles[].region e.g., 'us-weat-1'
87
- * @return {String} profiles[].output e.g., 'json'
88
- * @return {String} profiles[].sso_start_url e.g., 'https://cloudless.awsapps.com/start'
89
- * @return {String} profiles[].sso_region e.g., 'us-weat-1'
90
- * @return {String} profiles[].sso_account_id e.g., '1234'
91
- * @return {String} profiles[].sso_role_name e.g., 'god'
92
- */
93
- const listProfiles = () => catchErrors((async () => {
94
- await awsCliV2Exists()
95
- const [configStrErrors, configStr] = await getConfigFile()
96
- if (configStrErrors)
97
- throw wrapErrors('Fail to list AWS profiles', configStrErrors)
98
-
99
- if (!configStr)
100
- return []
101
-
102
- const profiles = configStr.match(/\[(.*?)\]/g)
103
- return profiles.map(profile => {
104
- const [,rest=''] = configStr.split(profile)
105
- const [config=''] = rest.split('[')
106
- const params = config.split(LINE_SEP)
107
- const p = {
108
- name: profile.replace(/(^\[profile\s+|\[|\])/g, ''),
109
- sso_start_url: getParam(params, 'sso_start_url'),
110
- sso_region: getParam(params, 'sso_region'),
111
- sso_account_id: getParam(params, 'sso_account_id'),
112
- sso_role_name: getParam(params, 'sso_role_name'),
113
- sso_session: getParam(params, 'sso_session'),
114
- region: getParam(params, 'region'),
115
- output: getParam(params, 'output')
116
- }
117
-
118
- // Handle newer AWS CLI v2 SSO session format where sso_start_url is in a separate [sso-session] section
119
- if (p.sso_session && !p.sso_start_url) {
120
- const ssoSessionSection = `[sso-session ${p.sso_session}]`
121
- const ssoSessionMatch = configStr.split(ssoSessionSection)
122
- if (ssoSessionMatch.length > 1) {
123
- const [ssoSessionRest=''] = ssoSessionMatch[1].split('[')
124
- const ssoSessionParams = ssoSessionRest.split(LINE_SEP)
125
- p.sso_start_url = getParam(ssoSessionParams, 'sso_start_url')
126
- // If sso_region is not in profile, check the session section
127
- if (!p.sso_region) {
128
- p.sso_region = getParam(ssoSessionParams, 'sso_region')
129
- }
130
- }
131
- }
132
-
133
- if (p.sso_region)
134
- p.region = p.sso_region
135
-
136
- p.friendlyName = `${p.name}${p.sso_start_url ? ` (SSO [role:${p.sso_role_name||'unknown'} - account:${p.sso_account_id||'unknown'}])` : ''}`
137
-
138
- return p
139
- }).filter(p => p.name != 'default' && !p.name.startsWith('sso-session '))
140
- })())
141
-
142
- /**
143
- * Gets the session details associated with this 'ssoUrl' from the local folder '.aws/sso/cache/'.
144
- * If the session exists but has expired, null is returned.
145
- *
146
- * @param {String} ssoUrl e.g., 'https://cloudless.awsapps.com/start'
147
- *
148
- * @return {[Error]}
149
- * @return {String} session.startUrl e.g., 'https://cloudless.awsapps.com/start'
150
- * @return {String} session.region e.g., 'ap-southeast-2'
151
- * @return {String} session.accessToken e.g., 'dwqdwdwqd...dwqdqw'
152
- * @return {String} session.expiresAt e.g., '2021-07-17T11:33:12Z'
153
- */
154
- const getSsoSession = ssoUrl => catchErrors((async () => {
155
- const ssoHost = new URL(ssoUrl).host
156
- if (!ssoHost)
157
- throw new Error(`The SSO portal URL ${ssoUrl} is not a valid URL.`)
158
-
159
- const ssoFolderExists = await fileHelper.exists(AWS_SSO_FOLDER)
160
- if (!ssoFolderExists)
161
- throw new Error(`AWS SSO folder ${AWS_SSO_FOLDER} not found.`)
162
- const files = await fileHelper.list(AWS_SSO_FOLDER, { pattern:'*.json' })
163
- if (!files || !files.length)
164
- throw new Error(`AWS SSO folder ${AWS_SSO_FOLDER} contains no credentials.`)
165
- let creds = null
166
- for (let i=0;i<files.length;i++) {
167
- const _creds = await fileHelper.json.get(files[i])
168
- if (_creds.startUrl && _creds.expiresAt) {
169
- const credHost = new URL(_creds.startUrl).host
170
- const credStillValid = (Date.now() - 2*60*1000) < new Date(_creds.expiresAt).getTime()
171
- if (credHost == ssoHost && credStillValid && _creds.accessToken) {
172
- creds = _creds
173
- continue
174
- }
175
- }
176
- }
177
-
178
- return creds
179
- })())
180
-
181
- /**
182
- * Gets the credentials details associated with the 'access_key_end' and 'secret_key_end' from the local folder '.aws/cli/cache/'.
183
- * We need this function because unfortunatelly, the 'aws configure list' does not output the details in full. Instead, it stores
184
- * them in the cache file.
185
- *
186
- * @param {String} access_key_end e.g., '1234'
187
- * @param {String} secret_key_end e.g., '5678'
188
- *
189
- * @return {[Error]}
190
- * @return {String} session.aws_access_key_id e.g., '********1234'
191
- * @return {String} session.aws_secret_access_key e.g., '********5678'
192
- * @return {String} session.aws_session_token e.g., 'dwqdwdwqd...dwqdqw'
193
- * @return {Date} session.expiry_date e.g., 2021-07-17T11:33:12Z
194
- */
195
- const getSsoCredsFromCacheFile = (access_key_end, secret_key_end) => catchErrors((async () => {
196
- const errMsg = `Fail to get the local CLI credentials from folder ${AWS_CLI_FOLDER}`
197
- if (!access_key_end)
198
- throw wrapErrors(errMsg, [new Error('Missing required argument \'access_key_end\'.')])
199
- if (!secret_key_end)
200
- throw wrapErrors(errMsg, [new Error('Missing required argument \'secret_key_end\'.')])
201
-
202
- const folderExists = await fileHelper.exists(AWS_CLI_FOLDER)
203
- if (!folderExists)
204
- return null
205
- const files = await fileHelper.list(AWS_CLI_FOLDER, { pattern:'*.json' })
206
- if (!files || !files.length)
207
- return null
208
-
209
- for (let i=0;i<files.length;i++) {
210
- const _creds = await fileHelper.json.get(files[i])
211
-
212
- // Creds must be SSO
213
- if (!_creds || _creds.ProviderType != 'sso' || !_creds.Credentials)
214
- continue
215
-
216
- // Creds must still be valid for the next 2 minutes
217
- if (_creds.Credentials.Expiration && (Date.now() - 2*60*1000) < new Date(_creds.Credentials.Expiration).getTime()) {
218
- const credsMatch = (_creds.Credentials.AccessKeyId||'').slice(-4) == access_key_end &&
219
- (_creds.Credentials.SecretAccessKey||'').slice(-4) == secret_key_end
220
-
221
- if (credsMatch)
222
- return {
223
- aws_access_key_id: _creds.Credentials.AccessKeyId,
224
- aws_secret_access_key: _creds.Credentials.SecretAccessKey,
225
- aws_session_token: _creds.Credentials.SessionToken,
226
- expiry_date: new Date(_creds.Credentials.Expiration)
227
- }
228
- }
229
- }
230
-
231
- return null
232
- })())
233
-
234
- /**
235
- * Gets SSO credentials. It executes the 'aws configure list --profile <PROFILE>' command, which
236
- * checks the local cache first (i.e., '~/.aws/cli/cache'). If that cache for that profile does not exist or if it
237
- * is expired, it goes to AWS to fetch new ones and refresh the cache.
238
- *
239
- * @param {String} profile e.g., 'sso-dev-cloudless'
240
- *
241
- * @return {[Error]}
242
- * @return {String} session.aws_access_key_id e.g., '********1234'
243
- * @return {String} session.aws_secret_access_key e.g., '********5678'
244
- * @return {String} session.aws_session_token e.g., 'dwqdwdwqd...dwqdqw'
245
- * @return {Date} session.expiry_date e.g., 2021-07-17T11:33:12Z
246
- */
247
- const getSsoCredentials = profile => catchErrors((async () => {
248
- await awsCliV2Exists()
249
- const errMsg = `Fail to get AWS SSO credentials for profile ${profile}`
250
- try {
251
- if (!profile)
252
- throw wrapErrors(errMsg, [new Error('Missing required \'profile\' argument')])
253
- const data = await exec(`aws configure list --profile ${profile}`) || ''
254
- const access_key_end = ((data.match(/access_key\s*\*+.{4}/g)||[])[0]||'').slice(-4)
255
- const secret_key_end = ((data.match(/secret_key\s*\*+.{4}/g)||[])[0]||'').slice(-4)
256
-
257
- if (!access_key_end || !secret_key_end)
258
- return null
259
-
260
- const [ssoCredsErrors, creds] = await getSsoCredsFromCacheFile(access_key_end, secret_key_end)
261
-
262
- if (ssoCredsErrors)
263
- throw wrapErrors(errMsg, ssoCredsErrors)
264
- return creds
265
- } catch(err) {
266
- throw wrapErrors(errMsg, [err])
267
- }
268
- })())
269
-
270
- const isSSOexpired = ssoSession => {
271
- if (!ssoSession)
272
- return true
273
-
274
- return (new Date(ssoSession.expiresAt).getTime() - Date.now()) < (2*60*1000)
275
- }
276
-
277
- /**
278
- * Makes sure the profile is using a valid (i.e., exists and not expired) local SSO session. If not, try
279
- * to create one manually by redirecting the user to the SSO page.
280
- *
281
- * @param {String} profile e.g., 'sso-dev-cloudless'
282
- * @param {String} ssoUrl e.g., 'https://cloudless.awsapps.com/start'
283
- * @param {Boolean} options.force
284
- *
285
- * @return {[Error]}
286
- * @return {String} session.aws_access_key_id e.g., '********1234'
287
- * @return {String} session.aws_secret_access_key e.g., '********5678'
288
- * @return {String} session.aws_session_token e.g., 'dwqdwdwqd...dwqdqw'
289
- * @return {Date} session.expiry_date e.g., 2021-07-17T11:33:12Z
290
- */
291
- const refreshSsoSession = (profile, ssoUrl, options) => catchErrors((async () => {
292
- const errMsg = `Fail to refresh the SSO session for AWS profile ${profile}`
293
- let [ssoSessionErrors, ssoSession] = await getSsoSession(ssoUrl)
294
- if (ssoSessionErrors)
295
- throw wrapErrors(errMsg, ssoSessionErrors)
296
-
297
- const { force } = options || {}
298
-
299
- try {
300
- // No valid SSO session found. Manually get a new one via the SSO portal
301
- const startTime = Date.now()
302
- if (force || isSSOexpired(ssoSession)) {
303
- await exec(`aws sso login --profile ${profile}`)
304
- while (!ssoSession && Date.now() - startTime < SSO_GET_CREDS_TIMEOUT) {
305
- const resp = await getSsoSession(ssoUrl)
306
- if (resp[0])
307
- throw wrapErrors(errMsg, resp[0])
308
- ssoSession = resp[1]
309
- if (!ssoSession)
310
- await delay(2000)
311
- }
312
- }
313
-
314
- if (ssoSession)
315
- return ssoSession
316
- else if (Date.now() - startTime > SSO_GET_CREDS_TIMEOUT)
317
- throw wrapErrors(errMsg, [new Error(`Timeout - Time to wait for refreshing the SSO session for profile ${profile} exceeded ${SSO_GET_CREDS_TIMEOUT}ms.`)])
318
- else
319
- return null
320
- } catch(err) {
321
- throw wrapErrors(errMsg, [err])
322
- }
323
- })())
324
-
325
- /**
326
- * Gets the AWS credentials for a specific profile. If that profile is an SSO profile, this function has a series of
327
- * side-effects:
328
- * - If the local SSO session stored under ~/.aws/sso/cache has expired, then it will redirect the user to the SSO portal and eventually refresh that ~/.aws/sso/cache.
329
- * - If the local SSO creds stored under ~/.aws/cli/cache have expired (AWS_KEY, AWS_SECRET, AWS_SESSION), then they will be refreshed using the session stored under the ~/.aws/sso/cache.
330
- *
331
- * @param {String} profile e.g., 'sso-dev-cloudless'
332
- * @param {String} ssoUrl e.g., 'https://cloudless.awsapps.com/start'
333
- *
334
- * @return {[Error]}
335
- * @return {String} creds.aws_access_key_id e.g., '********1234'
336
- * @return {String} creds.aws_secret_access_key e.g., '********5678'
337
- * @return {String} creds.aws_session_token e.g., 'dwqdwdwqd...dwqdqw'
338
- * @return {Date} creds.expiry_date e.g., 2021-07-17T11:33:12Z
339
- */
340
- const getCredentials = (profile, ssoUrl) => catchErrors((async () => {
341
- await awsCliV2Exists()
342
- const errMsg = `Fail to get AWS credentials for profile ${profile}`
343
- if (ssoUrl) {
344
- await refreshSsoSession(profile, ssoUrl)
345
- let [ssoCredsErrors, ssoCreds] = await getSsoCredentials(profile)
346
- if (ssoCredsErrors) {
347
- const ssoSessionIsInvalid = ssoCredsErrors.some(e => e.message && e.message.toLowerCase().indexOf('session associated with this profile has expired') >= 0)
348
- if (ssoSessionIsInvalid) {
349
- await refreshSsoSession(profile, ssoUrl, { force:true })
350
- const resp = await getSsoCredentials(profile)
351
- if (resp[0])
352
- throw wrapErrors(errMsg, resp[0])
353
-
354
- ssoCreds = resp[1]
355
- } else
356
- throw wrapErrors(errMsg, ssoCredsErrors)
357
- }
358
-
359
- if (!ssoCreds) {
360
- try {
361
- const data = await exec(`aws configure export-credentials --profile ${profile} --format process`)
362
- const parsed = JSON.parse(data)
363
- if (parsed.AccessKeyId && parsed.SecretAccessKey) {
364
- ssoCreds = {
365
- aws_access_key_id: parsed.AccessKeyId,
366
- aws_secret_access_key: parsed.SecretAccessKey,
367
- aws_session_token: parsed.SessionToken,
368
- expiry_date: parsed.Expiration ? new Date(parsed.Expiration) : null
369
- }
370
- }
371
- } catch(e) {
372
- // Fallback also failed
373
- }
374
- }
375
-
376
- if (!ssoCreds)
377
- throw new Error(errMsg)
378
-
379
- return ssoCreds
380
- } else {
381
- const [errors, credsStr] = await getCredsFile()
382
- if (errors)
383
- throw wrapErrors(errMsg, errors)
384
-
385
- const [, rest] = credsStr.split(`[${profile}]`)
386
- if (!rest)
387
- throw new Error(`Profile ${profile} not found in ${AWS_CREDS_FILE}. Standard profiles must have credentials defined in this file.`)
388
-
389
- const [config=''] = rest.split('[')
390
- const params = config.split(LINE_SEP)
391
- const creds = {
392
- aws_access_key_id: getParam(params, 'aws_access_key_id'),
393
- aws_secret_access_key: getParam(params, 'aws_secret_access_key'),
394
- aws_session_token: getParam(params, 'aws_session_token'),
395
- expiry_date: null
396
- }
397
-
398
- return creds
399
- }
400
- })())
401
-
402
-
403
- const updateDefaultProfile = ({ profile, region, expiry_date, aws_access_key_id, aws_secret_access_key, aws_session_token }) => catchErrors((async () => {
404
- const errMsg = `Fail to update the ${AWS_CREDS_FILE} file`
405
- const [configStrErrors, configStr] = await getConfigFile()
406
- const [credsStrErrors, credsStr] = await getCredsFile()
407
- if (credsStrErrors||configStrErrors)
408
- throw wrapErrors(errMsg, credsStrErrors||configStrErrors)
409
-
410
- const newDefaultCreds = '[default]'+NL+
411
- `aws_access_key_id = ${aws_access_key_id}`+NL+
412
- `aws_secret_access_key = ${aws_secret_access_key}`+NL+
413
- (aws_session_token ? `aws_session_token = ${aws_session_token}`+NL : '') +
414
- (expiry_date ? `expiry_date = ${expiry_date.toISOString()}`+NL : '') +
415
- `profile = ${profile}`+NL+NL
416
-
417
- const newDefaultConfig = '[default]'+NL+
418
- `region = ${region}`+NL+
419
- 'output = json'+NL+NL
420
-
421
- const defaultCredsSection = (credsStr.match(/\[default\]((.|\n|\r)*?)(\[|$)/)||[])[0]
422
- const defaultConfigSection = (configStr.match(/\[default\]((.|\n|\r)*?)(\[|$)/)||[])[0]
423
-
424
- let updatedCreds = ''
425
- if (defaultCredsSection) {
426
- const lastChar = defaultCredsSection.slice(-1)
427
- updatedCreds = credsStr.replace(defaultCredsSection, newDefaultCreds+lastChar)
428
- } else
429
- updatedCreds = newDefaultCreds + credsStr
430
-
431
- let updatedConfig = ''
432
- if (defaultConfigSection) {
433
- const lastChar = defaultConfigSection.slice(-1)
434
- updatedConfig = configStr.replace(defaultConfigSection, newDefaultConfig+lastChar)
435
- } else
436
- updatedConfig = newDefaultConfig + configStr
437
-
438
- await fileHelper.write(AWS_CREDS_FILE, updatedCreds)
439
- await fileHelper.write(AWS_CONFIG_FILE, updatedConfig)
440
- })())
441
-
442
- const getDefaultProfile = () => catchErrors((async () => {
443
- const errMsg = `Fail to get the default AWS profile in the ${AWS_CREDS_FILE} file.`
444
- const [errors, credsStr] = await getCredsFile()
445
- if (errors)
446
- throw wrapErrors(errMsg, errors)
447
-
448
- const params = ((credsStr.match(/\[default\]((.|\n|\r)*?)(\[|$)/)||[])[0]||'').split(LINE_SEP)
449
- const creds = {
450
- aws_access_key_id: getParam(params, 'aws_access_key_id'),
451
- aws_secret_access_key: getParam(params, 'aws_secret_access_key'),
452
- aws_session_token: getParam(params, 'aws_session_token'),
453
- expiry_date: getParam(params, 'expiry_date'),
454
- profile: getParam(params, 'profile')
455
- }
456
-
457
- return creds
458
- })())
459
-
460
- const deleteProfileFromConfig = (profile, fileContent) => {
461
- fileContent = fileContent || ''
462
- const regExp = new RegExp(`\\[(profile\\s){0,1}${profile}\\]((.|\\n|\\r)*?)(\\[|$)`)
463
- const profileMatch = (fileContent.match(regExp)||[])[0] || ''
464
-
465
- if (!profileMatch)
466
- return fileContent
467
-
468
- const lastChar = profileMatch.slice(-1)
469
- return fileContent.replace(profileMatch, lastChar)
470
- }
471
-
472
- const deleteProfileFromCreds = (profile, fileContent) => {
473
- fileContent = fileContent || ''
474
- const regExp = new RegExp(`\\[${profile}\\]((.|\\n|\\r)*?)(\\[|$)`)
475
- const profileMatch = (fileContent.match(regExp)||[])[0] || ''
476
-
477
- if (!profileMatch)
478
- return fileContent
479
-
480
- const lastChar = profileMatch.slice(-1)
481
- return fileContent.replace(profileMatch, lastChar)
482
- }
483
-
484
- const deleteProfiles = profiles => catchErrors((async () => {
485
- if (!profiles || !profiles.length)
486
- return
487
-
488
- const errMsg = 'Fail to delete AWS profiles'
489
-
490
- if (profiles.some(p => p == 'default'))
491
- throw wrapErrors(errMsg, [new Error('The \'default\' profile cannot be deleted.')])
492
-
493
- let [configStrErrors, configStr] = await getConfigFile()
494
- let [credsStrErrors, credsStr] = await getCredsFile()
495
-
496
- if (configStrErrors || credsStrErrors)
497
- throw wrapErrors(errMsg, configStrErrors || credsStrErrors)
498
-
499
- const updateConfig = configStr
500
- const updateCreds = credsStr
501
-
502
- for (let i=0;i<profiles.length;i++) {
503
- const profile = profiles[i]
504
- configStr = deleteProfileFromConfig(profile, configStr)
505
- credsStr = deleteProfileFromCreds(profile, credsStr)
506
- }
507
-
508
- if (updateConfig)
509
- await fileHelper.write(AWS_CONFIG_FILE, configStr)
510
- if (updateCreds)
511
- await fileHelper.write(AWS_CREDS_FILE, credsStr)
512
- })())
513
-
514
- const createProfile = ({ name, aws_access_key_id, aws_secret_access_key, region }) => catchErrors((async () => {
515
- await awsCliV2Exists()
516
-
517
- const errMsg = 'Fail to create AWS profile'
518
- if (!name)
519
- throw wrapErrors(errMsg, [new Error('Missing required argument \'name\'.')])
520
- if (!region)
521
- throw wrapErrors(errMsg, [new Error('Missing required argument \'region\'.')])
522
- if (!aws_access_key_id)
523
- throw wrapErrors(errMsg, [new Error('Missing required argument \'aws_access_key_id\'.')])
524
- if (!aws_secret_access_key)
525
- throw wrapErrors(errMsg, [new Error('Missing required argument \'aws_secret_access_key\'.')])
526
-
527
- let [configStrErrors, configStr] = await getConfigFile()
528
- let [credsStrErrors, credsStr] = await getCredsFile()
529
- if (configStrErrors||credsStrErrors)
530
- throw wrapErrors(errMsg, configStrErrors||credsStrErrors)
531
-
532
- const configProfiles = [`[profile ${name}]`+NL]
533
- const credsProfiles = [`[${name}]`+NL]
534
-
535
- credsProfiles.push(`aws_access_key_id = ${aws_access_key_id}`+NL)
536
- credsProfiles.push(`aws_secret_access_key = ${aws_secret_access_key}`+NL+NL)
537
-
538
- configProfiles.push(`region = ${region}`+NL)
539
- configProfiles.push('output = json'+NL+NL)
540
-
541
- const newCreds = credsProfiles.join('')
542
- const newConfig = configProfiles.join('')
543
-
544
- if (!configStr)
545
- configStr = DEFAULT_CONFIG
546
- if (!credsStr)
547
- credsStr = DEFAULT_CREDS
548
-
549
- await fileHelper.write(AWS_CONFIG_FILE, configStr+NL+newConfig)
550
- await fileHelper.write(AWS_CREDS_FILE, credsStr+NL+newCreds)
551
- })())
552
-
553
- const createSsoProfile = name => catchErrors((async () => {
554
- await awsCliV2Exists()
555
- const exitCode = await new Promise(next => {
556
- const child = spawn('aws', ['configure', 'sso', '--profile', name], { stdio: 'inherit', ...(IS_WINDOWS ? { shell: true } : {}) })
557
- child.on('exit', code => next(code))
558
- })
559
- if (exitCode !== 0)
560
- throw new Error(`'aws configure sso' exited with code ${exitCode}. The SSO profile may not have been created correctly.`)
561
- })())
562
-
563
- module.exports = {
564
- listProfiles,
565
- getCredentials,
566
- getDefaultProfile,
567
- updateDefaultProfile,
568
- deleteProfiles,
569
- createProfile,
570
- createSsoProfile,
571
- regions,
572
- awsCliV2Exists
573
- }
574
-
@@ -1,103 +0,0 @@
1
- module.exports = [
2
- {
3
- name: 'US East (Ohio)',
4
- code: 'us-east-2'
5
- },
6
- {
7
- name: 'US East (N. Virginia)',
8
- code: 'us-east-1'
9
- },
10
- {
11
- name: 'US West (N. California)',
12
- code: 'us-west-1'
13
- },
14
- {
15
- name: 'US West (Oregon)',
16
- code: 'us-west-2'
17
- },
18
- {
19
- name: 'Africa (Cape Town)',
20
- code: 'af-south-1'
21
- },
22
- {
23
- name: 'Asia Pacific (Hong Kong)',
24
- code: 'ap-east-1'
25
- },
26
- {
27
- name: 'Asia Pacific (Mumbai)',
28
- code: 'ap-south-1'
29
- },
30
- {
31
- name: 'Asia Pacific (Osaka-Local)',
32
- code: 'ap-northeast-3'
33
- },
34
- {
35
- name: 'Asia Pacific (Seoul)',
36
- code: 'ap-northeast-2'
37
- },
38
- {
39
- name: 'Asia Pacific (Singapore)',
40
- code: 'ap-southeast-1'
41
- },
42
- {
43
- name: 'Asia Pacific (Sydney)',
44
- code: 'ap-southeast-2'
45
- },
46
- {
47
- name: 'Asia Pacific (Tokyo)',
48
- code: 'ap-northeast-1'
49
- },
50
- {
51
- name: 'Canada (Central)',
52
- code: 'ca-central-1'
53
- },
54
- {
55
- name: 'China (Beijing)',
56
- code: 'cn-north-1'
57
- },
58
- {
59
- name: 'China (Ningxia)',
60
- code: 'cn-northwest-1'
61
- },
62
- {
63
- name: 'EU (Frankfurt)',
64
- code: 'eu-central-1'
65
- },
66
- {
67
- name: 'EU (Ireland)',
68
- code: 'eu-west-1'
69
- },
70
- {
71
- name: 'EU (London)',
72
- code: 'eu-west-2'
73
- },
74
- {
75
- name: 'EU (Milan)',
76
- code: 'eu-south-1'
77
- },
78
- {
79
- name: 'EU (Paris)',
80
- code: 'eu-west-3'
81
- },
82
- {
83
- name: 'EU (Stockholm)',
84
- code: 'eu-north-1'
85
- },
86
- {
87
- name: 'Middle East (Bahrain)',
88
- code: 'me-south-1'
89
- },
90
- {
91
- name: 'South America (Sao Paulo)',
92
- code: 'sa-east-1'
93
- },
94
- {
95
- name: 'AWS GovCloud (US-East)',
96
- code: 'us-gov-east-1'
97
- },
98
- {
99
- name: 'AWS GovCloud (US-West)',
100
- code: 'us-gov-west-1'
101
- }
102
- ]
103
-