sym 2.8.0 → 2.10.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.
Files changed (50) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +30 -31
  3. data/.envrc +7 -0
  4. data/.gitignore +1 -0
  5. data/.rubocop.yml +150 -928
  6. data/.travis.yml +16 -26
  7. data/CHANGELOG.md +206 -167
  8. data/Gemfile +1 -0
  9. data/README.adoc +650 -0
  10. data/Rakefile +9 -3
  11. data/bin/{sym.completion → sym.completion.bash} +9 -14
  12. data/bin/sym.symit.bash +781 -0
  13. data/codecov.yml +29 -0
  14. data/design/sym-help.png +0 -0
  15. data/exe/keychain +1 -1
  16. data/exe/sym +5 -2
  17. data/lib/ruby_warnings.rb +7 -0
  18. data/lib/sym.rb +1 -7
  19. data/lib/sym/app.rb +1 -1
  20. data/lib/sym/app/args.rb +3 -2
  21. data/lib/sym/app/cli.rb +1 -2
  22. data/lib/sym/app/cli_slop.rb +1 -1
  23. data/lib/sym/app/commands.rb +1 -1
  24. data/lib/sym/app/commands/base_command.rb +1 -1
  25. data/lib/sym/app/commands/bash_completion.rb +20 -8
  26. data/lib/sym/app/commands/open_editor.rb +1 -1
  27. data/lib/sym/app/commands/password_protect_key.rb +4 -4
  28. data/lib/sym/app/commands/show_examples.rb +1 -1
  29. data/lib/sym/app/input/handler.rb +7 -1
  30. data/lib/sym/app/keychain.rb +15 -9
  31. data/lib/sym/app/output/noop.rb +2 -1
  32. data/lib/sym/app/password/cache.rb +1 -1
  33. data/lib/sym/app/password/providers.rb +2 -3
  34. data/lib/sym/app/private_key/decryptor.rb +2 -2
  35. data/lib/sym/app/private_key/detector.rb +4 -7
  36. data/lib/sym/application.rb +6 -11
  37. data/lib/sym/constants.rb +28 -13
  38. data/lib/sym/data/wrapper_struct.rb +20 -12
  39. data/lib/sym/errors.rb +11 -2
  40. data/lib/sym/extensions/instance_methods.rb +7 -8
  41. data/lib/sym/extensions/stdlib.rb +0 -1
  42. data/lib/sym/extensions/with_retry.rb +1 -1
  43. data/lib/sym/extensions/with_timeout.rb +1 -1
  44. data/lib/sym/version.rb +30 -5
  45. data/sym.gemspec +35 -35
  46. metadata +88 -71
  47. data/.codeclimate.yml +0 -30
  48. data/README.md +0 -623
  49. data/bin/sym.symit +0 -565
  50. data/lib/sym/app/password/providers/drb_provider.rb +0 -41
@@ -0,0 +1,29 @@
1
+ codecov:
2
+ require_ci_to_pass: no
3
+
4
+ notify:
5
+ wait_for_ci: yes
6
+
7
+ parsers:
8
+ v1:
9
+ include_full_missed_files: true # To use with Ruby so we see files that have NO tests written
10
+
11
+ coverage:
12
+ range: 50..75
13
+ round: down
14
+ precision: 1
15
+ status:
16
+ project:
17
+ default: off
18
+ sym:
19
+ target: 70%
20
+ threshold: 10%
21
+ informational: true
22
+ if_not_found: success
23
+ if_ci_failed: error
24
+ paths:
25
+ - lib/
26
+ flags:
27
+ sym:
28
+ paths:
29
+ - lib/
Binary file
@@ -32,7 +32,7 @@ puts data ? \
32
32
  Sym::App::KeyChain.new(key_name).send(action.to_sym, data) :
33
33
  Sym::App::KeyChain.new(key_name).send(action.to_sym)
34
34
  rescue StandardError => e
35
- STDERR.puts "#{e.message.red}"
35
+ warn "#{e.message.red}"
36
36
  end
37
37
 
38
38
 
data/exe/sym CHANGED
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
+ # vim: ft=ruby
3
+
4
+ require_relative '../lib/ruby_warnings'
2
5
 
3
6
  lib_path = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
7
  $LOAD_PATH << lib_path if File.exist?(lib_path) && !$LOAD_PATH.include?(lib_path)
@@ -6,12 +9,12 @@ $LOAD_PATH << lib_path if File.exist?(lib_path) && !$LOAD_PATH.include?(lib_path
6
9
  require 'sym'
7
10
  require 'sym/app'
8
11
 
9
- #ARGV.any?{ |a| a =~ /^-/ } ?
12
+ # ARGV.any?{ |a| a =~ /^-/ } ?
10
13
  begin
11
14
  exit ::Sym::App::CLI.new(ARGV.dup).execute
12
15
  rescue Interrupt => e
13
16
  STDERR.flush
14
- STDERR.puts "Interrupt, #{e.message}, exiting."
17
+ warn "Interrupt, #{e.message}, exiting."
15
18
  STDERR.flush
16
19
  exit 1
17
20
  end
@@ -0,0 +1,7 @@
1
+ ruby_version = RbConfig::CONFIG['MAJOR'].to_i * 10 + RbConfig::CONFIG['MINOR'].to_i
2
+ if ruby_version >= 27
3
+ Warning[:deprecated] = false
4
+ ENV['RUBYOPT'] = '-W:no-deprecated'
5
+ else
6
+ ENV['RUBYOPT']="-W0"
7
+ end
data/lib/sym.rb CHANGED
@@ -21,17 +21,11 @@ Sym::Configuration.configure do |config|
21
21
  # When nil is selected, providers are auto-detected.
22
22
  config.password_cache_default_provider = nil
23
23
  config.password_cache_arguments = {
24
- drb: {
25
- opts: {
26
- uri: 'druby://127.0.0.1:24924'
27
- }
28
- },
29
24
  memcached: {
30
25
  args: %w(127.0.0.1:11211),
31
26
  opts: { namespace: 'sym',
32
27
  compress: true,
33
- expires_in: config.password_cache_timeout
34
- }
28
+ expires_in: config.password_cache_timeout}
35
29
 
36
30
  }
37
31
  }
@@ -66,7 +66,7 @@ module Sym
66
66
  self.exit_code = 1
67
67
  end
68
68
 
69
- def self.is_osx?
69
+ def self.osx?
70
70
  Gem::Platform.local.os.eql?('darwin')
71
71
  end
72
72
 
@@ -12,7 +12,7 @@ module Sym
12
12
 
13
13
  def initialize(opts)
14
14
  self.opts = opts
15
- self.selected_options = opts.keys.reject { |k| !opts[k] }
15
+ self.selected_options = opts.keys.select { |k| opts[k] }
16
16
  end
17
17
 
18
18
  def specify_key?
@@ -33,10 +33,11 @@ module Sym
33
33
  end
34
34
 
35
35
  def provided_options
36
- opts.to_hash.keys.reject { |k| !opts[k] }
36
+ opts.to_hash.keys.select { |k| opts[k] }
37
37
  end
38
38
 
39
39
  private
40
+
40
41
  def do?(list)
41
42
  !(list & selected_options).empty?
42
43
  end
@@ -60,7 +60,6 @@ module Sym
60
60
 
61
61
 
62
62
  def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = nil)
63
-
64
63
  self.stdin = stdin
65
64
  self.stdout = stdout
66
65
  self.stderr = stderr
@@ -140,7 +139,7 @@ module Sym
140
139
  private
141
140
 
142
141
  def log(*args)
143
- Sym::App.log(*args, **(opts.to_hash))
142
+ Sym::App.log(*args, **opts.to_hash)
144
143
  end
145
144
 
146
145
  def error(hash)
@@ -55,7 +55,7 @@ module Sym
55
55
  o.separator 'Create a new private key:'.yellow
56
56
  o.bool '-g', '--generate', ' generate a new private key'
57
57
  o.bool '-p', '--password', ' encrypt the key with a password'
58
- if Sym::App.is_osx?
58
+ if Sym::App.osx?
59
59
  o.string '-x', '--keychain', '[key-name] '.blue + 'write the key to OS-X Keychain'
60
60
  end
61
61
 
@@ -37,7 +37,7 @@ module Sym
37
37
  # Sort commands based on the #dependencies array, which itself is sorted
38
38
  # based on command dependencies.
39
39
  def sorted_commands
40
- @sorted_commands ||= self.commands.to_a.sort_by{|klass| dependencies.index(klass.short_name) }
40
+ @sorted_commands ||= self.commands.to_a.sort_by{ |klass| dependencies.index(klass.short_name) }
41
41
  @sorted_commands
42
42
  end
43
43
 
@@ -73,7 +73,7 @@ module Sym
73
73
  end
74
74
 
75
75
  def add_to_keychain_if_needed(key)
76
- if opts[:keychain] && Sym::App.is_osx?
76
+ if opts[:keychain] && Sym::App.osx?
77
77
  Sym::App::KeyChain.new(opts[:keychain], opts).add(key)
78
78
  else
79
79
  key
@@ -8,21 +8,24 @@ module Sym
8
8
  try_after :generate_key, :open_editor, :encrypt, :decrypt
9
9
 
10
10
  def ok
11
- '[OK]'.bold.green
11
+ ' '.bold.green
12
12
  end
13
13
 
14
14
  def execute
15
15
  file = opts[:bash_support]
16
16
 
17
17
  out = ''
18
- Sym::Constants::Bash::Config.each_pair do |key, config|
18
+ Sym::Constants::Bash::CONFIG.each_pair do |key, config|
19
19
  script_name = key.to_s
20
- if (!File.exist?(config[:dest])) ||
21
- (File.exist?(config[:dest]) && !FileUtils.identical?(config[:source], config[:dest]))
22
- FileUtils.cp(config[:source], config[:dest])
23
- out << "#{} installing #{config[:dest].bold.blue }...\n"
24
- else
20
+
21
+ # This removes the old version of this file.
22
+ remove_old_version(out, config[:dest])
23
+
24
+ if File.exist?(config[:dest]) && File.read(config[:source]) == File.read(config[:dest])
25
25
  out << "#{ok} file #{config[:dest].bold.blue } exists, and is up to date.\n"
26
+ else
27
+ FileUtils.cp(config[:source], config[:dest])
28
+ out << "#{ok} installing #{config[:dest].bold.blue }...\n"
26
29
  end
27
30
 
28
31
  out << if File.exist?(file)
@@ -40,7 +43,7 @@ module Sym
40
43
  out << "\nPlease reload your terminal session to activate bash completion\n"
41
44
  out << "and other installed BASH utilities.\n"
42
45
  out << "\nAlternatively, just type #{"source #{file}".bold.green} to reload BASH.\n"
43
- out << "Also — go ahead and try running #{"sym -h".bold.blue} and #{"symit -h".bold.blue}.\n"
46
+ out << "Also — go ahead and try running #{'sym -h'.bold.blue} and #{'symit -h'.bold.blue}.\n"
44
47
  end
45
48
 
46
49
  private
@@ -51,6 +54,15 @@ module Sym
51
54
  end
52
55
  end
53
56
 
57
+ def remove_old_version(out, file)
58
+ if file =~ /\.bash$/
59
+ old_file = file.gsub(/\.bash$/, '')
60
+ if File.exist?(old_file)
61
+ out << "Removing old version — #{old_file.bold.magenta}..."
62
+ FileUtils.rm_f old_file
63
+ end
64
+ end
65
+ end
54
66
  end
55
67
  end
56
68
  end
@@ -48,7 +48,7 @@ module Sym
48
48
  end
49
49
 
50
50
  def timestamp
51
- @timestamp ||= Time.now.to_a.select { |d| d.is_a?(Fixnum) }.map { |d| '%02d' % d }[0..-3].reverse.join
51
+ @timestamp ||= Time.now.to_a.select { |d| d.is_a?(Integer) }.map { |d| '%02d' % d }[0..-3].reverse.join
52
52
  end
53
53
 
54
54
  def process(code)
@@ -16,10 +16,10 @@ module Sym
16
16
  the_key = self.key
17
17
 
18
18
  if opts[:password]
19
- encrypted_key, password = encrypt_with_password(the_key)
20
- add_password_to_the_cache(encrypted_key, password)
21
- the_key = encrypted_key
22
- end
19
+ encrypted_key, password = encrypt_with_password(the_key)
20
+ add_password_to_the_cache(encrypted_key, password)
21
+ the_key = encrypted_key
22
+ end
23
23
 
24
24
  add_to_keychain_if_needed(the_key)
25
25
 
@@ -56,7 +56,7 @@ Diff:
56
56
  # (c) 2016 Konstantin Gredeskoul. All rights reserved.'.green.bold)
57
57
 
58
58
 
59
- if Sym::App.is_osx?
59
+ if Sym::App.osx?
60
60
  output << example(comment: 'generate a new password-encrypted key, save it to your Keychain:',
61
61
  command: 'sym -gpcx staging.key')
62
62
 
@@ -27,7 +27,13 @@ module Sym
27
27
  end
28
28
 
29
29
  def prompt(message, color)
30
- raise Sym::Errors::CantReadPasswordNoTTY.new('key requires a password, however STDIN is not a TTY') unless stdin.tty?
30
+ unless STDIN.isatty && STDIN.tty?
31
+ raise Sym::Errors::CantReadPasswordNoTTY.new('key requires a password, however STDIN is not a TTY')
32
+ end
33
+ highline(message, color)
34
+ end
35
+
36
+ def highline(message, color)
31
37
  HighLine.new(stdin, stderr).ask(message.bold) { |q| q.echo = '•'.send(color) }
32
38
  end
33
39
 
@@ -39,11 +39,13 @@ module Sym
39
39
  self.key_name = key_name
40
40
  self.opts = opts
41
41
  self.class.validate!
42
- stderr_off
42
+ opts[:trace] ? stderr_on : stderr_off
43
43
  end
44
44
 
45
45
  def add(password)
46
- execute command(:add, "-U -w '#{password}' ")
46
+ delete rescue nil
47
+ sleep 0.1
48
+ execute command(:add, " -T /usr/bin/security -w '#{password}' ")
47
49
  end
48
50
 
49
51
  def find
@@ -56,10 +58,14 @@ module Sym
56
58
 
57
59
  def execute(command)
58
60
  command += ' 2>/dev/null' if stderr_disabled
59
- puts "> #{command.yellow.green}" if opts[:verbose]
61
+ puts "> #{command.yellow}" if opts[:verbose]
60
62
  output = `#{command}`
61
63
  result = $?
62
- raise Sym::Errors::KeyChainCommandError.new("Command error: #{result}, command: #{command}") unless result.success?
64
+ unless result.success?
65
+ warn "> ERROR running command:\n> $ #{output.red}" if !stderr_disabled && opts[:verbose]
66
+ raise Sym::Errors::KeyChainCommandError.new("Command error: #{result}, command: #{command}")
67
+ end
68
+
63
69
  output.chomp
64
70
  rescue Errno::ENOENT => e
65
71
  raise Sym::Errors::KeyChainCommandError.new("Command error: #{e.message}, command: #{command}")
@@ -80,16 +86,16 @@ module Sym
80
86
  out << extras if extras
81
87
  out = out.join
82
88
  # Do not actually ever run these commands on non MacOSX
83
- out = "echo Run this –\"#{out}\", on #{Sym::App.this_os}?\nAre you sure?" unless Sym::App.is_osx?
89
+ out = "echo Run this –\"#{out}\", on #{Sym::App.this_os}?\nAre you sure?" unless Sym::App.osx?
84
90
  out
85
91
  end
86
92
 
87
93
  def base_command(action)
88
94
  [
89
- "security #{action}-#{self.class.sub_section} ",
90
- "-a '#{self.class.user}' ",
91
- "-D '#{self.class.kind}' ",
92
- "-s '#{self.key_name}' "
95
+ "/usr/bin/security #{action}-#{self.class.sub_section} ",
96
+ "-a #{self.class.user} ",
97
+ "-D #{self.class.kind} ",
98
+ "-s #{self.key_name} "
93
99
  ]
94
100
  end
95
101
  end
@@ -7,7 +7,8 @@ module Sym
7
7
  required_option :quiet
8
8
 
9
9
  def output_proc
10
- ->(*) { ; }
10
+ ->(*) do
11
+ end
11
12
  end
12
13
  end
13
14
  end
@@ -36,7 +36,7 @@ module Sym
36
36
  self.enabled = opts[:enabled]
37
37
  self.verbose = opts[:verbose]
38
38
  self.timeout = opts[:timeout] || ::Sym::Configuration.config.password_cache_timeout
39
- self.provider = Providers.provider(opts[:provider], opts[:provider_opts] || {})
39
+ self.provider = Providers.provider(opts[:provider], **(opts[:provider_opts] || {}))
40
40
  self.enabled = false unless self.provider
41
41
  self
42
42
  end
@@ -15,7 +15,7 @@ module Sym
15
15
  self.providers << provider_class
16
16
  end
17
17
 
18
- # Detect first instance that is "alive?" and return it.
18
+ # Detect first instance tht is "alive?" and return it.
19
19
  def detect
20
20
  self.detected ||= self.providers.inject(nil) do |instance, provider_class|
21
21
  instance || (p = provider_class.new; p.alive? ? p : nil)
@@ -38,7 +38,7 @@ module Sym
38
38
 
39
39
  def provider_from_argument(p, **opts, &block)
40
40
  case p
41
- when String, Symbol
41
+ when String, Symbol
42
42
  provider_class_name = "#{p.to_s.capitalize}Provider"
43
43
  Sym::App::Password::Providers.const_defined?(provider_class_name) ?
44
44
  Sym::App::Password::Providers.const_get(provider_class_name).new(**opts, &block) :
@@ -53,4 +53,3 @@ end
53
53
 
54
54
  # Order is important — they are tried in this order for auto detect
55
55
  require 'sym/app/password/providers/memcached_provider'
56
- require 'sym/app/password/providers/drb_provider'
@@ -31,10 +31,10 @@ module Sym
31
31
  rescue ::OpenSSL::Cipher::CipherError => e
32
32
  input_handler.puts 'Invalid password. Please try again.'
33
33
 
34
- if ((retries += 1) < 3)
34
+ if (retries += 1) < 3
35
35
  retry
36
36
  else
37
- raise(Sym::Errors::InvalidPasswordProvidedForThePrivateKey.new('Invalid password.'))
37
+ raise(Sym::Errors::WrongPasswordForKey.new('Invalid password.'))
38
38
  end
39
39
  end
40
40
  else
@@ -23,11 +23,10 @@ module Sym
23
23
  # procs on a given string.
24
24
  def read!
25
25
  KeySourceCheck::CHECKS.each do |source_check|
26
- if result = source_check.detect(self) rescue nil
27
- if key_ = normalize_key(result.key)
28
- key_source_ = result.to_s
29
- return key_, key_source_
30
- end
26
+ next unless result = source_check.detect(self) rescue nil
27
+ if key_ = normalize_key(result.key)
28
+ key_source_ = result.to_s
29
+ return key_, key_source_
31
30
  end
32
31
  end
33
32
  nil
@@ -51,8 +50,6 @@ module Sym
51
50
  rescue
52
51
  nil
53
52
  end
54
- else
55
- nil
56
53
  end
57
54
  end
58
55
  end
@@ -32,7 +32,6 @@ module Sym
32
32
  :stdin, :stdout, :stderr, :kernel
33
33
 
34
34
  def initialize(opts, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = nil)
35
-
36
35
  self.stdin = stdin
37
36
  self.stdout = stdout
38
37
  self.stderr = stderr
@@ -111,16 +110,12 @@ module Sym
111
110
  end
112
111
 
113
112
  def editor
114
- editors_to_try.find { |editor| File.exist?(editor) }
113
+ editors_to_try.compact.find { |editor| File.exist?(editor) }
115
114
  end
116
115
 
117
116
  def process_output(result)
118
- unless result.is_a?(Hash)
119
- self.output.call(result)
120
- result
121
- else
122
- result
123
- end
117
+ self.output.call(result) unless result.is_a?(Hash)
118
+ result
124
119
  end
125
120
 
126
121
  private
@@ -182,7 +177,7 @@ module Sym
182
177
  args[:verbose] = opts[:verbose]
183
178
  args[:provider] = opts[:cache_provider] if opts[:cache_provider]
184
179
 
185
- self.password_cache = Sym::App::Password::Cache.instance.configure(args)
180
+ self.password_cache = Sym::App::Password::Cache.instance.configure(**args)
186
181
  end
187
182
 
188
183
  def process_edit_option
@@ -207,7 +202,7 @@ module Sym
207
202
  end
208
203
 
209
204
  def initialize_action
210
- self.action = if opts[:encrypt] then
205
+ self.action = if opts[:encrypt]
211
206
  :encr
212
207
  elsif opts[:decrypt]
213
208
  :decr
@@ -217,7 +212,7 @@ module Sym
217
212
  # If we are encrypting or decrypting, and no data has been provided, check if we
218
213
  # should read from STDIN
219
214
  def initialize_data_source
220
- if self.action && opts[:string].nil? && opts[:file].nil? && !(self.stdin.tty?)
215
+ if self.action && opts[:string].nil? && opts[:file].nil? && !self.stdin.tty?
221
216
  opts[:file] = '-'
222
217
  end
223
218
  end