awskeyring 1.11.0 → 1.12.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/exe/awskeyring +1 -1
- data/i18n/en.yml +1 -0
- data/lib/awskeyring/awsapi.rb +32 -5
- data/lib/awskeyring/version.rb +1 -1
- data/lib/awskeyring.rb +14 -0
- data/lib/awskeyring_command.rb +42 -14
- data/man/awskeyring.5 +4 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 155240a1418a0de58a8d3bd88fe97d607cb5f68ea6655f4b3e82ad6628683dad
|
4
|
+
data.tar.gz: 99224076df4e631f41e7aef1f0b8a713ff458887943303dbfd691af4e5ddd875
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8cfc74bf58e2886e28c3ab58f3d04955a57dbbcc4bffe9f450a472651df70f2ab3e1585dc21b1118a1f14e5ae8a1703076f56ff5215f19d623c3420c1883b65
|
7
|
+
data.tar.gz: 6c0c9f2f7b5916067b016bac45a3088d349298aff18e6b90e554e7ce2791476d8a5865800e0bbe334d2b07146f8a14b6cd68312a82af43ad6aedc5ffde585106
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
![Awskeyring](https://raw.githubusercontent.com/tristanmorgan/awskeyring/main/awskeyring-144.png)
|
4
4
|
|
5
|
-
*
|
5
|
+
* ![Build Passing](https://github.com/tristanmorgan/awskeyring/actions/workflows/ruby.yml/badge.svg)
|
6
6
|
* [![Gem Version](https://img.shields.io/gem/v/awskeyring)](https://badge.fury.io/rb/awskeyring)
|
7
7
|
* [![license MIT](https://img.shields.io/badge/license-MIT-brightgreen.svg)](https://opensource.org/licenses/MIT)
|
8
8
|
* [![All Downloads](https://img.shields.io/gem/dt/awskeyring)](https://rubygems.org/gems/awskeyring)
|
data/exe/awskeyring
CHANGED
data/i18n/en.yml
CHANGED
@@ -5,6 +5,7 @@ en:
|
|
5
5
|
add_role_desc: Adds a ROLE to the keyring
|
6
6
|
awskeyring_desc: Autocompletion for bourne shells
|
7
7
|
console_desc: Open the AWS Console for the ACCOUNT
|
8
|
+
decode_desc: Decode an account id from a KEY
|
8
9
|
default_desc: Run default help or initialise if needed.
|
9
10
|
env_desc: Outputs bourne shell environment exports for an ACCOUNT
|
10
11
|
exec_desc: Execute a COMMAND with the environment set for an ACCOUNT
|
data/lib/awskeyring/awsapi.rb
CHANGED
@@ -25,6 +25,7 @@ module Awskeyring
|
|
25
25
|
# AWS Env vars
|
26
26
|
AWS_ENV_VARS = %w[
|
27
27
|
AWS_ACCOUNT_NAME
|
28
|
+
AWS_ACCOUNT_ID
|
28
29
|
AWS_ACCESS_KEY_ID
|
29
30
|
AWS_ACCESS_KEY
|
30
31
|
AWS_CREDENTIAL_EXPIRATION
|
@@ -85,7 +86,7 @@ module Awskeyring
|
|
85
86
|
)
|
86
87
|
end
|
87
88
|
rescue Aws::STS::Errors::AccessDenied => e
|
88
|
-
warn e
|
89
|
+
warn e
|
89
90
|
exit 1
|
90
91
|
end
|
91
92
|
|
@@ -123,14 +124,16 @@ module Awskeyring
|
|
123
124
|
# [String] secret The aws_secret_access_key
|
124
125
|
# [String] token The aws_session_token
|
125
126
|
# @return [Hash] env_var hash
|
126
|
-
def self.get_env_array(params = {})
|
127
|
+
def self.get_env_array(params = {}) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/AbcSize
|
127
128
|
env_var = {}
|
128
129
|
env_var['AWS_DEFAULT_REGION'] = 'us-east-1' unless region
|
129
130
|
|
130
131
|
params[:expiration] = Time.at(params[:expiry]).iso8601 unless params[:expiry].nil?
|
132
|
+
params[:account_name] = params.delete(:account)
|
133
|
+
params[:account_id] = get_account_id(key: params[:key]) unless params[:key].nil?
|
131
134
|
|
132
|
-
|
133
|
-
|
135
|
+
AWS_ENV_VARS.each do |var_name|
|
136
|
+
params.each_key do |param_name|
|
134
137
|
if var_name.include?(param_name.to_s.upcase) && !params[param_name].nil?
|
135
138
|
env_var[var_name] = params[param_name]
|
136
139
|
end
|
@@ -151,7 +154,7 @@ module Awskeyring
|
|
151
154
|
sts = Aws::STS::Client.new(access_key_id: key, secret_access_key: secret, session_token: token)
|
152
155
|
sts.get_caller_identity
|
153
156
|
rescue Aws::Errors::ServiceError => e
|
154
|
-
warn e
|
157
|
+
warn e
|
155
158
|
exit 1
|
156
159
|
end
|
157
160
|
true
|
@@ -229,6 +232,30 @@ module Awskeyring
|
|
229
232
|
region || Aws.shared_config.region(profile: 'default')
|
230
233
|
end
|
231
234
|
|
235
|
+
# Get the account number from an access key
|
236
|
+
#
|
237
|
+
# @param [String] key The aws_access_key_id
|
238
|
+
# @return [String] Account number
|
239
|
+
def self.get_account_id(key:)
|
240
|
+
padded_no = key[3..12]
|
241
|
+
mask = (2 << 39) - 1
|
242
|
+
decimal = (decode(padded_no) >> 4) & mask
|
243
|
+
decimal.to_s.rjust(12, '0')
|
244
|
+
end
|
245
|
+
|
246
|
+
# base32 decode function
|
247
|
+
# returns 0 on failure
|
248
|
+
private_class_method def self.decode(str)
|
249
|
+
aws_table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'
|
250
|
+
bytes = str.bytes
|
251
|
+
bytes.inject do |m, o|
|
252
|
+
i = aws_table.index(o.chr)
|
253
|
+
return 0 if i.nil?
|
254
|
+
|
255
|
+
(m << 5) + i
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
232
259
|
# Rotates the AWS access keys
|
233
260
|
#
|
234
261
|
# @param [String] key The aws_access_key_id
|
data/lib/awskeyring/version.rb
CHANGED
data/lib/awskeyring.rb
CHANGED
@@ -4,6 +4,7 @@ require 'i18n'
|
|
4
4
|
require 'json'
|
5
5
|
require 'keychain'
|
6
6
|
require 'awskeyring/validate'
|
7
|
+
require 'awskeyring/awsapi'
|
7
8
|
|
8
9
|
# Awskeyring Module,
|
9
10
|
# gives you an interface to access keychains and items.
|
@@ -195,6 +196,19 @@ module Awskeyring # rubocop:disable Metrics/ModuleLength
|
|
195
196
|
(items + tokens).uniq.sort
|
196
197
|
end
|
197
198
|
|
199
|
+
# Return a list account item names plus account ids
|
200
|
+
def self.list_account_names_plus # rubocop:disable Metrics/AbcSize
|
201
|
+
list_items.concat(list_tokens).map do |elem|
|
202
|
+
account_id = Awskeyring::Awsapi.get_account_id(key: elem.attributes[:account])
|
203
|
+
account_name = if elem.attributes[:label].start_with?(ACCOUNT_PREFIX)
|
204
|
+
elem.attributes[:label][(ACCOUNT_PREFIX.length)..]
|
205
|
+
else
|
206
|
+
elem.attributes[:label][(SESSION_KEY_PREFIX.length)..]
|
207
|
+
end
|
208
|
+
"#{account_name}\t#{account_id}"
|
209
|
+
end.uniq.sort
|
210
|
+
end
|
211
|
+
|
198
212
|
# Return a list role item names
|
199
213
|
def self.list_role_names
|
200
214
|
list_roles.map { |elem| elem.attributes[:label][(ROLE_PREFIX.length)..] }.sort
|
data/lib/awskeyring_command.rb
CHANGED
@@ -77,13 +77,18 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
77
77
|
end
|
78
78
|
|
79
79
|
desc 'list', I18n.t('list_desc')
|
80
|
+
method_option :detail, type: :boolean, aliases: '-d', desc: I18n.t('method_option.detail'), default: false
|
80
81
|
# list the accounts
|
81
82
|
def list
|
82
83
|
if Awskeyring.list_account_names.empty?
|
83
84
|
warn I18n.t('message.missing_account', bin: File.basename($PROGRAM_NAME))
|
84
85
|
exit 1
|
85
86
|
end
|
86
|
-
|
87
|
+
if options[:detail]
|
88
|
+
puts Awskeyring.list_account_names_plus.join("\n")
|
89
|
+
else
|
90
|
+
puts Awskeyring.list_account_names.join("\n")
|
91
|
+
end
|
87
92
|
end
|
88
93
|
|
89
94
|
desc 'list-role', I18n.t('list_role_desc')
|
@@ -181,8 +186,8 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
181
186
|
method_option 'no-bundle', type: :boolean, aliases: '-b', desc: I18n.t('method_option.nobundle'), default: false
|
182
187
|
method_option 'no-token', type: :boolean, aliases: '-n', desc: I18n.t('method_option.notoken'), default: false
|
183
188
|
# execute an external command with env set
|
184
|
-
def exec(account, *
|
185
|
-
if
|
189
|
+
def exec(account, *exec) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
190
|
+
if exec.empty?
|
186
191
|
warn I18n.t('message.exec')
|
187
192
|
exit 1
|
188
193
|
end
|
@@ -194,11 +199,11 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
194
199
|
env_vars = Awskeyring::Awsapi.get_env_array(cred)
|
195
200
|
unbundle if options['no-bundle']
|
196
201
|
begin
|
197
|
-
pid = Process.spawn(env_vars,
|
202
|
+
pid = Process.spawn(env_vars, exec.join(' '))
|
198
203
|
Process.wait pid
|
199
204
|
exit 1 if Process.last_status.exitstatus.positive?
|
200
205
|
rescue Errno::ENOENT => e
|
201
|
-
warn e
|
206
|
+
warn e
|
202
207
|
exit 1
|
203
208
|
end
|
204
209
|
end
|
@@ -330,7 +335,7 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
330
335
|
key_message: I18n.t('message.rotate', account: account)
|
331
336
|
)
|
332
337
|
rescue Aws::Errors::ServiceError => e
|
333
|
-
warn e
|
338
|
+
warn e
|
334
339
|
exit 1
|
335
340
|
end
|
336
341
|
|
@@ -426,6 +431,16 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
426
431
|
end
|
427
432
|
end
|
428
433
|
|
434
|
+
desc 'decode KEY', I18n.t('decode_desc'), hide: true
|
435
|
+
# decode account numbers
|
436
|
+
def decode(key = nil)
|
437
|
+
key = ask_check(
|
438
|
+
existing: key, message: I18n.t('message.key'), validator: Awskeyring::Validate.method(:access_key)
|
439
|
+
)
|
440
|
+
|
441
|
+
puts Awskeyring::Awsapi.get_account_id(key: key)
|
442
|
+
end
|
443
|
+
|
429
444
|
desc "#{File.basename($PROGRAM_NAME)} CURR PREV", I18n.t('awskeyring_desc'), hide: true
|
430
445
|
map File.basename($PROGRAM_NAME) => :autocomplete
|
431
446
|
# autocomplete
|
@@ -441,7 +456,7 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
441
456
|
|
442
457
|
comp_lines = comp_line[0..(comp_point_str.to_i)].split
|
443
458
|
|
444
|
-
comp_type, sub_cmd = comp_type(comp_lines: comp_lines, prev: prev)
|
459
|
+
comp_type, sub_cmd = comp_type(comp_lines: comp_lines, prev: prev, curr: curr)
|
445
460
|
list = fetch_auto_resp(comp_type, sub_cmd)
|
446
461
|
puts list.select { |elem| elem.start_with?(curr) }.sort!.join("\n")
|
447
462
|
end
|
@@ -458,7 +473,7 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
458
473
|
end
|
459
474
|
|
460
475
|
# determine the type of completion needed
|
461
|
-
def comp_type(comp_lines:, prev:)
|
476
|
+
def comp_type(comp_lines:, prev:, curr:)
|
462
477
|
sub_cmd = sub_command(comp_lines)
|
463
478
|
comp_idx = comp_lines.rindex(prev)
|
464
479
|
|
@@ -469,19 +484,19 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
469
484
|
comp_type = :browser_type
|
470
485
|
else
|
471
486
|
comp_type = :command
|
472
|
-
comp_type = param_type(comp_idx, sub_cmd) unless sub_cmd.empty?
|
487
|
+
comp_type = param_type(comp_idx, sub_cmd, curr) unless sub_cmd.empty?
|
473
488
|
end
|
474
489
|
|
475
490
|
[comp_type, sub_cmd]
|
476
491
|
end
|
477
492
|
|
478
493
|
# check params for named params or fall back to flags
|
479
|
-
def param_type(comp_idx, sub_cmd)
|
480
|
-
types = %i[opt req]
|
494
|
+
def param_type(comp_idx, sub_cmd, curr)
|
495
|
+
types = %i[opt req rest]
|
481
496
|
param_list = method(sub_cmd).parameters.select { |elem| types.include? elem[0] }
|
482
497
|
if comp_idx.zero?
|
483
498
|
:command
|
484
|
-
elsif comp_idx > param_list.length
|
499
|
+
elsif comp_idx > param_list.length || curr.start_with?('-')
|
485
500
|
:flag
|
486
501
|
else
|
487
502
|
param_list[comp_idx - 1][1]
|
@@ -500,7 +515,7 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
500
515
|
end
|
501
516
|
|
502
517
|
# given a type return the right list for completions
|
503
|
-
def fetch_auto_resp(comp_type, sub_cmd)
|
518
|
+
def fetch_auto_resp(comp_type, sub_cmd) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
504
519
|
case comp_type
|
505
520
|
when :command
|
506
521
|
list_commands
|
@@ -514,6 +529,8 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
514
529
|
Awskeyring.list_token_names
|
515
530
|
when :browser_type
|
516
531
|
Awskeyring.list_browsers
|
532
|
+
when :exec
|
533
|
+
list_exec
|
517
534
|
else
|
518
535
|
list_arguments(command: sub_cmd)
|
519
536
|
end
|
@@ -522,7 +539,18 @@ class AwskeyringCommand < Thor # rubocop:disable Metrics/ClassLength
|
|
522
539
|
# list command names
|
523
540
|
def list_commands
|
524
541
|
commands = self.class.all_commands.keys.map { |elem| elem.tr('_', '-') }
|
525
|
-
commands.reject! { |elem| %w[autocomplete default].include?(elem) }
|
542
|
+
commands.reject! { |elem| %w[autocomplete default decode].include?(elem) }
|
543
|
+
end
|
544
|
+
|
545
|
+
# list executables
|
546
|
+
def list_exec
|
547
|
+
list = []
|
548
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
549
|
+
list.concat(Dir.children(File.expand_path(path)))
|
550
|
+
rescue Errno::ENOENT
|
551
|
+
next
|
552
|
+
end
|
553
|
+
list.flatten
|
526
554
|
end
|
527
555
|
|
528
556
|
# list flags for a command
|
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" "
|
4
|
+
.TH "AWSKEYRING" "5" "June 2024" "" ""
|
5
5
|
.
|
6
6
|
.SH "NAME"
|
7
7
|
\fBAwskeyring\fR \- is a small tool to manage AWS account keys in the macOS Keychain
|
@@ -159,6 +159,9 @@ list:
|
|
159
159
|
.IP
|
160
160
|
Prints a list of accounts in the keyring
|
161
161
|
.
|
162
|
+
.IP
|
163
|
+
\-d, \-\-detail, \-\-no\-detail: Show more detail\.
|
164
|
+
.
|
162
165
|
.TP
|
163
166
|
list\-role:
|
164
167
|
.
|
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.
|
4
|
+
version: 1.12.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tristan Morgan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-06-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-iam
|
@@ -92,9 +92,9 @@ licenses:
|
|
92
92
|
metadata:
|
93
93
|
bug_tracker_uri: https://github.com/tristanmorgan/awskeyring/issues
|
94
94
|
changelog_uri: https://github.com/tristanmorgan/awskeyring/blob/main/CHANGELOG.md
|
95
|
-
documentation_uri: https://rubydoc.info/gems/awskeyring/1.
|
95
|
+
documentation_uri: https://rubydoc.info/gems/awskeyring/1.12.1
|
96
96
|
rubygems_mfa_required: 'true'
|
97
|
-
source_code_uri: https://github.com/tristanmorgan/awskeyring/tree/v1.
|
97
|
+
source_code_uri: https://github.com/tristanmorgan/awskeyring/tree/v1.12.1
|
98
98
|
wiki_uri: https://github.com/tristanmorgan/awskeyring/wiki
|
99
99
|
post_install_message:
|
100
100
|
rdoc_options: []
|