shhh 1.3.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4ee814eff1d6f5243a0e3be1e31c85e0bb329512
4
- data.tar.gz: b05dbb3702143ac23f3ef6dfee34fdfd62cac03b
3
+ metadata.gz: 326b0b0a82ce4ceb7e3a56a32f1f9546f88b9c83
4
+ data.tar.gz: c58225fb321bb2d459567f96140237829efcaef0
5
5
  SHA512:
6
- metadata.gz: cb5177308cfe91b81ef89a9ad05c23e919b6c32f641f8c2ab6ff392898caad6fc7ad29525b41e55c232229e01350126c0da5a0e8a97436c0dfaf35231cf290c4
7
- data.tar.gz: 19c2cd4f58536784b3e157667dfc76f5345fdadab397cd9370f1295c537294003ca5d04f457a332a114ef7bdd19a47cba9f27195b435fa2713f48040eb090b42
6
+ metadata.gz: 4dfcedd479814b71b5a0f0d4372e717fbcc66bd44e95b4053806cb280f9147aaa84bedac3c60793fc74ce12e45acf189f5df60ead4cc885bf1be9798b97a9475
7
+ data.tar.gz: 51eec0fd771a16205bc349a3f1de230c8623c942b4021655c3986d9bb6e4e2e4f9f13c736a8f1d558c0b126c2c63b73cd27e5d71efef9f66c01c65bcf8c27024
data/.document ADDED
@@ -0,0 +1,2 @@
1
+ lib/ exe/ - README.md MANAGING-KEYS.md LICENSE
2
+
data/.yardopts ADDED
@@ -0,0 +1,5 @@
1
+
2
+ --protected
3
+ --no-private
4
+ --embed-mixin ClassMethods
5
+ --embed-mixin Shhh::Extensions::InstanceMethods
data/README.md CHANGED
@@ -3,12 +3,11 @@
3
3
  [![Gem Version](https://badge.fury.io/rb/shhh.svg)](https://badge.fury.io/rb/shhh)
4
4
  [![Downloads](http://ruby-gem-downloads-badge.herokuapp.com/shhh?type=total)](https://rubygems.org/gems/shhh)
5
5
 
6
- <br />
7
6
 
8
- [![Build Status](https://travis-ci.org/kigster/shhh.svg?branch=master)](https://travis-ci.org/kigster/shhh)
9
- [![Code Climate](https://codeclimate.com/github/kigster/shhh/badges/gpa.svg)](https://codeclimate.com/github/kigster/shhh)
10
- [![Test Coverage](https://codeclimate.com/github/kigster/shhh/badges/coverage.svg)](https://codeclimate.com/github/kigster/shhh/coverage)
11
- [![Issue Count](https://codeclimate.com/github/kigster/shhh/badges/issue_count.svg)](https://codeclimate.com/github/kigster/shhh)
7
+ [![Build Status](https://travis-ci.org/kigster/secrets-cipher-base64.svg?branch=master)](https://travis-ci.org/kigster/secrets-cipher-base64)
8
+ [![Code Climate](https://codeclimate.com/github/kigster/secrets-cipher-base64/badges/gpa.svg)](https://codeclimate.com/github/kigster/secrets-cipher-base64)
9
+ [![Test Coverage](https://codeclimate.com/github/kigster/secrets-cipher-base64/badges/coverage.svg)](https://codeclimate.com/github/kigster/secrets-cipher-base64/coverage)
10
+ [![Issue Count](https://codeclimate.com/github/kigster/secrets-cipher-base64/badges/issue_count.svg)](https://codeclimate.com/github/kigster/secrets-cipher-base64)
12
11
 
13
12
  ## Summary
14
13
 
@@ -279,6 +278,7 @@ end
279
278
  The library offers a typical `Shhh::Configuration` class which can be used to tweak some of the internals of the gem. This is really meant for a very advanced user who knows what she is doing. The following snippet is actually part of the Configuration class itself, but can be overridden by your code that uses and initializes this library. `Configuration` is a singleton, so changes to it will propagate to any subsequent calls to the gem.
280
279
 
281
280
  ```ruby
281
+ require 'zlib'
282
282
  Shhh::Configuration.configure do |config|
283
283
  config.password_cipher = 'AES-128-CBC' #
284
284
  config.data_cipher = 'AES-256-CBC'
@@ -308,16 +308,13 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/kigste
308
308
 
309
309
  ### Natural Language Based API
310
310
 
311
- This is the spec for an alternative CLI that is at feature parity with the standard flag-based CLI.
311
+ This is the proposed mini-idea/specification for an alternative CLI that is at a feature parity with the standard flag-based CLI.
312
312
 
313
313
  shhh encrypt with $key string 'hello' and save to output.enc
314
- shhh edit file 'hamlet.enc' encrypted with $key
315
- shhh decrypt file'hamlet.enc' encrypted with $key \
316
- and save to hamlet.txt
314
+ shhh edit file 'passwords.enc' encrypted with $key
315
+ shhh decrypt file /etc/secrets encrypted with $key save to ./secrets
317
316
  shhh encrypt with keychain $item file $input
318
317
 
319
-
320
-
321
318
  ## License
322
319
 
323
320
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -1,13 +1,14 @@
1
1
  require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
- #require 'guard/notifiers/terminal_notifier'
4
- RSpec::Core::RakeTask.new(:spec)
5
-
6
3
  require 'yard'
7
- YARD::Rake::YardocTask.new do |t|
4
+
5
+
6
+ YARD::Rake::YardocTask.new(:doc) do |t|
8
7
  t.files = %w(lib/**/*.rb exe/*.rb - README.md MANAGING-KEYS.md LICENSE)
9
8
  t.options.unshift('--title', '"Shhh – Symmetric Key Encryption for Your Data"')
10
- system('open doc/index.html')
9
+ t.after = ->() { exec('open doc/index.html') }
11
10
  end
12
11
 
12
+ RSpec::Core::RakeTask.new(:spec)
13
+
13
14
  task :default => :spec
data/lib/shhh/app/cli.rb CHANGED
@@ -16,10 +16,42 @@ require_relative 'output/stdout'
16
16
 
17
17
  module Shhh
18
18
  module App
19
- class CLI
19
+ # This is the main interface class for the CLI application.
20
+ # It is responsible for parsing user's input, providing help, examples,
21
+ # coordination of various sub-systems (such as PrivateKey detection), etc.
22
+ #
23
+ # Besides holding the majority of the application state, it contains
24
+ # two primary public methods: +#new+ and +#run+.
25
+ #
26
+ # The constructor is responsible for parsing the flags and determining
27
+ # the the application is about to do. It sets up input/output, but doesn't
28
+ # really execute any encryption or decryption. This happens in the +#run+
29
+ # method called immediately after +#new+.
30
+ #
31
+ # {{Shh::App::CLI}} module effectively performs the translation of
32
+ # the +opts+ object (of type {Slop::Result}) and interpretation of
33
+ # users intentions. It holds on to +opts+ for the duration of the program.
34
+ #
35
+ # == Responsibility Delegated
36
+ #
37
+ # The responsibility of determining the private key from various
38
+ # options provided is performed by the {Shhh::App::PrivateKey::Handler}
39
+ # instance. See there for more details.
40
+ #
41
+ # Subsequently, +#run+ method handles the finding of the appropriate
42
+ # {Shhh::App::Commands::Command} subclass to respond to user's request.
43
+ # Command registry, sorting, command dependencies, and finding them is
44
+ # done by the {Shhh::App::Coommands} module.
45
+ #
46
+ # User input is handled by the {Shhh::App::Input::Handler} instance, while
47
+ # the output is provided by the procs in the {Shhh::App::Output} classes.
48
+ #
49
+ # Finally, the Mac OS-X -specific usage of the KeyChain, is encapsulated
50
+ # in a cross-platform way inside the {Shhh::App::Keychain} module.
20
51
 
52
+ class CLI
21
53
  attr_accessor :opts, :output_proc, :print_proc, :write_proc,
22
- :action, :password, :key
54
+ :action, :password, :key, :input_handler, :key_handler
23
55
 
24
56
  def initialize(argv)
25
57
  begin
@@ -30,19 +62,27 @@ module Shhh
30
62
  end
31
63
  configure_color(argv)
32
64
  select_output_stream
33
- self.action = { opts[:encrypt] => :encr, opts[:decrypt] => :decr }[true]
65
+
66
+ initialize_input_handler
67
+ initialize_key_handler
68
+ self.action = { opts[:encrypt] => :encr, opts[:decrypt] => :decr }[true]
34
69
  end
35
70
 
36
71
  def run
37
72
  return Shhh::App.exit_code if Shhh::App.exit_code != 0
73
+ unless opts[:generate]
74
+ self.key = PrivateKey::Handler.new(opts,
75
+ input_handler).key
76
+ end
38
77
 
39
- self.key = PrivateKey::Handler.new(self.opts).key unless opts[:generate]
40
-
41
- return self.output_proc.call(command.run) if command
42
-
43
- # command was not found. Reset output to printing, and return an error.
44
- self.output_proc = print_proc
45
- command_not_found_error!
78
+ if command
79
+ result = command.run
80
+ output_proc.call(result)
81
+ else
82
+ # command was not found. Reset output to printing, and return an error.
83
+ self.output_proc = print_proc
84
+ command_not_found_error!
85
+ end
46
86
 
47
87
  rescue ::OpenSSL::Cipher::CipherError => e
48
88
  error type: 'Cipher Error',
@@ -56,6 +96,10 @@ module Shhh
56
96
  reason: (opts[:password] ? nil : 'Perhaps the key is password-protected?'),
57
97
  exception: e
58
98
 
99
+ rescue Shhh::Errors::InvalidPasswordPrivateKey => e
100
+ error type: 'Error',
101
+ details: 'Invalid password, private key can not decrypted.'
102
+
59
103
  rescue Shhh::Errors::Error => e
60
104
  error type: 'Error',
61
105
  details: e.message,
@@ -86,7 +130,6 @@ module Shhh
86
130
  self.output_proc = opts[:output] ? self.write_proc : self.print_proc
87
131
  end
88
132
 
89
-
90
133
  def configure_color(argv)
91
134
  if opts[:no_color]
92
135
  Colored2.disable! # reparse options without the colors to create new help msg
@@ -94,6 +137,16 @@ module Shhh
94
137
  end
95
138
  end
96
139
 
140
+
141
+ def initialize_input_handler(handler = Input::Handler.new)
142
+ self.input_handler = handler
143
+ end
144
+
145
+ def initialize_key_handler
146
+ self.key_handler = PrivateKey::Handler.new(self.opts, input_handler)
147
+ end
148
+
149
+
97
150
  def command_not_found_error!
98
151
  if key
99
152
  h = opts.to_hash
@@ -142,7 +195,6 @@ module Shhh
142
195
  o.separator ''
143
196
  end
144
197
  rescue StandardError => e
145
- error exception: e
146
198
  raise(e)
147
199
  end
148
200
  end
@@ -14,7 +14,7 @@ module Shhh
14
14
 
15
15
  if opts[:password]
16
16
  new_private_key = encr_password(new_private_key,
17
- Shhh::App::Input::Handler.new_password)
17
+ cli.input_handler.new_password)
18
18
  end
19
19
 
20
20
  clipboard_copy(new_private_key) if opts[:copy]
@@ -4,7 +4,7 @@ module Shhh
4
4
  module App
5
5
  module Input
6
6
  class Handler
7
- def self.ask
7
+ def ask
8
8
  retries ||= 0
9
9
  prompt('Password: ', :green)
10
10
  rescue ::OpenSSL::Cipher::CipherError
@@ -13,11 +13,15 @@ module Shhh
13
13
  nil
14
14
  end
15
15
 
16
- def self.prompt(message, color)
16
+ def puts(*args)
17
+ STDERR.puts args
18
+ end
19
+
20
+ def prompt(message, color)
17
21
  HighLine.new(STDIN, STDERR).ask(message.bold) { |q| q.echo = '•'.send(color) }
18
22
  end
19
23
 
20
- def self.new_password
24
+ def new_password
21
25
  password = prompt('New Password : ', :blue)
22
26
  password_confirm = prompt('Confirm Password : ', :blue)
23
27
 
@@ -7,7 +7,7 @@ module Shhh
7
7
 
8
8
  attr_accessor :encrypted_key, :input_handler
9
9
 
10
- def initialize(encrypted_key, input_handler = Shhh::App::Input::Handler)
10
+ def initialize(encrypted_key, input_handler)
11
11
  self.encrypted_key = encrypted_key
12
12
  self.input_handler = input_handler
13
13
  end
@@ -20,8 +20,8 @@ module Shhh
20
20
  retries ||= 0
21
21
  decrypted_key = decrypt(password)
22
22
  rescue ::OpenSSL::Cipher::CipherError => e
23
- STDERR.puts 'Invalid password. Please try again.'
24
- ((retries += 1) < 3) ? retry : raise(Shhh::Errors::InvalidPasswordPrivateKey.new(e))
23
+ input_handler.puts 'Invalid password. Please try again.'
24
+ ((retries += 1) < 3) ? retry : raise(Shhh::Errors::InvalidPasswordPrivateKey.new('Invalid password.'))
25
25
  end
26
26
  else
27
27
  decrypted_key = encrypted_key
@@ -1,7 +1,7 @@
1
1
  module Shhh
2
2
  module App
3
3
  module PrivateKey
4
- class Detector < Struct.new(:opts) # :nodoc:
4
+ class Detector < Struct.new(:opts, :input_handler) # :nodoc:s
5
5
  @mapping = Hash.new
6
6
  class << self
7
7
  attr_reader :mapping
@@ -13,20 +13,28 @@ module Shhh
13
13
 
14
14
  def key
15
15
  self.class.mapping.each_pair do |options_key, key_proc|
16
- return key_proc.call(self.opts[options_key]) if self.opts[options_key]
16
+ return key_proc.call(opts[options_key], self) if opts[options_key]
17
17
  end
18
18
  nil
19
19
  end
20
20
  end
21
21
 
22
- Detector.register :private_key, ->(key) { key }
23
- Detector.register :interactive, -> { Input::Handler.prompt('Private Key: ', :magenta) }
24
- Detector.register :keychain, ->(key_name) { KeyChain.new(key_name).find }
25
- Detector.register :keyfile, ->(file) {
22
+ Detector.register :private_key,
23
+ ->(key, *) { key }
24
+
25
+ Detector.register :interactive,
26
+ ->(*, detector) { detector.input_handler.prompt('Please paste your private key: ', :magenta) }
27
+
28
+ Detector.register :keychain,
29
+ ->(key_name, * ) { KeyChain.new(key_name).find }
30
+
31
+ Detector.register :keyfile,
32
+ ->(file, *) {
26
33
  begin
27
34
  ::File.read(file)
28
35
  rescue Errno::ENOENT
29
36
  raise Shhh::Errors::FileNotFound.new("Encryption key file #{file} was not found.")
37
+ nil
30
38
  end
31
39
  }
32
40
  end
@@ -1,6 +1,7 @@
1
1
  require_relative 'detector'
2
2
  require_relative 'base64_decoder'
3
3
  require_relative 'decryptor'
4
+ require_relative '../input/handler'
4
5
  module Shhh
5
6
  module App
6
7
  module PrivateKey
@@ -9,24 +10,32 @@ module Shhh
9
10
  class Handler
10
11
  include Shhh
11
12
 
12
- attr_accessor :opts, :key
13
+ attr_accessor :opts, :input_handler
14
+ attr_writer :key
15
+
16
+ def initialize(opts, input_handler)
17
+ self.opts = opts
18
+ self.input_handler = input_handler
19
+ end
13
20
 
14
- def initialize(opts)
15
- self.opts = opts
16
21
 
22
+ # @return [String] key Private key detected
23
+ def key
24
+ return @key if @key
17
25
 
18
- self.key =
19
- begin
20
- Detector.new(opts).key
21
- rescue Shhh::Errors::Error => e
22
- if Shhh::App::Args.new(opts).key? && key.nil?
23
- raise e
24
- end
26
+ @key = begin
27
+ Detector.new(opts, input_handler).key
28
+ rescue Shhh::Errors::Error => e
29
+ if Shhh::App::Args.new(opts).key? && key.nil?
30
+ raise e
25
31
  end
32
+ end
26
33
 
27
- if key && key.length > 45
28
- self.key = Decryptor.new(Base64Decoder.new(key).key).key
34
+ if @key && @key.length > 45
35
+ @key = Decryptor.new(Base64Decoder.new(key).key, input_handler).key
29
36
  end
37
+
38
+ @key
30
39
  end
31
40
  end
32
41
  end
data/lib/shhh/app.rb CHANGED
@@ -1,12 +1,16 @@
1
1
  require 'shhh/data'
2
2
  require 'active_support/inflector'
3
3
  module Shhh
4
- # The +App+ Module is responsible for handing user input and executing commands.
5
- # Central class in this module is the +CLI+ class.
6
-
7
- # This module is responsible for printing pretty errors and maintaining the
8
- # future exit code class-global variable.
9
4
 
5
+ # The {Shhh::App} Module is responsible for handing user input and executing commands.
6
+ # Central class in this module is the {Shhh::App::CLI} class.
7
+ #
8
+ # Methods in this module are responsible for reporting errors and
9
+ # maintaining the future exit code class-global variable.
10
+ #
11
+ # It also contains several helpers that enable some additional functionality
12
+ # on Mac OS-X (such as using KeyChain for storing encryption keys).
13
+ #
10
14
  module App
11
15
  class << self
12
16
  attr_accessor :exit_code
@@ -2,10 +2,11 @@ require 'base64'
2
2
  require_relative 'configuration'
3
3
 
4
4
  module Shhh
5
- #
6
- # +CipherHandler+ contains cipher-related utilities necessary to create
7
- # ciphers, and seed them with the salt or iV vector,
8
- #
5
+
6
+ # {Shhh::CipherHandler} contains cipher-related utilities necessary to create
7
+ # ciphers, and seed them with the salt or iV vector. It also defines the
8
+ # internal structure {Shhh::CipherHandler::CipherStruct} which is a key
9
+ # struct used in constructing cipher and saving it with the data packet.
9
10
  module CipherHandler
10
11
 
11
12
  CREATE_CIPHER = ->(name) { ::OpenSSL::Cipher.new(name) }
@@ -1,8 +1,24 @@
1
1
  module Shhh
2
- # Application configuration Singleton class.
2
+ # This class encapsulates application configuration, and exports
3
+ # a familiar method +#configure+ for defining configuration in a
4
+ # block.
5
+ #
3
6
  # It's values are requested by the library upon encryption or
4
7
  # decryption, or any other operation.
5
-
8
+ #
9
+ # == Example
10
+ #
11
+ # The following is an actual initialization from the code of this
12
+ # library. You may override any of the value defined below in your
13
+ # code, but _before_ you _use_ library's encryption methods.
14
+ #
15
+ # Shhh::Configuration.configure do |config|
16
+ # config.password_cipher = 'AES-128-CBC' #
17
+ # config.data_cipher = 'AES-256-CBC'
18
+ # config.private_key_cipher = config.data_cipher
19
+ # config.compression_enabled = true
20
+ # config.compression_level = Zlib::BEST_COMPRESSION
21
+ # end
6
22
  class Configuration
7
23
  class << self
8
24
  attr_accessor :config
data/lib/shhh/errors.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  module Shhh
2
+ # All public exceptions of this library are here.
2
3
  module Errors
3
4
  # Exceptions superclass for this library.
4
5
  class Shhh::Errors::Error < StandardError; end
data/lib/shhh/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Shhh
2
- VERSION = '1.3.0'
2
+ VERSION = '1.4.0'
3
3
  end
data/lib/shhh.rb CHANGED
@@ -13,34 +13,70 @@ Shhh::Configuration.configure do |config|
13
13
  end
14
14
 
15
15
  #
16
- # _Include_ +Shhh+ in your class to enable functionality of this library.
17
- #
18
- # Once included, you would normally use +#encr+ and +#decr+ instance methods to perform
19
- # encryption and decryption of object of any type using a symmetric key encryption.
20
- #
21
- # You could also use +#encr_password+ and +#decr_password+ if you prefer to encrypt
22
- # with a password instead. The encryption key is generated from the password in that
23
- # case.
24
- #
25
- # Create a new key with +#create_private_key+ class method, which returns a new key every
26
- # time it's called, or with +#private_key+ class method, which either assigns, or creates
27
- # and caches the private key at a class level.
28
- #
29
- # ```ruby
30
- # require 'shhh'
31
- # class TestClass
32
- # include Shhh
33
- # private_key ENV['PRIVATE_KEY']
34
- #
35
- # def sensitive_value=(value)
36
- # @sensitive_value = encr(value, self.class.private_key)
37
- # end
38
- #
39
- # def sensitive_value
40
- # decr(@sensitive_value, self.class.private_key)
41
- # end
42
- # end
43
- # ```
16
+ # == Using Shhh Library
17
+ #
18
+ # This library is a "wrapper" that allows you to take advantage of the
19
+ # symmetric encryption functionality provided by the {OpenSSL} gem (and the
20
+ # underlying C library). In order to use the library in your ruby classes, you
21
+ # should _include_ the module {Shhh}.
22
+ #
23
+ # The including class is decorated with four instance methods from the
24
+ # module {Shhh::Extensions::InstanceMethods} and two class methods from
25
+ # {Shhh::Extensions::ClassMethods} for specifics, please refer there.
26
+ #
27
+ # The two main instance methods are +#encr+ and +#decr+, which as the name
28
+ # implies, perform two-way symmetric encryption and decryption of any Ruby object
29
+ # that can be +marshaled+.
30
+ #
31
+ # Two additional instance methods +#encr_password+ and +#decr_password+ turn on
32
+ # password-based encryption, which actually uses a password to construct a 128-bit
33
+ # long private key, and then uses that in the encryption of the data.
34
+ # You could use them to encrypt data with a password instead of a randomly
35
+ # generated private key.
36
+ #
37
+ # The library comes with a rich CLI interface, which is mostly encapsulated under the
38
+ # +Shhh::App+ namespace.
39
+ #
40
+ # The +shhh+ executable that is the "app" in this case, and is a _user_ of the
41
+ # API methods +#encr+ and +#decr+.
42
+ #
43
+ # Create a new key with +#create_private_key+ class method, which returns a new
44
+ # key every time it's called, or with +#private_key+ class method, which either
45
+ # assigns, or creates and caches the private key at a class level.
46
+ #
47
+ # == Example
48
+ #
49
+ # require 'shhh'
50
+ #
51
+ # class TestClass
52
+ # include Shhh
53
+ # # read the key from environmant variable and assign to this class.
54
+ # private_key ENV['PRIVATE_KEY']
55
+ #
56
+ # def sensitive_value=(value)
57
+ # @sensitive_value = encr(value, self.class.private_key)
58
+ # end
59
+ #
60
+ # def sensitive_value
61
+ # decr(@sensitive_value, self.class.private_key)
62
+ # end
63
+ # end
64
+ #
65
+ # == Private Key
66
+ #
67
+ # They private key can be generated by +TestClass.create_private_key+
68
+ # which returns but does not store a new random 256-bit key.
69
+ #
70
+ # The key can be assigned and saved, or auto-generated and saved using the
71
+ # +#private_key+ method on the class that includes the +Shhh+ module.
72
+ #
73
+ # Each class including the +Shhh+ module would get their own +#private_key#
74
+ # class-instance variable accessor, and a possible value.
75
+ #
76
+ # For example:
77
+ #
78
+ #
79
+
44
80
  module Shhh
45
81
  extend RequireDir
46
82
  init(__FILE__)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shhh
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Gredeskoul
@@ -176,10 +176,12 @@ extensions: []
176
176
  extra_rdoc_files: []
177
177
  files:
178
178
  - ".codeclimate.yml"
179
+ - ".document"
179
180
  - ".gitignore"
180
181
  - ".rspec"
181
182
  - ".rubocop.yml"
182
183
  - ".travis.yml"
184
+ - ".yardopts"
183
185
  - Gemfile
184
186
  - LICENSE
185
187
  - MANAGING-KEYS.md