chamber 2.8.0 → 2.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -0
- data/LICENSE.txt +19 -0
- data/Rakefile +1 -0
- data/bin/chamber +1 -0
- data/lib/chamber.rb +1 -0
- data/lib/chamber/binary/heroku.rb +1 -0
- data/lib/chamber/binary/runner.rb +1 -0
- data/lib/chamber/binary/travis.rb +1 -0
- data/lib/chamber/commands/base.rb +1 -0
- data/lib/chamber/commands/comparable.rb +1 -0
- data/lib/chamber/commands/compare.rb +1 -0
- data/lib/chamber/commands/files.rb +1 -0
- data/lib/chamber/commands/heroku.rb +1 -0
- data/lib/chamber/commands/heroku/clear.rb +1 -0
- data/lib/chamber/commands/heroku/compare.rb +1 -0
- data/lib/chamber/commands/heroku/pull.rb +1 -0
- data/lib/chamber/commands/heroku/push.rb +1 -0
- data/lib/chamber/commands/initialize.rb +5 -3
- data/lib/chamber/commands/securable.rb +1 -0
- data/lib/chamber/commands/secure.rb +1 -0
- data/lib/chamber/commands/show.rb +1 -0
- data/lib/chamber/commands/travis.rb +1 -0
- data/lib/chamber/commands/travis/secure.rb +1 -0
- data/lib/chamber/configuration.rb +1 -0
- data/lib/chamber/context_resolver.rb +10 -7
- data/lib/chamber/decryption_key.rb +1 -0
- data/lib/chamber/encryption_methods/none.rb +17 -0
- data/lib/chamber/encryption_methods/public_key.rb +27 -0
- data/lib/chamber/encryption_methods/ssl.rb +60 -0
- data/lib/chamber/environmentable.rb +1 -0
- data/lib/chamber/errors/decryption_failure.rb +1 -0
- data/lib/chamber/file.rb +9 -1
- data/lib/chamber/file_set.rb +4 -3
- data/lib/chamber/filters/boolean_conversion_filter.rb +2 -1
- data/lib/chamber/filters/decryption_filter.rb +20 -29
- data/lib/chamber/filters/encryption_filter.rb +29 -14
- data/lib/chamber/filters/environment_filter.rb +2 -1
- data/lib/chamber/filters/failed_decryption_filter.rb +3 -2
- data/lib/chamber/filters/insecure_filter.rb +1 -0
- data/lib/chamber/filters/namespace_filter.rb +2 -1
- data/lib/chamber/filters/secure_filter.rb +2 -1
- data/lib/chamber/filters/translate_secure_keys_filter.rb +2 -1
- data/lib/chamber/instance.rb +1 -0
- data/lib/chamber/namespace_set.rb +4 -3
- data/lib/chamber/rails.rb +1 -0
- data/lib/chamber/rails/railtie.rb +3 -1
- data/lib/chamber/rubinius_fix.rb +1 -0
- data/lib/chamber/settings.rb +23 -18
- data/lib/chamber/version.rb +2 -1
- data/spec/lib/chamber/commands/files_spec.rb +5 -2
- data/spec/lib/chamber/commands/heroku/clear_spec.rb +1 -0
- data/spec/lib/chamber/commands/heroku/compare_spec.rb +1 -0
- data/spec/lib/chamber/commands/heroku/pull_spec.rb +1 -0
- data/spec/lib/chamber/commands/heroku/push_spec.rb +1 -0
- data/spec/lib/chamber/commands/secure_spec.rb +5 -2
- data/spec/lib/chamber/commands/show_spec.rb +1 -0
- data/spec/lib/chamber/context_resolver_spec.rb +8 -5
- data/spec/lib/chamber/file_set_spec.rb +55 -52
- data/spec/lib/chamber/file_spec.rb +43 -9
- data/spec/lib/chamber/filters/boolean_conversion_filter_spec.rb +14 -5
- data/spec/lib/chamber/filters/decryption_filter_spec.rb +85 -9
- data/spec/lib/chamber/filters/encryption_filter_spec.rb +76 -10
- data/spec/lib/chamber/filters/environment_filter_spec.rb +9 -2
- data/spec/lib/chamber/filters/failed_decryption_filter_spec.rb +7 -6
- data/spec/lib/chamber/filters/insecure_filter_spec.rb +12 -4
- data/spec/lib/chamber/filters/namespace_filter_spec.rb +33 -14
- data/spec/lib/chamber/filters/secure_filter_spec.rb +8 -3
- data/spec/lib/chamber/filters/translate_secure_keys_filter_spec.rb +10 -3
- data/spec/lib/chamber/namespace_set_spec.rb +6 -3
- data/spec/lib/chamber/settings_spec.rb +36 -25
- data/spec/lib/chamber_spec.rb +25 -10
- data/spec/rails-2-test/config/application.rb +1 -0
- data/spec/rails-3-test/config/application.rb +1 -0
- data/spec/rails-4-test/config/application.rb +1 -0
- metadata +35 -9
- metadata.gz.sig +0 -0
- data/LICENSE +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70d5a99fb72440e64e3ef88a6ab33a3304466b19
|
4
|
+
data.tar.gz: a9e604aa036a20152fa0be993ccfcd69e47406de
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6bafc0df4003a0f5dc2ef004bbb874b4489166e8000f8be0caa92e2edb09197b7716a0080d7941fe482721e996110f51baff07ca167af5f4907349b9b8e80d8
|
7
|
+
data.tar.gz: 50985ca6d2a0716b1256a0e09df31d9501df5e26119be403b99ebaa7b67b327832236fc47616272579bce02abb3d9b703af8af68b24cbf8463216c87f0a98a2f
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data.tar.gz.sig
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
UM���K]����@��jb}��TχN)�)�l�X�����]�Ժ�ha�����V�u�0h�J�&��$� ���]I~{cU��±��-�9rA��l�J�r_kV%|��KH��}oM�?�H0a�v%CC!�
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2010-2016 The Kompanee, Ltd
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/Rakefile
CHANGED
data/bin/chamber
CHANGED
data/lib/chamber.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'pathname'
|
2
3
|
require 'fileutils'
|
3
4
|
require 'openssl'
|
@@ -25,7 +26,7 @@ class Initialize < Chamber::Commands::Base
|
|
25
26
|
|
26
27
|
::FileUtils.touch gitignore_filepath
|
27
28
|
|
28
|
-
unless ::File.read(gitignore_filepath)
|
29
|
+
unless ::File.read(gitignore_filepath) =~ /^.chamber.pem$/
|
29
30
|
shell.append_to_file gitignore_filepath, "\n# Private and protected key files for Chamber\n"
|
30
31
|
shell.append_to_file gitignore_filepath, "#{private_key_filename}\n"
|
31
32
|
shell.append_to_file gitignore_filepath, "#{protected_key_filename}\n"
|
@@ -76,7 +77,8 @@ class Initialize < Chamber::Commands::Base
|
|
76
77
|
|
77
78
|
def gem_path
|
78
79
|
@gem_path ||= Pathname.new(
|
79
|
-
::File.expand_path('../../../..', __FILE__)
|
80
|
+
::File.expand_path('../../../..', __FILE__),
|
81
|
+
)
|
80
82
|
end
|
81
83
|
|
82
84
|
def settings_filepath
|
@@ -129,7 +131,7 @@ class Initialize < Chamber::Commands::Base
|
|
129
131
|
end
|
130
132
|
|
131
133
|
def rsa_key_passphrase
|
132
|
-
@rsa_key_passphrase
|
134
|
+
@rsa_key_passphrase ||= SecureRandom.uuid
|
133
135
|
end
|
134
136
|
end
|
135
137
|
end
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'pathname'
|
2
3
|
require 'socket'
|
3
4
|
require 'hashie/mash'
|
@@ -36,19 +37,21 @@ class ContextResolver
|
|
36
37
|
if options[:namespaces] == []
|
37
38
|
require options[:rootpath].join('config', 'application').to_s
|
38
39
|
|
39
|
-
options[:namespaces]
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
options[:namespaces] = [
|
41
|
+
::Rails.env,
|
42
|
+
Socket.gethostname,
|
43
|
+
]
|
43
44
|
end
|
44
45
|
else
|
45
|
-
options[:basepath]
|
46
|
+
options[:basepath] ||= options[:rootpath]
|
46
47
|
end
|
47
48
|
|
48
49
|
options[:basepath] = Pathname.new(options[:basepath])
|
49
50
|
|
50
|
-
options[:files] ||= [
|
51
|
-
|
51
|
+
options[:files] ||= [
|
52
|
+
options[:basepath] + 'settings*.yml',
|
53
|
+
options[:basepath] + 'settings',
|
54
|
+
]
|
52
55
|
|
53
56
|
options
|
54
57
|
rescue LoadError
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Chamber
|
2
|
+
module EncryptionMethods
|
3
|
+
class None
|
4
|
+
def self.encrypt(_key, value, _encryption_key)
|
5
|
+
value
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.decrypt(key, value, _decryption_key)
|
9
|
+
warn "WARNING: It appears that you would like to keep your information for #{key} " \
|
10
|
+
"secure, however the value for that setting does not appear to be encrypted. " \
|
11
|
+
"Make sure you run 'chamber secure' before committing."
|
12
|
+
|
13
|
+
value
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Chamber
|
2
|
+
module EncryptionMethods
|
3
|
+
class PublicKey
|
4
|
+
def self.encrypt(_key, value, encryption_key)
|
5
|
+
value = YAML.dump(value)
|
6
|
+
encrypted_string = encryption_key.public_encrypt(value)
|
7
|
+
|
8
|
+
Base64.strict_encode64(encrypted_string)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.decrypt(_key, value, decryption_key)
|
12
|
+
if decryption_key.nil?
|
13
|
+
value
|
14
|
+
else
|
15
|
+
decoded_string = Base64.strict_decode64(value)
|
16
|
+
unencrypted_value = decryption_key.private_decrypt(decoded_string)
|
17
|
+
|
18
|
+
begin
|
19
|
+
_unserialized_value = YAML.load(unencrypted_value)
|
20
|
+
rescue TypeError
|
21
|
+
unencrypted_value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Chamber
|
2
|
+
module EncryptionMethods
|
3
|
+
class Ssl
|
4
|
+
LARGE_DATA_STRING_PATTERN = %r{\A([A-Za-z0-9\+\/#]*\={0,2})#([A-Za-z0-9\+\/#]*\={0,2})#([A-Za-z0-9\+\/#]*\={0,2})\z} # rubocop:disable Metrics/LineLength
|
5
|
+
|
6
|
+
def self.encrypt(_key, value, encryption_key)
|
7
|
+
value = YAML.dump(value)
|
8
|
+
cipher = OpenSSL::Cipher::Cipher.new('AES-128-CBC')
|
9
|
+
cipher.encrypt
|
10
|
+
symmetric_key = cipher.random_key
|
11
|
+
iv = cipher.random_iv
|
12
|
+
|
13
|
+
# encrypt all data with this key and iv
|
14
|
+
encrypted_data = cipher.update(value) + cipher.final
|
15
|
+
|
16
|
+
# encrypt the key with the public key
|
17
|
+
encrypted_key = encryption_key.public_encrypt(symmetric_key)
|
18
|
+
|
19
|
+
# assemble the resulting Base64 encoded data, the key
|
20
|
+
Base64.strict_encode64(encrypted_key) + '#' +
|
21
|
+
Base64.strict_encode64(iv) + '#' +
|
22
|
+
Base64.strict_encode64(encrypted_data)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.decrypt(key, value, decryption_key)
|
26
|
+
if decryption_key.nil?
|
27
|
+
value
|
28
|
+
else
|
29
|
+
key, iv, decoded_string = value.
|
30
|
+
match(LARGE_DATA_STRING_PATTERN).
|
31
|
+
captures.
|
32
|
+
map do |part|
|
33
|
+
Base64.strict_decode64(part)
|
34
|
+
end
|
35
|
+
key = decryption_key.private_decrypt(key)
|
36
|
+
|
37
|
+
cipher_dec = OpenSSL::Cipher::Cipher.new('AES-128-CBC')
|
38
|
+
|
39
|
+
cipher_dec.decrypt
|
40
|
+
|
41
|
+
cipher_dec.key = key
|
42
|
+
cipher_dec.iv = iv
|
43
|
+
|
44
|
+
begin
|
45
|
+
unencrypted_value = cipher_dec.update(decoded_string) + cipher_dec.final
|
46
|
+
rescue OpenSSL::Cipher::CipherError
|
47
|
+
raise Chamber::Errors::DecryptionFailure,
|
48
|
+
'A decryption error occurred. It was probably due to invalid key data.'
|
49
|
+
end
|
50
|
+
|
51
|
+
begin
|
52
|
+
_unserialized_value = YAML.load(unencrypted_value)
|
53
|
+
rescue TypeError
|
54
|
+
unencrypted_value
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/chamber/file.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'pathname'
|
2
3
|
require 'yaml'
|
3
4
|
require 'erb'
|
@@ -83,7 +84,14 @@ class File < Pathname
|
|
83
84
|
file_contents.
|
84
85
|
sub!(
|
85
86
|
/^(\s*)_secure_#{escaped_name}(\s*):(\s*)['"]?#{escaped_value}['"]?$/,
|
86
|
-
"\\1_secure_#{name_pieces.last}\\2:\\3#{secure_value}"
|
87
|
+
"\\1_secure_#{name_pieces.last}\\2:\\3#{secure_value}",
|
88
|
+
)
|
89
|
+
|
90
|
+
file_contents.
|
91
|
+
sub!(
|
92
|
+
/^(\s*)_secure_#{escaped_name}(\s*):(\s*)\|((?:\n\1\s{2}.*)+)/,
|
93
|
+
"\\1_secure_#{name_pieces.last}\\2:\\3#{secure_value}",
|
94
|
+
)
|
87
95
|
end
|
88
96
|
|
89
97
|
write(file_contents)
|
data/lib/chamber/file_set.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'pathname'
|
2
3
|
require 'chamber/namespace_set'
|
3
4
|
require 'chamber/file'
|
@@ -163,7 +164,7 @@ class FileSet
|
|
163
164
|
# # => <Chamber::Settings>
|
164
165
|
#
|
165
166
|
def to_settings
|
166
|
-
files.
|
167
|
+
files.inject(Settings.new) do |settings, file|
|
167
168
|
settings.merge(file.to_settings).tap do |merged|
|
168
169
|
yield merged if block_given?
|
169
170
|
end
|
@@ -207,7 +208,7 @@ class FileSet
|
|
207
208
|
# duplicates removed.
|
208
209
|
#
|
209
210
|
def files
|
210
|
-
@files ||= lambda
|
211
|
+
@files ||= lambda {
|
211
212
|
sorted_relevant_files = []
|
212
213
|
|
213
214
|
file_globs.each do |glob|
|
@@ -225,7 +226,7 @@ class FileSet
|
|
225
226
|
end
|
226
227
|
|
227
228
|
sorted_relevant_files.uniq
|
228
|
-
|
229
|
+
}.call
|
229
230
|
end
|
230
231
|
|
231
232
|
private
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
module Chamber
|
2
3
|
module Filters
|
3
4
|
class BooleanConversionFilter
|
@@ -6,7 +7,7 @@ class BooleanConversionFilter
|
|
6
7
|
end
|
7
8
|
|
8
9
|
def self.execute(options = {})
|
9
|
-
new(options).
|
10
|
+
new(options).__send__(:execute)
|
10
11
|
end
|
11
12
|
|
12
13
|
protected
|
@@ -1,14 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'openssl'
|
2
3
|
require 'base64'
|
3
4
|
require 'hashie/mash'
|
4
5
|
require 'yaml'
|
6
|
+
require 'chamber/encryption_methods/public_key'
|
7
|
+
require 'chamber/encryption_methods/ssl'
|
8
|
+
require 'chamber/encryption_methods/none'
|
5
9
|
require 'chamber/errors/decryption_failure'
|
6
10
|
|
7
11
|
module Chamber
|
8
12
|
module Filters
|
9
13
|
class DecryptionFilter
|
10
|
-
SECURE_KEY_TOKEN
|
11
|
-
BASE64_STRING_PATTERN
|
14
|
+
SECURE_KEY_TOKEN = /\A_secure_/
|
15
|
+
BASE64_STRING_PATTERN = %r{\A[A-Za-z0-9\+/]{342}==\z}
|
16
|
+
LARGE_DATA_STRING_PATTERN = %r{\A([A-Za-z0-9\+\/#]*\={0,2})#([A-Za-z0-9\+\/#]*\={0,2})#([A-Za-z0-9\+\/#]*\={0,2})\z} # rubocop:disable Metrics/LineLength
|
12
17
|
|
13
18
|
def initialize(options = {})
|
14
19
|
self.decryption_key = options.fetch(:decryption_key, nil)
|
@@ -16,7 +21,7 @@ class DecryptionFilter
|
|
16
21
|
end
|
17
22
|
|
18
23
|
def self.execute(options = {})
|
19
|
-
new(options).
|
24
|
+
new(options).__send__(:execute)
|
20
25
|
end
|
21
26
|
|
22
27
|
protected
|
@@ -30,8 +35,8 @@ class DecryptionFilter
|
|
30
35
|
raw_data.each_pair do |key, value|
|
31
36
|
settings[key] = if value.respond_to? :each_pair
|
32
37
|
execute(value)
|
33
|
-
elsif key.match(SECURE_KEY_TOKEN)
|
34
|
-
|
38
|
+
elsif key.match(SECURE_KEY_TOKEN)
|
39
|
+
decryption_method(value).decrypt(key, value, decryption_key)
|
35
40
|
else
|
36
41
|
value
|
37
42
|
end
|
@@ -54,31 +59,17 @@ class DecryptionFilter
|
|
54
59
|
|
55
60
|
private
|
56
61
|
|
57
|
-
def
|
58
|
-
if value.match
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
value
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def decrypt(value)
|
71
|
-
if decryption_key.nil?
|
72
|
-
value
|
73
|
-
else
|
74
|
-
decoded_string = Base64.strict_decode64(value)
|
75
|
-
unencrypted_value = decryption_key.private_decrypt(decoded_string)
|
76
|
-
|
77
|
-
begin
|
78
|
-
_unserialized_value = YAML.load(unencrypted_value)
|
79
|
-
rescue TypeError
|
80
|
-
unencrypted_value
|
62
|
+
def decryption_method(value)
|
63
|
+
if value.respond_to?(:match)
|
64
|
+
if value.match(BASE64_STRING_PATTERN)
|
65
|
+
EncryptionMethods::PublicKey
|
66
|
+
elsif value.match(LARGE_DATA_STRING_PATTERN)
|
67
|
+
EncryptionMethods::Ssl
|
68
|
+
else
|
69
|
+
EncryptionMethods::None
|
81
70
|
end
|
71
|
+
else
|
72
|
+
EncryptionMethods::None
|
82
73
|
end
|
83
74
|
end
|
84
75
|
end
|