muchkeys 0.3.3 → 0.3.6
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.
- checksums.yaml +4 -4
- data/lib/muchkeys/cli/validation.rb +17 -0
- data/lib/muchkeys/cli/validator.rb +34 -9
- data/lib/muchkeys/cli.rb +65 -24
- data/lib/muchkeys/errors.rb +4 -3
- data/lib/muchkeys/version.rb +1 -1
- data/lib/muchkeys.rb +43 -53
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7b1691f5996a3bbe70a2dc689f6168b08859f5a7
|
4
|
+
data.tar.gz: 1d49e1b24e67b72c55adf5ed724e0269e0ac0a0a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4ec21f49f82ce55a894ce5fbfaf8b5a567fe56dd0313576e17d7a1cc553dd08a6895877df76176694e90e890e8d6063ba146f1032e482ed437bbca2c54a9a3c
|
7
|
+
data.tar.gz: c49e8fe3eab027bfe23c032eba3bae91dd54e9320035221a5fac78471150f4f646cb9bd8628730a20298a799ca64dfa8e0fab4d61f2bd97037f721ab6b00c300
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require_relative "../errors"
|
2
|
+
require_relative "./validation"
|
2
3
|
|
3
4
|
class MuchKeys::CLI::Validator
|
4
5
|
|
@@ -6,24 +7,48 @@ class MuchKeys::CLI::Validator
|
|
6
7
|
raise MuchKeys::CLIOptionsError, primary_mode_error_message unless options_has_one_mode?(options)
|
7
8
|
end
|
8
9
|
|
9
|
-
def self.
|
10
|
-
|
11
|
-
|
10
|
+
def self.validate_encrypt_options(options)
|
11
|
+
validation = MuchKeys::CLI::Validation.new
|
12
|
+
if !options[:file] || !options[:public_key]
|
13
|
+
validation.errors << "--decrypt needs the --file and --public_key set."
|
14
|
+
end
|
15
|
+
|
16
|
+
validation
|
12
17
|
end
|
13
18
|
|
14
|
-
def self.
|
19
|
+
def self.validate_decrypt_options(options)
|
20
|
+
validation = MuchKeys::CLI::Validation.new
|
21
|
+
if options[:consul_key] && options[:public_key] && options[:private_key]
|
22
|
+
validate_automatic_certificate(validation, options)
|
23
|
+
else
|
24
|
+
validation.errors << "--decrypt needs the --consul_key, --public_key and --private_key set."
|
25
|
+
end
|
26
|
+
|
27
|
+
validation
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.validate_automatic_certificate(chained_validation, options)
|
31
|
+
# i won't mutate chained_validation on principle
|
32
|
+
validation = MuchKeys::CLI::Validation.new
|
33
|
+
validation.errors = chained_validation.errors.dup
|
15
34
|
key_name = options[:consul_key]
|
16
|
-
abort "--decrypt needs the --consul_key option passed." if !key_name
|
17
35
|
|
18
36
|
if !secret_adapter.auto_certificates_exist_for_key?(key_name)
|
19
37
|
certfile_expected = secret_adapter.certfile_name(key_name)
|
20
|
-
|
21
|
-
|
38
|
+
validation.errors << "--decrypt needs the --public_key option passed or a PEM file needs to be at #{certfile_expected}." if !options[:public_key]
|
39
|
+
validation.errors << "--decrypt needs the --private_key option passed or a PEM file needs to be at #{certfile_expected}." if !options[:private_key]
|
22
40
|
end
|
41
|
+
|
42
|
+
validation
|
23
43
|
end
|
24
44
|
|
25
|
-
def self.
|
26
|
-
|
45
|
+
def self.validate_plain_options(options)
|
46
|
+
validation = MuchKeys::CLI::Validation.new
|
47
|
+
if !options[:consul_key]
|
48
|
+
validation.errors << "--plain needs the --consul_key option passed."
|
49
|
+
end
|
50
|
+
|
51
|
+
validation
|
27
52
|
end
|
28
53
|
|
29
54
|
def self.options_has_one_mode?(options)
|
data/lib/muchkeys/cli.rb
CHANGED
@@ -8,18 +8,8 @@ module MuchKeys
|
|
8
8
|
# I'd like to not be doing this kind of check
|
9
9
|
# But this is tricky because we need to know
|
10
10
|
# later if help was invoked so we don't execute run with blank options.
|
11
|
-
@
|
11
|
+
@cli_should_exit = false
|
12
12
|
parsed = parse_options(arguments)
|
13
|
-
return if @help_invoked
|
14
|
-
|
15
|
-
begin
|
16
|
-
set_primary_mode
|
17
|
-
rescue MuchKeys::CLIOptionsError => e
|
18
|
-
puts e.message
|
19
|
-
puts @opts
|
20
|
-
end
|
21
|
-
|
22
|
-
configure_muchkeys
|
23
13
|
end
|
24
14
|
|
25
15
|
def parse_options(arguments)
|
@@ -32,14 +22,11 @@ module MuchKeys
|
|
32
22
|
o.string "--private_key", "Location of your private key"
|
33
23
|
o.string "--public_key", "Location of your public key"
|
34
24
|
|
35
|
-
|
36
|
-
o.string "--file", "File to encrypt"
|
25
|
+
o.string "-f", "--file", "File to encrypt"
|
37
26
|
o.string "-c", "--consul_key", "Consul key to decrypt"
|
38
27
|
|
39
|
-
o.
|
40
|
-
|
41
|
-
@help_invoked = true
|
42
|
-
end
|
28
|
+
o.bool "-h", "--help", "Shows usage"
|
29
|
+
o.bool "-v", "--version", "Prints the version number"
|
43
30
|
end
|
44
31
|
end
|
45
32
|
|
@@ -58,20 +45,53 @@ module MuchKeys
|
|
58
45
|
|
59
46
|
# this guy figures out the appropriate action to take given CLI options
|
60
47
|
def run
|
61
|
-
|
48
|
+
|
49
|
+
check_for_early_exit_actions
|
50
|
+
return if @cli_should_exit
|
51
|
+
|
52
|
+
begin
|
53
|
+
set_primary_mode
|
54
|
+
rescue MuchKeys::CLIOptionsError => e
|
55
|
+
puts e.message
|
62
56
|
puts @opts
|
63
|
-
return
|
64
57
|
end
|
65
58
|
|
59
|
+
return if @cli_should_exit
|
60
|
+
|
61
|
+
configure_muchkeys
|
62
|
+
|
66
63
|
if @opts[:encrypt]
|
67
|
-
|
68
|
-
|
64
|
+
options = { file: @opts[:file], public_key: @opts[:public_key] }
|
65
|
+
validation = MuchKeys::CLI::Validator.validate_encrypt_options(options)
|
66
|
+
|
67
|
+
if validation.valid?
|
68
|
+
encrypt(@opts[:file], @opts[:public_key])
|
69
|
+
else
|
70
|
+
puts validation.errors
|
71
|
+
return
|
72
|
+
end
|
69
73
|
elsif @opts[:decrypt]
|
70
|
-
|
71
|
-
|
74
|
+
options = { consul_key: @opts[:consul_key], public_key: @opts[:public_key], private_key: @opts[:private_key] }
|
75
|
+
validation = MuchKeys::CLI::Validator.validate_decrypt_options(options)
|
76
|
+
|
77
|
+
if validation.valid?
|
78
|
+
decrypt(@opts[:consul_key], @opts[:public_key], @opts[:private_key])
|
79
|
+
else
|
80
|
+
puts validation.errors
|
81
|
+
return
|
82
|
+
end
|
72
83
|
elsif @opts[:plain]
|
73
|
-
|
84
|
+
options = { consul_key: @opts[:consul_key] }
|
85
|
+
validation = MuchKeys::CLI::Validator.validate_plain_options(options)
|
86
|
+
|
87
|
+
if validation.valid?
|
88
|
+
plain(@opts[:consul_key])
|
89
|
+
else
|
90
|
+
puts validation.errors
|
91
|
+
return
|
92
|
+
end
|
74
93
|
end
|
94
|
+
|
75
95
|
end
|
76
96
|
|
77
97
|
def encrypt(file, public_key)
|
@@ -87,6 +107,17 @@ module MuchKeys
|
|
87
107
|
puts MuchKeys.fetch_key(consul_key)
|
88
108
|
end
|
89
109
|
|
110
|
+
def print_version_number
|
111
|
+
puts MuchKeys::VERSION
|
112
|
+
@cli_should_exit = true
|
113
|
+
end
|
114
|
+
|
115
|
+
def print_help
|
116
|
+
# this is how the slop gem prints help
|
117
|
+
puts @opts
|
118
|
+
@cli_should_exit = true
|
119
|
+
end
|
120
|
+
|
90
121
|
|
91
122
|
private
|
92
123
|
def select_primary_mode(options)
|
@@ -99,5 +130,15 @@ module MuchKeys
|
|
99
130
|
MuchKeys::Secret
|
100
131
|
end
|
101
132
|
|
133
|
+
def check_for_early_exit_actions
|
134
|
+
if @opts[:help]
|
135
|
+
print_help
|
136
|
+
end
|
137
|
+
|
138
|
+
if @opts[:version]
|
139
|
+
print_version_number
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
102
143
|
end
|
103
144
|
end
|
data/lib/muchkeys/errors.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
module MuchKeys
|
2
|
-
InvalidKey
|
3
|
-
CLIOptionsError
|
4
|
-
NoKeysSet
|
2
|
+
InvalidKey = Class.new(StandardError)
|
3
|
+
CLIOptionsError = Class.new(StandardError)
|
4
|
+
NoKeysSet = Class.new(StandardError)
|
5
|
+
UnknownApplication = Class.new(StandardError)
|
5
6
|
end
|
data/lib/muchkeys/version.rb
CHANGED
data/lib/muchkeys.rb
CHANGED
@@ -10,6 +10,10 @@ require "net/http"
|
|
10
10
|
|
11
11
|
module MuchKeys
|
12
12
|
|
13
|
+
# revealing intention
|
14
|
+
module BlankKey; false; end
|
15
|
+
|
16
|
+
|
13
17
|
class << self
|
14
18
|
attr_accessor :configuration
|
15
19
|
|
@@ -20,37 +24,22 @@ module MuchKeys
|
|
20
24
|
end
|
21
25
|
end
|
22
26
|
|
23
|
-
|
24
|
-
if MuchKeys.configuration.search_paths
|
25
|
-
search_paths = MuchKeys.configuration.search_paths.collect do |path|
|
26
|
-
"#{path}/#{key_name}"
|
27
|
-
end
|
28
|
-
else
|
29
|
-
search_paths = [
|
30
|
-
"git/#{application_name}/secrets/#{key_name}",
|
31
|
-
"git/#{application_name}/config/#{key_name}",
|
32
|
-
"git/shared/secrets/#{key_name}",
|
33
|
-
"git/shared/config/#{key_name}"
|
34
|
-
]
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
27
|
+
# this is the entry point to the ENV-like object that devs will use
|
38
28
|
def find_first(key_name)
|
39
|
-
return ENV[key_name] unless ENV[key_name].nil?
|
40
|
-
|
41
29
|
unless MuchKeys.configuration.search_paths
|
42
|
-
application_name
|
43
|
-
return false if !application_name
|
30
|
+
raise MuchKeys::UnknownApplication, "Can't detect app name and application_name isn't set." if !application_name
|
44
31
|
end
|
45
32
|
|
46
|
-
|
33
|
+
consul_paths_to_search = search_order(application_name, key_name)
|
47
34
|
|
35
|
+
# search consul in a specific order until we find something
|
48
36
|
response = nil
|
49
|
-
|
37
|
+
consul_paths_to_search.detect do |consul_path|
|
50
38
|
response = fetch_key(consul_path)
|
39
|
+
response if response != MuchKeys::BlankKey
|
51
40
|
end
|
52
41
|
|
53
|
-
if
|
42
|
+
if response == BlankKey
|
54
43
|
raise MuchKeys::NoKeysSet, "Bailing. Consul isn't set with any keys for #{key_name}."
|
55
44
|
end
|
56
45
|
|
@@ -72,46 +61,47 @@ module MuchKeys
|
|
72
61
|
response = fetch_plain_key(key_name)
|
73
62
|
end
|
74
63
|
|
75
|
-
# empty and unset keys from consul are empty strings, so return false
|
76
|
-
# here TODO: UnsetKey would be better here.
|
77
|
-
return false if response == ""
|
78
|
-
|
79
64
|
# otherwise, we got consul data so return that
|
80
65
|
response
|
81
66
|
end
|
82
67
|
|
83
|
-
def
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
raise MuchKeys::InvalidKey
|
68
|
+
def search_order(application_name, key_name)
|
69
|
+
if MuchKeys.configuration.search_paths
|
70
|
+
search_paths = MuchKeys.configuration.search_paths.collect do |path|
|
71
|
+
"#{path}/#{key_name}"
|
72
|
+
end
|
73
|
+
else
|
74
|
+
search_paths = [
|
75
|
+
"git/#{application_name}/secrets/#{key_name}",
|
76
|
+
"git/#{application_name}/config/#{key_name}",
|
77
|
+
"git/shared/secrets/#{key_name}",
|
78
|
+
"git/shared/config/#{key_name}"
|
79
|
+
]
|
96
80
|
end
|
81
|
+
|
82
|
+
search_paths
|
97
83
|
end
|
98
84
|
|
99
85
|
|
100
86
|
private
|
87
|
+
def consul_url(key_name)
|
88
|
+
URI("#{configuration.consul_url}/v1/kv/#{key_name}?raw")
|
89
|
+
end
|
90
|
+
|
101
91
|
def fetch_plain_key(key_name)
|
102
92
|
url = consul_url(key_name)
|
103
93
|
response = Net::HTTP.get_response url
|
104
|
-
|
105
|
-
|
94
|
+
|
95
|
+
return MuchKeys::BlankKey if !response.body || response.body.empty?
|
96
|
+
response.body
|
106
97
|
end
|
107
98
|
|
108
99
|
def fetch_secret_key(key_name, public_pem=nil, private_pem=nil)
|
109
100
|
result = fetch_plain_key(key_name)
|
110
|
-
# FIXME: omg use a class like MuchKeys::UnsetKey instead of "" as a
|
111
|
-
# return value -- there are other places like this too.
|
112
101
|
|
113
102
|
# we hit a key that doesn't exist, so don't try to decrypt it
|
114
|
-
return
|
103
|
+
return MuchKeys::BlankKey if result == MuchKeys::BlankKey
|
104
|
+
|
115
105
|
secret_adapter.decrypt_string(result, public_pem, private_pem)
|
116
106
|
end
|
117
107
|
|
@@ -128,18 +118,15 @@ module MuchKeys
|
|
128
118
|
end
|
129
119
|
|
130
120
|
# Detecting Rails app names is a known quantity.
|
131
|
-
#
|
132
|
-
def
|
121
|
+
# Rack apps need to set the name through config.
|
122
|
+
def application_name
|
133
123
|
return configuration.application_name if configuration.application_name
|
134
124
|
|
135
|
-
# Rails.application is "Monorail::Application".
|
136
125
|
if defined?(Rails)
|
126
|
+
# Rails.application looks something like "Monorail::Application"
|
137
127
|
application_name = Rails.application.class.to_s.split("::").first
|
138
|
-
elsif defined?(Rack)
|
139
|
-
application_name = "Asset_Server"
|
140
128
|
else
|
141
|
-
|
142
|
-
return
|
129
|
+
return false
|
143
130
|
end
|
144
131
|
|
145
132
|
snakecase(application_name)
|
@@ -164,8 +151,11 @@ MuchKeys.configuration ||= MuchKeys::Configuration.new
|
|
164
151
|
# This interface looks like ENV which is more friendly to devs
|
165
152
|
class MUCHKEYS
|
166
153
|
|
167
|
-
def self.[](
|
168
|
-
|
154
|
+
def self.[](key_name)
|
155
|
+
# if an ENV key is set, use that first
|
156
|
+
return ENV[key_name] unless ENV[key_name].nil?
|
157
|
+
|
158
|
+
MuchKeys.find_first(key_name)
|
169
159
|
end
|
170
160
|
|
171
161
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: muchkeys
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pat O'Brien
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-04
|
12
|
+
date: 2016-05-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: slop
|
@@ -129,6 +129,7 @@ files:
|
|
129
129
|
- exe/muchkeys
|
130
130
|
- lib/muchkeys.rb
|
131
131
|
- lib/muchkeys/cli.rb
|
132
|
+
- lib/muchkeys/cli/validation.rb
|
132
133
|
- lib/muchkeys/cli/validator.rb
|
133
134
|
- lib/muchkeys/configuration.rb
|
134
135
|
- lib/muchkeys/errors.rb
|