awskeyring 1.8.4 → 1.9.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d6214486cc6877ca62ed23c40f01636f0f5bd726f7d7fdd9dd7f310ec87da84
4
- data.tar.gz: fede3a531c42bab12951bb316e8f4c0f9c3d383f60121c4993359013422fb6b4
3
+ metadata.gz: 6461179e25d74d7a488cc8dd25db6cb3f3965c177f0dd5cdc8fa440f7c0bf1e3
4
+ data.tar.gz: 30ac24cde26e0b407a89b218e61ecfd5a8f3ed2852d1da3e3339fa0ef82d17c1
5
5
  SHA512:
6
- metadata.gz: f23bed2643e3ab8f288ff690f20f540b8486a9aca792ff362696bf867009d36d874391f13b936cc1808a9908f1f16617d2fe81073e08c6620f0997835e653cb3
7
- data.tar.gz: a9732e12755c7465545bdcd59a982f446a33e42988de10158a4db977c4d8fc5a8a391d6c55c67b835fb6af749dd3e77dfef1d335b04fa6683a6df1ce0a36d227
6
+ metadata.gz: c11cee874dbaa962b252a637ebffb6623fbc0bf05cafaab9e32bbf34b8243dcf0a53e91f1ca6b3f1e4a2e65f3112981cae169334fa89817a866b8efe48a650dd
7
+ data.tar.gz: e4bbba7de171b98f88a1e3ea9232ab54c09a785712cddf979f232539ec867676bc0e33fe3b763eaf8217feecb3728aad11436326795f30560034ceeb2ac2d769
data/README.md CHANGED
@@ -62,24 +62,24 @@ more details on this config option.
62
62
  The CLI is using [Thor](http://whatisthor.com) with help provided interactively.
63
63
 
64
64
  Awskeyring commands:
65
- awskeyring --version, -v # Prints the version
66
- awskeyring add ACCOUNT # Adds an ACCOUNT to the keyring
67
- awskeyring add-role ROLE # Adds a ROLE to the keyring
68
- awskeyring console ACCOUNT # Open the AWS Console for the ACCOUNT
69
- awskeyring env ACCOUNT # Outputs bourne shell environment exports for an ACCOUNT
70
- awskeyring exec ACCOUNT command... # Execute a COMMAND with the environment set for an ACCOUNT
71
- awskeyring help [COMMAND] # Describe available commands or one specific command
72
- awskeyring import ACCOUNT # Import an ACCOUNT to the keyring from ~/.aws/credentials
73
- awskeyring initialise # Initialises a new KEYCHAIN
74
- awskeyring json ACCOUNT # Outputs AWS CLI compatible JSON for an ACCOUNT
75
- awskeyring list # Prints a list of accounts in the keyring
76
- awskeyring list-role # Prints a list of roles in the keyring
77
- awskeyring remove ACCOUNT # Removes an ACCOUNT from the keyring
78
- awskeyring remove-role ROLE # Removes a ROLE from the keyring
79
- awskeyring remove-token ACCOUNT # Removes a token for ACCOUNT from the keyring
80
- awskeyring rotate ACCOUNT # Rotate access keys for an ACCOUNT
81
- awskeyring token ACCOUNT [ROLE] [MFA] # Create an STS Token from a ROLE or an MFA code
82
- awskeyring update ACCOUNT # Updates an ACCOUNT in the keyring
65
+ awskeyring --version, -v # Prints the version
66
+ awskeyring add ACCOUNT # Adds an ACCOUNT to the keyring
67
+ awskeyring add-role ROLE # Adds a ROLE to the keyring
68
+ awskeyring console ACCOUNT # Open the AWS Console for the ACCOUNT
69
+ awskeyring env ACCOUNT # Outputs bourne shell environment exports for an ACCOUNT
70
+ awskeyring exec ACCOUNT command... # Execute a COMMAND with the environment set for an ACCOUNT
71
+ awskeyring help [COMMAND] # Describe available commands or one specific command
72
+ awskeyring import ACCOUNT # Import an ACCOUNT to the keyring from ~/.aws/credentials
73
+ awskeyring initialise # Initialises a new KEYCHAIN
74
+ awskeyring json ACCOUNT # Outputs AWS CLI compatible JSON for an ACCOUNT
75
+ awskeyring list # Prints a list of accounts in the keyring
76
+ awskeyring list-role # Prints a list of roles in the keyring
77
+ awskeyring remove ACCOUNT # Removes an ACCOUNT from the keyring
78
+ awskeyring remove-role ROLE # Removes a ROLE from the keyring
79
+ awskeyring remove-token ACCOUNT # Removes a token for ACCOUNT from the keyring
80
+ awskeyring rotate ACCOUNT # Rotate access keys for an ACCOUNT
81
+ awskeyring token ACCOUNT [ROLE] [CODE] # Create an STS Token from a ROLE or an mfa CODE
82
+ awskeyring update ACCOUNT # Updates an ACCOUNT in the keyring
83
83
 
84
84
  and autocomplete that can be installed with:
85
85
 
data/Rakefile CHANGED
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'bundler/gem_tasks'
4
- require 'rspec/core/rake_task'
5
4
  require 'rubocop/rake_task'
6
5
  require 'ronn'
7
6
  require 'github_changelog_generator/task'
@@ -49,8 +48,9 @@ end
49
48
  desc 'generate manpage'
50
49
  task :ronn do
51
50
  puts 'Running Ronn...'
52
- roff_text = Ronn::Document.new('man/awskeyring.5.ronn').to_roff
53
- File.write('man/awskeyring.5', roff_text)
51
+ doc = Ronn::Document.new('man/awskeyring.5.ronn')
52
+ doc.date = Time.parse(`git show -s --format=%ad --date=short`)
53
+ File.write('man/awskeyring.5', doc.to_roff)
54
54
  puts "done\n\n"
55
55
  end
56
56
 
data/i18n/en.yml CHANGED
@@ -17,7 +17,7 @@ en:
17
17
  remove_role_desc: Removes a ROLE from the keyring
18
18
  remove_token_desc: Removes a token for ACCOUNT from the keyring
19
19
  rotate_desc: Rotate access keys for an ACCOUNT
20
- token_desc: Create an STS Token from a ROLE or an MFA code
20
+ token_desc: Create an STS Token from a ROLE or an mfa CODE
21
21
  update_desc: Updates an ACCOUNT in the keyring
22
22
  method_option:
23
23
  arn: 'AWS role arn.'
@@ -209,7 +209,7 @@ module Awskeyring
209
209
  # Get the signin token param
210
210
  private_class_method def self.token_param(session_json:)
211
211
  get_signin_token_url = AWS_SIGNIN_URL + '?Action=getSigninToken' \
212
- '&Session=' + CGI.escape(session_json)
212
+ '&Session=' + CGI.escape(session_json)
213
213
 
214
214
  uri = URI(get_signin_token_url)
215
215
  request = Net::HTTP.new(uri.host, uri.port)
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aws-sdk-core'
4
+ require 'awskeyring'
5
+
6
+ module Awskeyring
7
+ # Provide a credential provider for use as a library, eg.
8
+ # require 'awskeyring/credential_provider'
9
+ # client = Aws::STS::Client.new(
10
+ # credentials: Awskeyring::CredentialProvider.new("company-acc")
11
+ # )
12
+ class CredentialProvider
13
+ include Aws::CredentialProvider
14
+
15
+ attr_accessor :account
16
+
17
+ def initialize(account)
18
+ @account = account
19
+ end
20
+
21
+ # returns a new Aws::Credentials object
22
+ def credentials
23
+ cred = Awskeyring.get_valid_creds(account: account)
24
+ Aws::Credentials.new(cred[:key],
25
+ cred[:secret],
26
+ cred[:token])
27
+ end
28
+ end
29
+ end
@@ -6,7 +6,7 @@ require 'json'
6
6
  # Version const and query of latest.
7
7
  module Awskeyring
8
8
  # The Gem's version number
9
- VERSION = '1.8.4'
9
+ VERSION = '1.9.2'
10
10
  # The Gem's homepage
11
11
  HOMEPAGE = 'https://github.com/servian/awskeyring'
12
12
 
data/lib/awskeyring.rb CHANGED
@@ -52,6 +52,7 @@ module Awskeyring # rubocop:disable Metrics/ModuleLength
52
52
  prefs = {
53
53
  awskeyring: awskeyring,
54
54
  keyage: DEFAULT_KEY_AGE,
55
+ browser: DEFAULT_BROWSER_LIST,
55
56
  console: DEFAULT_CONSOLE_LIST
56
57
  }
57
58
  File.new(Awskeyring::PREFS_FILE, 'w').write JSON.dump(prefs)
@@ -97,6 +98,17 @@ module Awskeyring # rubocop:disable Metrics/ModuleLength
97
98
  all_items.where(account: account).first
98
99
  end
99
100
 
101
+ # return item that matches a prefix if only one.
102
+ def self.solo_select(list, prefix)
103
+ return prefix if list.include?(prefix)
104
+
105
+ list.select! { |elem| elem.start_with?(prefix) }
106
+
107
+ return list.first if list.length == 1
108
+
109
+ nil
110
+ end
111
+
100
112
  # Add an account item
101
113
  #
102
114
  # @param [String] account The account name to create
@@ -317,7 +329,7 @@ module Awskeyring # rubocop:disable Metrics/ModuleLength
317
329
  # @param [String] account_name the associated account name.
318
330
  def self.account_exists(account_name)
319
331
  Awskeyring::Validate.account_name(account_name)
320
- raise 'Account does not exist' unless list_account_names.include?(account_name)
332
+ raise 'Account does not exist' unless (account_name = solo_select(list_account_names, account_name))
321
333
 
322
334
  account_name
323
335
  end
@@ -347,7 +359,7 @@ module Awskeyring # rubocop:disable Metrics/ModuleLength
347
359
  # @param [String] role_name the associated role name.
348
360
  def self.role_exists(role_name)
349
361
  Awskeyring::Validate.role_name(role_name)
350
- raise 'Role does not exist' unless list_role_names.include?(role_name)
362
+ raise 'Role does not exist' unless (role_name = solo_select(list_role_names, role_name))
351
363
 
352
364
  role_name
353
365
  end
@@ -367,7 +379,7 @@ module Awskeyring # rubocop:disable Metrics/ModuleLength
367
379
  # @param [String] token_name the associated account name.
368
380
  def self.token_exists(token_name)
369
381
  Awskeyring::Validate.account_name(token_name)
370
- raise 'Token does not exist' unless list_token_names.include?(token_name)
382
+ raise 'Token does not exist' unless (token_name = solo_select(list_token_names, token_name))
371
383
 
372
384
  token_name
373
385
  end
@@ -16,7 +16,6 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
16
16
  I18n.backend.load_translations
17
17
 
18
18
  map %w[--version -v] => :__version
19
- map %w[--help -h] => :help
20
19
  map 'adr' => :add_role
21
20
  map 'assume-role' => :token
22
21
  map 'ls' => :list
@@ -125,7 +124,8 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
125
124
  # Print JSON for use with credential_process
126
125
  def json(account)
127
126
  account = ask_check(
128
- existing: account, message: I18n.t('message.account'), validator: Awskeyring.method(:account_exists)
127
+ existing: account, message: I18n.t('message.account'), validator: Awskeyring.method(:account_exists),
128
+ limited_to: Awskeyring.list_account_names
129
129
  )
130
130
  cred = age_check_and_get(account: account, no_token: options['no-token'])
131
131
  expiry = Time.at(cred[:expiry]) unless cred[:expiry].nil?
@@ -177,11 +177,15 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
177
177
  method_option 'no-token', type: :boolean, aliases: '-n', desc: I18n.t('method_option.notoken'), default: false
178
178
  method_option 'no-bundle', type: :boolean, aliases: '-b', desc: I18n.t('method_option.nobundle'), default: false
179
179
  # execute an external command with env set
180
- def exec(account, *command)
180
+ def exec(account, *command) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
181
181
  if command.empty?
182
182
  warn I18n.t('message.exec')
183
183
  exit 1
184
184
  end
185
+ account = ask_check(
186
+ existing: account, message: I18n.t('message.account'), validator: Awskeyring.method(:account_exists),
187
+ limited_to: Awskeyring.list_account_names
188
+ )
185
189
  cred = age_check_and_get(account: account, no_token: options['no-token'])
186
190
  env_vars = Awskeyring::Awsapi.get_env_array(cred)
187
191
  unbundle if options['no-bundle']
@@ -335,7 +339,7 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
335
339
  puts I18n.t('message.upaccount', account: account)
336
340
  end
337
341
 
338
- desc 'token ACCOUNT [ROLE] [MFA]', I18n.t('token_desc')
342
+ desc 'token ACCOUNT [ROLE] [CODE]', I18n.t('token_desc')
339
343
  method_option :code, type: :string, aliases: '-c', desc: I18n.t('method_option.code')
340
344
  method_option :duration, type: :string, aliases: '-d', desc: I18n.t('method_option.duration')
341
345
  # generate a sessiopn token
@@ -430,7 +434,8 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
430
434
  desc "#{File.basename($PROGRAM_NAME)} CURR PREV", I18n.t('awskeyring_desc'), hide: true
431
435
  map File.basename($PROGRAM_NAME) => :autocomplete
432
436
  # autocomplete
433
- def autocomplete(curr, prev)
437
+ def autocomplete(curr, prev = nil)
438
+ curr, prev = fix_args(curr, prev)
434
439
  comp_line = ENV['COMP_LINE']
435
440
  comp_point_str = ENV['COMP_POINT']
436
441
  unless comp_line && comp_point_str
@@ -448,16 +453,16 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
448
453
 
449
454
  private
450
455
 
451
- def age_check_and_get(account:, no_token:)
452
- cred = Awskeyring.get_valid_creds(account: account, no_token: no_token)
453
-
454
- maxage = Awskeyring.key_age
455
- age = (Time.new - cred[:updated]).div Awskeyring::Awsapi::ONE_DAY
456
- warn I18n.t('message.age_check', account: account, age: age) unless age < maxage
457
-
458
- cred
456
+ # when a double dash is parsed it is dropped from the args but we need it
457
+ def fix_args(curr, prev)
458
+ if prev.nil?
459
+ [ARGV[1], ARGV[2]]
460
+ else
461
+ [curr, prev]
462
+ end
459
463
  end
460
464
 
465
+ # determine the type of completion needed
461
466
  def comp_type(comp_lines:, prev:)
462
467
  sub_cmd = sub_command(comp_lines)
463
468
  comp_idx = comp_lines.rindex(prev)
@@ -475,8 +480,10 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
475
480
  [comp_type, sub_cmd]
476
481
  end
477
482
 
483
+ # check params for named params or fall back to flags
478
484
  def param_type(comp_idx, sub_cmd)
479
- param_list = method(sub_cmd).parameters
485
+ types = %i[opt req]
486
+ param_list = method(sub_cmd).parameters.select { |elem| types.include? elem[0] }
480
487
  if comp_idx.zero?
481
488
  :command
482
489
  elsif comp_idx > param_list.length
@@ -486,18 +493,18 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
486
493
  end
487
494
  end
488
495
 
496
+ # catch the command from prefixes and aliases
489
497
  def sub_command(comp_lines)
490
- return '' if comp_lines.nil? || comp_lines.length < 2
498
+ return '' if comp_lines.length < 2
491
499
 
492
- sub_cmd = comp_lines[1].tr('-', '_')
500
+ sub_cmd = comp_lines[1]
493
501
 
494
- sub_cmds = self.class.all_commands.keys.select { |elem| elem.start_with?(sub_cmd) }
502
+ return self.class.map[sub_cmd].to_s if self.class.map.key? sub_cmd
495
503
 
496
- return sub_cmds.first if sub_cmds.length == 1
497
-
498
- self.class.map[sub_cmd].to_s
504
+ (Awskeyring.solo_select(list_commands, sub_cmd) || '').tr('-', '_')
499
505
  end
500
506
 
507
+ # given a type return the right list for completions
501
508
  def fetch_auto_resp(comp_type, sub_cmd)
502
509
  case comp_type
503
510
  when :command
@@ -517,11 +524,13 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
517
524
  end
518
525
  end
519
526
 
527
+ # list command names
520
528
  def list_commands
521
529
  commands = self.class.all_commands.keys.map { |elem| elem.tr('_', '-') }
522
530
  commands.reject! { |elem| %w[autocomplete default].include?(elem) }
523
531
  end
524
532
 
533
+ # list flags for a command
525
534
  def list_arguments(command:)
526
535
  options = self.class.all_commands[command].options.values
527
536
  exit 1 if options.empty?
@@ -530,18 +539,32 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
530
539
  options.map(&:switch_name)
531
540
  end
532
541
 
542
+ # add warning about old keys
543
+ def age_check_and_get(account:, no_token:)
544
+ cred = Awskeyring.get_valid_creds(account: account, no_token: no_token)
545
+
546
+ maxage = Awskeyring.key_age
547
+ age = (Time.new - cred[:updated]).div Awskeyring::Awsapi::ONE_DAY
548
+ warn I18n.t('message.age_check', account: account, age: age) unless age < maxage
549
+
550
+ cred
551
+ end
552
+
553
+ # print exports from map
533
554
  def put_env_string(cred)
534
555
  env_var = Awskeyring::Awsapi.get_env_array(cred)
535
556
  env_var.each { |var, value| puts "export #{var}=\"#{value}\"" }
536
557
  Awskeyring::Awsapi::AWS_ENV_VARS.each { |key| puts "unset #{key}" unless env_var.key?(key) }
537
558
  end
538
559
 
560
+ # select duration for sts token types
539
561
  def default_duration(duration, role, code)
540
562
  duration ||= Awskeyring::Awsapi::ONE_HOUR.to_s if role
541
563
  duration ||= Awskeyring::Awsapi::TWELVE_HOUR.to_s if code
542
564
  duration || Awskeyring::Awsapi::ONE_HOUR.to_s
543
565
  end
544
566
 
567
+ # ask and validate input values.
545
568
  def ask_check(existing:, message:, flags: nil, validator: nil, limited_to: nil) # rubocop:disable Metrics/MethodLength
546
569
  retries ||= 3
547
570
  begin
@@ -562,10 +585,12 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
562
585
  value
563
586
  end
564
587
 
588
+ # ask for somthinng if its missing.
565
589
  def ask_missing(existing:, message:, secure: false, optional: false, limited_to: nil)
566
590
  existing || ask(message: message, secure: secure, optional: optional, limited_to: limited_to).strip
567
591
  end
568
592
 
593
+ # ask in different ways
569
594
  def ask(message:, secure: false, optional: false, limited_to: nil)
570
595
  if secure
571
596
  Awskeyring::Input.read_secret("#{message.rjust(20)}: ")
@@ -578,6 +603,7 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
578
603
  end
579
604
  end
580
605
 
606
+ # undo Bundler env vars
581
607
  def unbundle
582
608
  to_delete = ENV.keys.select { |elem| elem.start_with?('BUNDLER_ORIG_') }
583
609
  bundled_env = to_delete.map { |elem| elem[('BUNDLER_ORIG_'.length)..] }
data/man/awskeyring.5 CHANGED
@@ -1,7 +1,7 @@
1
1
  .\" generated with Ronn/v0.7.3
2
2
  .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
3
  .
4
- .TH "AWSKEYRING" "5" "May 2021" "" ""
4
+ .TH "AWSKEYRING" "5" "September 2021" "" ""
5
5
  .
6
6
  .SH "NAME"
7
7
  \fBAwskeyring\fR \- is a small tool to manage AWS account keys in the macOS Keychain
@@ -189,10 +189,10 @@ rotate ACCOUNT:
189
189
  Rotate access keys for an ACCOUNT
190
190
  .
191
191
  .TP
192
- token ACCOUNT [ROLE] [MFA]:
192
+ token ACCOUNT [ROLE] [CODE]:
193
193
  .
194
194
  .IP
195
- Create an STS Token from a ROLE or an MFA code
195
+ Create an STS Token from a ROLE or an mfa CODE
196
196
  .
197
197
  .br
198
198
  .
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: awskeyring
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.4
4
+ version: 1.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tristan Morgan
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-24 00:00:00.000000000 Z
11
+ date: 2021-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-iam
@@ -82,6 +82,7 @@ files:
82
82
  - i18n/en.yml
83
83
  - lib/awskeyring.rb
84
84
  - lib/awskeyring/awsapi.rb
85
+ - lib/awskeyring/credential_provider.rb
85
86
  - lib/awskeyring/input.rb
86
87
  - lib/awskeyring/validate.rb
87
88
  - lib/awskeyring/version.rb
@@ -93,8 +94,8 @@ licenses:
93
94
  metadata:
94
95
  bug_tracker_uri: https://github.com/servian/awskeyring/issues
95
96
  changelog_uri: https://github.com/servian/awskeyring/blob/main/CHANGELOG.md
96
- documentation_uri: https://rubydoc.info/gems/awskeyring/1.8.4
97
- source_code_uri: https://github.com/servian/awskeyring/tree/v1.8.4
97
+ documentation_uri: https://rubydoc.info/gems/awskeyring/1.9.2
98
+ source_code_uri: https://github.com/servian/awskeyring/tree/v1.9.2
98
99
  wiki_uri: https://github.com/servian/awskeyring/wiki
99
100
  post_install_message:
100
101
  rdoc_options: []