sym 2.3.0 → 2.4.3

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +55 -2
  3. data/README.md +106 -70
  4. data/Rakefile +3 -2
  5. data/bin/sym.completion +6 -2
  6. data/lib/sym.rb +28 -15
  7. data/lib/sym/app.rb +1 -3
  8. data/lib/sym/app/args.rb +5 -1
  9. data/lib/sym/app/cli.rb +54 -6
  10. data/lib/sym/app/cli_slop.rb +35 -23
  11. data/lib/sym/app/commands/base_command.rb +12 -19
  12. data/lib/sym/app/commands/bash_completion.rb +19 -3
  13. data/lib/sym/app/commands/decrypt.rb +1 -1
  14. data/lib/sym/app/commands/encrypt.rb +1 -1
  15. data/lib/sym/app/commands/generate_key.rb +7 -3
  16. data/lib/sym/app/commands/keychain_add_key.rb +7 -2
  17. data/lib/sym/app/commands/open_editor.rb +1 -1
  18. data/lib/sym/app/commands/password_protect_key.rb +9 -4
  19. data/lib/sym/app/commands/print_key.rb +3 -3
  20. data/lib/sym/app/commands/show_examples.rb +25 -17
  21. data/lib/sym/app/commands/show_help.rb +2 -2
  22. data/lib/sym/app/keychain.rb +5 -0
  23. data/lib/sym/app/output/base.rb +3 -7
  24. data/lib/sym/app/output/file.rb +0 -1
  25. data/lib/sym/app/output/noop.rb +2 -1
  26. data/lib/sym/app/password/providers.rb +4 -0
  27. data/lib/sym/app/password/providers/memcached_provider.rb +1 -1
  28. data/lib/sym/app/private_key/base64_decoder.rb +1 -0
  29. data/lib/sym/app/private_key/decryptor.rb +1 -0
  30. data/lib/sym/app/private_key/detector.rb +45 -26
  31. data/lib/sym/app/private_key/handler.rb +20 -25
  32. data/lib/sym/app/private_key/key_source_check.rb +89 -0
  33. data/lib/sym/application.rb +115 -33
  34. data/lib/sym/configuration.rb +1 -0
  35. data/lib/sym/constants.rb +24 -0
  36. data/lib/sym/data/decoder.rb +2 -1
  37. data/lib/sym/data/wrapper_struct.rb +1 -1
  38. data/lib/sym/extensions/stdlib.rb +1 -0
  39. data/lib/sym/version.rb +1 -1
  40. data/sym.gemspec +1 -1
  41. metadata +5 -4
  42. data/lib/sym/encrypted_file.rb +0 -34
@@ -2,62 +2,80 @@ require 'colored2'
2
2
  require 'sym'
3
3
  require 'sym/app'
4
4
  require 'openssl'
5
+ require 'json'
5
6
 
6
7
  module Sym
7
8
  class Application
8
9
 
9
10
  attr_accessor :opts,
10
- :opts_hash,
11
+ :opts_original,
12
+ :opts,
13
+ :provided_options,
11
14
  :args,
12
15
  :action,
13
16
  :key,
17
+ :key_source,
14
18
  :input_handler,
15
19
  :key_handler,
16
20
  :result,
17
21
  :password_cache
18
22
 
19
23
  def initialize(opts)
20
- self.opts = opts
21
- self.opts_hash = opts.respond_to?(:to_hash) ? opts.to_hash : opts
22
- self.args = ::Sym::App::Args.new(opts_hash)
24
+ self.opts_original = opts
25
+ self.opts = opts.is_a?(Hash) ? opts : opts.to_hash
23
26
 
27
+ process_negated_option(opts[:negate]) if opts[:negate]
28
+ self.args = ::Sym::App::Args.new(self.provided_options)
29
+
30
+ initialize_action
31
+ initialize_data_source
24
32
  initialize_password_cache
25
33
  initialize_input_handler
26
- initialize_key_handler
27
- initialize_action
28
34
  end
29
35
 
30
- def initialize_action
31
- self.action = if opts[:encrypt] then
32
- :encr
33
- elsif opts[:decrypt]
34
- :decr
35
- end
36
+ def provided_options
37
+ provided_opts = self.opts.clone
38
+ provided_opts.delete_if { |k, v| !v }
39
+ provided_opts
40
+ end
41
+
42
+ def provided_safe_options
43
+ provided_options.map do |k, v|
44
+ k == :key && [44, 45].include?(v.size) ?
45
+ [k, '[reducted]'] :
46
+ [k, v]
47
+ end.to_h
48
+ end
49
+
50
+ def provided_flags
51
+ provided_flags = provided_options
52
+ provided_flags.delete_if { |k, v| ![false, true].include?(v) }
53
+ provided_flags.keys
54
+ end
55
+
56
+ def provided_value_options
57
+ provided = provided_safe_options
58
+ provided.delete_if { |k, v| [false, true].include?(v) }
59
+ provided
36
60
  end
37
61
 
38
62
  def execute!
39
- if !args.generate_key? && (args.require_key? || args.specify_key?)
40
- log :debug, 'operation requires a key...'
41
- self.key = Sym::App::PrivateKey::Handler.new(opts, input_handler, password_cache).key
42
- unless self.key
43
- log :error, 'Unable to determine the key, which appears to be required'
44
- raise Sym::Errors::NoPrivateKeyFound, 'Private key is required'
45
- end
46
- end
47
- log :info, "detected command [#{command.class.name}]"
63
+ initialize_key_source
48
64
  unless command
49
- raise Sym::Errors::InsufficientOptionsError, 'Can not determine what to do from the options ' + opts_hash.keys.reject { |k| !opts[k] }.to_s
65
+ raise Sym::Errors::InsufficientOptionsError,
66
+ " Can not determine what to do
67
+ from the options: \ n " +
68
+ " #{self.provided_options.inspect.green.bold}\n" +
69
+ "and flags #{self.provided_flags.to_s.green.bold}"
70
+ end
71
+ log :info, "command located is #{command.class.name.blue.bold}"
72
+ self.result = command.execute.tap do |result|
73
+ log :info, "result is #{result.nil? ? 'nil' : result[0..10].to_s.blue.bold }..." if opts[:trace]
50
74
  end
51
- self.result = command.execute
52
- end
53
-
54
- def log(*args)
55
- Sym::App.log(*args, **opts)
56
75
  end
57
76
 
58
77
  def execute
59
78
  execute!
60
-
61
79
  rescue ::OpenSSL::Cipher::CipherError => e
62
80
  { reason: 'Invalid key provided',
63
81
  exception: e }
@@ -67,8 +85,8 @@ module Sym
67
85
  exception: e }
68
86
 
69
87
  rescue TypeError => e
70
- if e.message =~ /marshal/
71
- { reason: 'Corrupt source data or invalid/corrupt key provided',
88
+ if e.message =~ /marshal/m
89
+ { reason: 'Corrupt source data or invalid/corrupt key provided',
72
90
  exception: e }
73
91
  else
74
92
  { exception: e }
@@ -84,10 +102,17 @@ module Sym
84
102
  @command
85
103
  end
86
104
 
105
+ def log(*args)
106
+ Sym::App.log(*args, **opts)
107
+ end
108
+
87
109
  def editor
88
110
  editors_to_try.find { |editor| File.exist?(editor) }
89
111
  end
90
112
 
113
+
114
+ private
115
+
91
116
  def editors_to_try
92
117
  [
93
118
  ENV['EDITOR'],
@@ -108,17 +133,74 @@ module Sym
108
133
  end
109
134
 
110
135
  def initialize_key_handler
111
- self.key_handler = ::Sym::App::PrivateKey::Handler.new(self.opts, input_handler, password_cache)
136
+ self.key_handler = ::Sym::App::PrivateKey::Handler.new(opts, input_handler, password_cache)
112
137
  end
113
138
 
114
139
  def initialize_password_cache
115
140
  args = {}
116
- args[:timeout] = opts[:cache_for].to_i if opts[:cache_for]
117
- args[:enabled] = opts[:cache_password]
141
+ args[:timeout] = (opts[:cache_timeout] || ENV['SYM_CACHE_TTL'] || Sym::Configuration.config.password_cache_timeout).to_i
142
+ args[:enabled] = opts[:cache_passwords]
118
143
  args[:verbose] = opts[:verbose]
119
144
  args[:provider] = opts[:cache_provider] if opts[:cache_provider]
120
145
 
121
146
  self.password_cache = Sym::App::Password::Cache.instance.configure(args)
122
147
  end
148
+
149
+ def process_negated_option(file)
150
+ opts.delete(:negate)
151
+ opts[:file] = file
152
+ extension = Sym.config.encrypted_file_extension
153
+ if file.end_with?('.enc')
154
+ opts[:decrypt] = true
155
+ opts[:output] = file.gsub(/\.#{extension}/, '')
156
+ opts.delete(:output) if opts[:output] == ''
157
+ else
158
+ opts[:encrypt] = true
159
+ opts[:output] = "#{file}.#{extension}"
160
+ end
161
+ end
162
+
163
+ def initialize_action
164
+ self.action = if opts[:encrypt] then
165
+ :encr
166
+ elsif opts[:decrypt]
167
+ :decr
168
+ end
169
+ end
170
+
171
+ # If we are encrypting or decrypting, and no data has been provided, check if we
172
+ # should read from STDIN
173
+ def initialize_data_source
174
+ if self.action && opts[:string].nil? && opts[:file].nil? && !(STDIN.tty?)
175
+ opts[:file] = '-'
176
+ end
177
+ end
178
+
179
+ # If no key is provided with command line options, check the default
180
+ # key location (which can be changed via Configuration class).
181
+ # In any case, attempt to initialize the key one way or another.
182
+ def initialize_key_source
183
+ detect_key_source
184
+
185
+ if args.require_key? && !self.key
186
+ log :error, 'Unable to determine the key, which appears to be required with current args'
187
+ raise Sym::Errors::NoPrivateKeyFound, 'Private key is required when ' + provided_flags.join(', ') << 'ing.'
188
+ end
189
+ log :debug, "initialize_key_source: detected key ends with [...#{(key ? key[-5..-1] : 'nil').bold.magenta}]"
190
+ log :debug, "opts: #{self.provided_value_options.to_s.green.bold}"
191
+ log :debug, "flags: #{self.provided_flags.to_s.green.bold}"
192
+ end
193
+
194
+ def detect_key_source
195
+ initialize_key_handler
196
+ self.key = self.key_handler.key
197
+ if self.key
198
+ self.key_source = key_handler.key_source
199
+ if key_source =~ /^default_file/
200
+ opts[:key] = self.key
201
+ end
202
+ log :info, "key was detected from source #{key_source.to_s.bold.green}"
203
+ end
204
+ end
123
205
  end
124
206
  end
@@ -39,5 +39,6 @@ module Sym
39
39
  attr_accessor :compression_enabled, :compression_level
40
40
  attr_accessor :password_cache_default_provider, :password_cache_timeout
41
41
  attr_accessor :password_cache_arguments
42
+ attr_accessor :default_key_file, :encrypted_file_extension
42
43
  end
43
44
  end
@@ -0,0 +1,24 @@
1
+ require 'logger'
2
+ module Sym
3
+ module Constants
4
+ module Completion
5
+ FILE = '.sym.completion'.freeze
6
+ PATH = "#{ENV['HOME']}/#{FILE}".freeze
7
+ Config = {
8
+ file: File.expand_path('../../../bin/sym.completion', __FILE__),
9
+ script: "[[ -f '#{PATH}' ]] && source '#{PATH}'",
10
+ }.freeze
11
+
12
+ end
13
+
14
+ module Log
15
+ NIL = Logger.new(nil).freeze # empty logger
16
+ LOG = Logger.new(STDERR).freeze
17
+ end
18
+
19
+ ENV_ARGS_VARIABLE_NAME = 'SYM_ARGS'.freeze
20
+ SYM_KEY_FILE = "#{ENV['HOME']}/.sym.key"
21
+ end
22
+ end
23
+
24
+
@@ -1,6 +1,7 @@
1
- require_relative '../errors'
1
+ require 'sym/errors'
2
2
  require 'base64'
3
3
  require 'zlib'
4
+
4
5
  module Sym
5
6
  module Data
6
7
  class Decoder
@@ -1,4 +1,4 @@
1
- require_relative '../errors'
1
+ require 'sym/errors'
2
2
  module Sym
3
3
  module Data
4
4
  class WrapperStruct < Struct.new(
@@ -21,3 +21,4 @@ class Object
21
21
  end
22
22
  end
23
23
  end
24
+
data/lib/sym/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Sym
2
- VERSION = '2.3.0'
2
+ VERSION = '2.4.3'
3
3
  DESCRIPTION = <<-eof
4
4
  Sym is a command line utility and a Ruby API that makes it trivial to encrypt and decrypt
5
5
  sensitive data. Unlike many other existing encryption tools, sym focuses on usability and
data/sym.gemspec CHANGED
@@ -48,4 +48,4 @@ EOF
48
48
  spec.add_development_dependency 'rspec', '~> 3'
49
49
  spec.add_development_dependency 'rspec-its'
50
50
  spec.add_development_dependency 'yard'
51
- end
51
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sym
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Gredeskoul
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-02-25 00:00:00.000000000 Z
11
+ date: 2017-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colored2
@@ -274,15 +274,16 @@ files:
274
274
  - lib/sym/app/private_key/decryptor.rb
275
275
  - lib/sym/app/private_key/detector.rb
276
276
  - lib/sym/app/private_key/handler.rb
277
+ - lib/sym/app/private_key/key_source_check.rb
277
278
  - lib/sym/app/short_name.rb
278
279
  - lib/sym/application.rb
279
280
  - lib/sym/cipher_handler.rb
280
281
  - lib/sym/configuration.rb
282
+ - lib/sym/constants.rb
281
283
  - lib/sym/data.rb
282
284
  - lib/sym/data/decoder.rb
283
285
  - lib/sym/data/encoder.rb
284
286
  - lib/sym/data/wrapper_struct.rb
285
- - lib/sym/encrypted_file.rb
286
287
  - lib/sym/errors.rb
287
288
  - lib/sym/extensions/class_methods.rb
288
289
  - lib/sym/extensions/instance_methods.rb
@@ -315,7 +316,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
315
316
  version: '0'
316
317
  requirements: []
317
318
  rubyforge_project:
318
- rubygems_version: 2.6.8
319
+ rubygems_version: 2.5.2
319
320
  signing_key:
320
321
  specification_version: 4
321
322
  summary: Super easy to use encryption library & a CLI with a strong aes-256-cbc cipher
@@ -1,34 +0,0 @@
1
- require 'sym'
2
- require 'sym/application'
3
- require 'sym/app/args'
4
-
5
- module Sym
6
- # This class provides a convenience wrapper for opening and reading
7
- # encrypted files as they were regular files, and then possibly writing
8
- # changes to them later.
9
-
10
- class EncryptedFile
11
-
12
- include Sym
13
-
14
- attr_reader :application, :file, :key_id, :key_type, :app_args
15
-
16
- def initialize(file:, key_id:, key_type:)
17
- @file = file
18
- @key_id = key_id
19
- @key_type = key_type.to_sym
20
- @app_args = { file: file, key_type => key_id, decrypt: true }
21
- @application = Sym::Application.new(self.app_args)
22
- end
23
-
24
- def read
25
- @content = application.execute! unless @content
26
- @content
27
- end
28
-
29
- def write
30
- Sym::Application.new(file: file, key_type => key_id, encrypt: true, output: file).execute
31
- end
32
- end
33
- end
34
-