sym 2.3.0 → 2.4.3

Sign up to get free protection for your applications and to get access to all the features.
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
-