chamber 2.14.3 → 3.0.0rc2
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
- checksums.yaml.gz.sig +0 -0
- data/lib/chamber/binary/circle_ci.rb +0 -1
- data/lib/chamber/binary/heroku.rb +0 -1
- data/lib/chamber/binary/runner.rb +0 -1
- data/lib/chamber/binary/travis.rb +0 -1
- data/lib/chamber/commands/initialize.rb +1 -1
- data/lib/chamber/encryption_methods/public_key.rb +26 -40
- data/lib/chamber/encryption_methods/ssl.rb +33 -51
- data/lib/chamber/errors/disallowed_class.rb +8 -0
- data/lib/chamber/file.rb +10 -22
- data/lib/chamber/files/signature.rb +6 -6
- data/lib/chamber/filters/decryption_filter.rb +9 -11
- data/lib/chamber/filters/encryption_filter.rb +8 -6
- data/lib/chamber/filters/environment_filter.rb +6 -7
- data/lib/chamber/filters/failed_decryption_filter.rb +4 -1
- data/lib/chamber/filters/insecure_filter.rb +1 -2
- data/lib/chamber/filters/namespace_filter.rb +11 -9
- data/lib/chamber/filters/secure_filter.rb +5 -3
- data/lib/chamber/filters/translate_secure_keys_filter.rb +5 -3
- data/lib/chamber/instance.rb +0 -10
- data/lib/chamber/refinements/deep_dup.rb +34 -0
- data/lib/chamber/refinements/enumerable.rb +1 -2
- data/lib/chamber/refinements/hash.rb +25 -0
- data/lib/chamber/settings.rb +15 -32
- data/lib/chamber/types/secured.rb +5 -5
- data/lib/chamber/version.rb +1 -1
- data/lib/chamber.rb +0 -16
- data.tar.gz.sig +0 -0
- metadata +9 -21
- metadata.gz.sig +0 -0
- data/lib/chamber/core_ext/hash.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9de7c74ea902d381006bd6b5f05bae3680d1beef940ae75e483f30c923bc310f
|
4
|
+
data.tar.gz: b6f45eb5b668a5964e898ffb4caa5b9a3e9bc227736dd0e687e257cff0c99f84
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1ab7fedfaf6cb26ab3e97402966368f3e686751ca76e441a7d9db64b7fe354a289ac4ac330cac806fb7960f3b4750c1ce4f7799e548c4f0f549ee57826e8552
|
7
|
+
data.tar.gz: 64cfa0683ca78d71cd620e38e60c4d2c25683c5217d74858995b2ee65eda704f7d2aca9395451ac743424bd75b8974ee088ed3563e192be5ab057f49ad458165
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -194,7 +194,7 @@ class Initialize < Chamber::Commands::Base
|
|
194
194
|
.chamber*.enc.pass
|
195
195
|
!.chamber*.pub.pem
|
196
196
|
}.each do |pattern|
|
197
|
-
unless gitignore_contents
|
197
|
+
unless gitignore_contents&.match?(Regexp.new(Regexp.escape(pattern)))
|
198
198
|
shell.append_to_file gitignore_filepath, "#{pattern}\n"
|
199
199
|
end
|
200
200
|
end
|
@@ -2,55 +2,41 @@
|
|
2
2
|
|
3
3
|
require 'base64'
|
4
4
|
|
5
|
+
require 'chamber/errors/disallowed_class'
|
6
|
+
|
5
7
|
module Chamber
|
6
8
|
module EncryptionMethods
|
7
9
|
class PublicKey
|
8
|
-
def self.encrypt(
|
10
|
+
def self.encrypt(_settings_key, value, encryption_key)
|
9
11
|
value = YAML.dump(value)
|
10
12
|
encrypted_string = encryption_key.public_encrypt(value)
|
11
13
|
|
12
14
|
Base64.strict_encode64(encrypted_string)
|
13
15
|
end
|
14
16
|
|
15
|
-
def self.decrypt(
|
16
|
-
if decryption_key.nil?
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
#{error.message}
|
40
|
-
|
41
|
-
Called from: '#{caller.to_a[8]}'
|
42
|
-
HEREDOC
|
43
|
-
|
44
|
-
if YAML.respond_to?(:unsafe_load)
|
45
|
-
YAML.unsafe_load(unencrypted_value)
|
46
|
-
else
|
47
|
-
YAML.load(unencrypted_value)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
rescue TypeError
|
51
|
-
unencrypted_value
|
52
|
-
end
|
53
|
-
end
|
17
|
+
def self.decrypt(_settings_key, value, decryption_key)
|
18
|
+
return value if decryption_key.nil?
|
19
|
+
|
20
|
+
decoded_string = ::Base64.strict_decode64(value)
|
21
|
+
unencrypted_value = decryption_key.private_decrypt(decoded_string)
|
22
|
+
|
23
|
+
::YAML.safe_load(unencrypted_value,
|
24
|
+
aliases: true,
|
25
|
+
permitted_classes: [
|
26
|
+
::Date,
|
27
|
+
::Time,
|
28
|
+
::Regexp,
|
29
|
+
])
|
30
|
+
rescue ::Psych::DisallowedClass => error
|
31
|
+
raise ::Chamber::Errors::DisallowedClass, <<~HEREDOC
|
32
|
+
#{error.message}
|
33
|
+
|
34
|
+
You attempted to load a class instance via your Chamber settings that is not allowed.
|
35
|
+
|
36
|
+
See https://github.com/thekompanee/chamber/wiki/Upgrading-To-Chamber-3.0#limiting-complex-classes for full details.
|
37
|
+
HEREDOC
|
38
|
+
rescue ::TypeError
|
39
|
+
unencrypted_value
|
54
40
|
end
|
55
41
|
end
|
56
42
|
end
|
@@ -16,7 +16,7 @@ class Ssl
|
|
16
16
|
\z
|
17
17
|
/x.freeze
|
18
18
|
|
19
|
-
def self.encrypt(
|
19
|
+
def self.encrypt(_settings_key, value, encryption_keys) # rubocop:disable Metrics/AbcSize
|
20
20
|
value = YAML.dump(value)
|
21
21
|
cipher = OpenSSL::Cipher.new('AES-128-CBC')
|
22
22
|
cipher.encrypt
|
@@ -35,64 +35,46 @@ class Ssl
|
|
35
35
|
Base64.strict_encode64(encrypted_data)
|
36
36
|
end
|
37
37
|
|
38
|
-
def self.decrypt(
|
39
|
-
if decryption_keys.nil?
|
40
|
-
value
|
41
|
-
else
|
42
|
-
key, iv, decoded_string = value
|
43
|
-
.match(LARGE_DATA_STRING_PATTERN)
|
44
|
-
.captures
|
45
|
-
.map do |part|
|
46
|
-
Base64.strict_decode64(part)
|
47
|
-
end
|
48
|
-
key = decryption_keys.private_decrypt(key)
|
38
|
+
def self.decrypt(_settings_key, value, decryption_keys) # rubocop:disable Metrics/AbcSize
|
39
|
+
return value if decryption_keys.nil?
|
49
40
|
|
50
|
-
|
51
|
-
|
52
|
-
|
41
|
+
key, iv, decoded_string = value
|
42
|
+
.match(LARGE_DATA_STRING_PATTERN)
|
43
|
+
.captures
|
44
|
+
.map do |part|
|
45
|
+
::Base64.strict_decode64(part)
|
46
|
+
end
|
47
|
+
key = decryption_keys.private_decrypt(key)
|
53
48
|
|
54
|
-
|
55
|
-
cipher_dec.iv = iv
|
49
|
+
cipher_dec = ::OpenSSL::Cipher.new('AES-128-CBC')
|
56
50
|
|
57
|
-
|
58
|
-
unencrypted_value = cipher_dec.update(decoded_string) + cipher_dec.final
|
59
|
-
rescue OpenSSL::Cipher::CipherError
|
60
|
-
raise Chamber::Errors::DecryptionFailure,
|
61
|
-
'A decryption error occurred. It was probably due to invalid key data.'
|
62
|
-
end
|
51
|
+
cipher_dec.decrypt
|
63
52
|
|
64
|
-
|
65
|
-
|
66
|
-
YAML.safe_load(unencrypted_value,
|
67
|
-
aliases: true,
|
68
|
-
permitted_classes: [
|
69
|
-
::Date,
|
70
|
-
::Time,
|
71
|
-
::Regexp,
|
72
|
-
])
|
73
|
-
rescue ::Psych::DisallowedClass => error
|
74
|
-
warn <<-HEREDOC
|
75
|
-
WARNING: Recursive data structures (complex classes) being loaded from Chamber
|
76
|
-
has been deprecated and will be removed in 3.0.
|
53
|
+
cipher_dec.key = key
|
54
|
+
cipher_dec.iv = iv
|
77
55
|
|
78
|
-
|
79
|
-
for full details.
|
56
|
+
unencrypted_value = cipher_dec.update(decoded_string) + cipher_dec.final
|
80
57
|
|
81
|
-
|
58
|
+
::YAML.safe_load(unencrypted_value,
|
59
|
+
aliases: true,
|
60
|
+
permitted_classes: [
|
61
|
+
::Date,
|
62
|
+
::Time,
|
63
|
+
::Regexp,
|
64
|
+
])
|
65
|
+
rescue ::OpenSSL::Cipher::CipherError
|
66
|
+
raise ::Chamber::Errors::DecryptionFailure,
|
67
|
+
'A decryption error occurred. It was probably due to invalid key data.'
|
68
|
+
rescue ::Psych::DisallowedClass => error
|
69
|
+
raise ::Chamber::Errors::DisallowedClass, <<~HEREDOC
|
70
|
+
#{error.message}
|
82
71
|
|
83
|
-
|
84
|
-
HEREDOC
|
72
|
+
You attempted to load a class instance via your Chamber settings that is not allowed.
|
85
73
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
end
|
91
|
-
end
|
92
|
-
rescue TypeError
|
93
|
-
unencrypted_value
|
94
|
-
end
|
95
|
-
end
|
74
|
+
See https://github.com/thekompanee/chamber/wiki/Upgrading-To-Chamber-3.0#limiting-complex-classes for full details.
|
75
|
+
HEREDOC
|
76
|
+
rescue ::TypeError
|
77
|
+
unencrypted_value
|
96
78
|
end
|
97
79
|
end
|
98
80
|
end
|
data/lib/chamber/file.rb
CHANGED
@@ -139,38 +139,26 @@ class File < Pathname
|
|
139
139
|
@secure_prefix_pattern ||= Regexp.escape(secure_prefix)
|
140
140
|
end
|
141
141
|
|
142
|
-
def file_contents_hash
|
142
|
+
def file_contents_hash
|
143
143
|
file_contents = read
|
144
|
-
erb_result = ERB.new(file_contents).result
|
144
|
+
erb_result = ::ERB.new(file_contents).result
|
145
145
|
|
146
|
-
|
147
|
-
YAML.safe_load(erb_result,
|
146
|
+
::YAML.safe_load(erb_result,
|
148
147
|
aliases: true,
|
149
148
|
permitted_classes: [
|
150
149
|
::Date,
|
151
150
|
::Time,
|
152
151
|
::Regexp,
|
153
152
|
]) || {}
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
has been deprecated and will be removed in 3.0.
|
153
|
+
rescue ::Psych::DisallowedClass => error
|
154
|
+
raise ::Chamber::Errors::DisallowedClass, <<~HEREDOC
|
155
|
+
#{error.message}
|
158
156
|
|
159
|
-
|
160
|
-
for full details.
|
157
|
+
You attempted to load a class instance via your Chamber settings that is not allowed.
|
161
158
|
|
162
|
-
#
|
163
|
-
|
164
|
-
|
165
|
-
HEREDOC
|
166
|
-
|
167
|
-
if YAML.respond_to?(:unsafe_load)
|
168
|
-
YAML.unsafe_load(erb_result) || {}
|
169
|
-
else
|
170
|
-
YAML.load(erb_result) || {}
|
171
|
-
end
|
172
|
-
end
|
173
|
-
rescue Errno::ENOENT
|
159
|
+
See https://github.com/thekompanee/chamber/wiki/Upgrading-To-Chamber-3.0#limiting-complex-classes for full details.
|
160
|
+
HEREDOC
|
161
|
+
rescue ::Errno::ENOENT
|
174
162
|
{}
|
175
163
|
end
|
176
164
|
end
|
@@ -42,13 +42,13 @@ class Signature
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def write
|
45
|
-
signature_filename.write(
|
46
|
-
Signed By: #{signature_name}
|
47
|
-
Signed At: #{Time.now.utc.iso8601}
|
45
|
+
signature_filename.write(<<~HEREDOC, 0, mode: 'w+')
|
46
|
+
Signed By: #{signature_name}
|
47
|
+
Signed At: #{Time.now.utc.iso8601}
|
48
48
|
|
49
|
-
#{SIGNATURE_HEADER}
|
50
|
-
#{encoded_signature}
|
51
|
-
#{SIGNATURE_FOOTER}
|
49
|
+
#{SIGNATURE_HEADER}
|
50
|
+
#{encoded_signature}
|
51
|
+
#{SIGNATURE_FOOTER}
|
52
52
|
HEREDOC
|
53
53
|
end
|
54
54
|
|
@@ -2,16 +2,18 @@
|
|
2
2
|
|
3
3
|
require 'openssl'
|
4
4
|
require 'base64'
|
5
|
-
require 'hashie/mash'
|
6
5
|
require 'yaml'
|
7
6
|
require 'chamber/encryption_methods/public_key'
|
8
7
|
require 'chamber/encryption_methods/ssl'
|
9
8
|
require 'chamber/encryption_methods/none'
|
10
9
|
require 'chamber/errors/decryption_failure'
|
10
|
+
require 'chamber/refinements/deep_dup'
|
11
11
|
|
12
12
|
module Chamber
|
13
13
|
module Filters
|
14
14
|
class DecryptionFilter
|
15
|
+
using ::Chamber::Refinements::DeepDup
|
16
|
+
|
15
17
|
BASE64_STRING_PATTERN = %r{\A[A-Za-z0-9+/]{342}==\z}.freeze
|
16
18
|
LARGE_DATA_STRING_PATTERN = %r{
|
17
19
|
\A # Beginning of String
|
@@ -34,8 +36,8 @@ class DecryptionFilter
|
|
34
36
|
attr_reader :decryption_keys
|
35
37
|
|
36
38
|
def initialize(data:, secure_key_prefix:, decryption_keys: {}, **_args)
|
37
|
-
self.decryption_keys = decryption_keys || {}
|
38
|
-
self.data = data.
|
39
|
+
self.decryption_keys = (decryption_keys || {}).transform_keys(&:to_s)
|
40
|
+
self.data = data.deep_dup
|
39
41
|
self.secure_key_token = /\A#{Regexp.escape(secure_key_prefix)}/
|
40
42
|
end
|
41
43
|
|
@@ -46,7 +48,7 @@ class DecryptionFilter
|
|
46
48
|
protected
|
47
49
|
|
48
50
|
def execute(raw_data = data)
|
49
|
-
settings =
|
51
|
+
settings = {}
|
50
52
|
|
51
53
|
raw_data.each_pair do |key, value|
|
52
54
|
settings[key] = if value.respond_to? :each_pair
|
@@ -75,21 +77,17 @@ class DecryptionFilter
|
|
75
77
|
|
76
78
|
private
|
77
79
|
|
78
|
-
# rubocop:disable Style/RedundantBegin
|
79
80
|
def decrypt(key, value)
|
80
81
|
method = decryption_method(value)
|
81
82
|
|
82
83
|
decryption_keys.each do |decryption_key|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
next
|
87
|
-
end
|
84
|
+
return method.decrypt(key, value, decryption_key)
|
85
|
+
rescue OpenSSL::PKey::RSAError
|
86
|
+
next
|
88
87
|
end
|
89
88
|
|
90
89
|
value
|
91
90
|
end
|
92
|
-
# rubocop:enable Style/RedundantBegin
|
93
91
|
|
94
92
|
def decryption_method(value)
|
95
93
|
if value.is_a?(::String)
|
@@ -1,15 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'openssl'
|
4
|
-
require 'hashie/mash'
|
5
4
|
require 'yaml'
|
6
5
|
require 'chamber/encryption_methods/public_key'
|
7
6
|
require 'chamber/encryption_methods/ssl'
|
8
7
|
require 'chamber/encryption_methods/none'
|
8
|
+
require 'chamber/refinements/deep_dup'
|
9
9
|
|
10
10
|
module Chamber
|
11
11
|
module Filters
|
12
12
|
class EncryptionFilter
|
13
|
+
using ::Chamber::Refinements::DeepDup
|
14
|
+
|
13
15
|
BASE64_STRING_PATTERN = %r{\A[A-Za-z0-9+/]{342}==\z}.freeze
|
14
16
|
BASE64_SUBSTRING_PATTERN = %r{[A-Za-z0-9+/#]*={0,2}}.freeze
|
15
17
|
LARGE_DATA_STRING_PATTERN = /
|
@@ -27,8 +29,8 @@ class EncryptionFilter
|
|
27
29
|
attr_reader :encryption_keys
|
28
30
|
|
29
31
|
def initialize(data:, secure_key_prefix:, encryption_keys: {}, **_args)
|
30
|
-
self.encryption_keys = encryption_keys || {}
|
31
|
-
self.data = data.
|
32
|
+
self.encryption_keys = (encryption_keys || {}).transform_keys(&:to_s)
|
33
|
+
self.data = data.deep_dup
|
32
34
|
self.secure_key_token = /\A#{Regexp.escape(secure_key_prefix)}/
|
33
35
|
end
|
34
36
|
|
@@ -39,7 +41,7 @@ class EncryptionFilter
|
|
39
41
|
protected
|
40
42
|
|
41
43
|
def execute(raw_data = data, namespace = nil)
|
42
|
-
raw_data.each_with_object(
|
44
|
+
raw_data.each_with_object({}) do |(key, value), settings|
|
43
45
|
settings[key] = if value.respond_to? :each_pair
|
44
46
|
execute(value, namespace || key)
|
45
47
|
elsif key.match(secure_key_token)
|
@@ -51,7 +53,7 @@ class EncryptionFilter
|
|
51
53
|
end
|
52
54
|
|
53
55
|
def encryption_keys=(other)
|
54
|
-
@encryption_keys = other.each_with_object({}) do |(namespace, keyish), memo|
|
56
|
+
@encryption_keys = other.each_with_object({}) do |(namespace, keyish), memo| # rubocop:disable Style/HashTransformValues
|
55
57
|
memo[namespace] = if keyish.is_a?(OpenSSL::PKey::RSA)
|
56
58
|
keyish
|
57
59
|
elsif ::File.readable?(::File.expand_path(keyish))
|
@@ -67,7 +69,7 @@ class EncryptionFilter
|
|
67
69
|
|
68
70
|
def encrypt(namespace, key, value)
|
69
71
|
method = encryption_method(value)
|
70
|
-
encryption_key = encryption_keys[namespace] || encryption_keys[
|
72
|
+
encryption_key = encryption_keys[namespace] || encryption_keys['__default']
|
71
73
|
|
72
74
|
return value unless encryption_key
|
73
75
|
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'yaml'
|
4
|
-
require 'hashie/mash'
|
5
4
|
|
6
5
|
require 'chamber/errors/environment_conversion'
|
7
6
|
|
@@ -122,7 +121,7 @@ class EnvironmentFilter
|
|
122
121
|
private
|
123
122
|
|
124
123
|
def with_environment(settings, parent_keys, hash_block, value_block)
|
125
|
-
environment_hash =
|
124
|
+
environment_hash = {}
|
126
125
|
|
127
126
|
settings.each_pair do |key, value|
|
128
127
|
environment_key = key.to_s.gsub(secure_key_token, '')
|
@@ -170,13 +169,13 @@ class EnvironmentFilter
|
|
170
169
|
environment_value
|
171
170
|
end
|
172
171
|
rescue ArgumentError
|
173
|
-
raise Chamber::Errors::EnvironmentConversion,
|
174
|
-
We attempted to convert '#{environment_key}' from '#{environment_value}' to a '#{settings_value.class.name}'.
|
172
|
+
raise Chamber::Errors::EnvironmentConversion, <<~HEREDOC
|
173
|
+
We attempted to convert '#{environment_key}' from '#{environment_value}' to a '#{settings_value.class.name}'.
|
175
174
|
|
176
|
-
Unfortunately, this did not go as planned. Please either verify that your value is convertable
|
177
|
-
or change the original YAML value to be something more generic (like a String).
|
175
|
+
Unfortunately, this did not go as planned. Please either verify that your value is convertable
|
176
|
+
or change the original YAML value to be something more generic (like a String).
|
178
177
|
|
179
|
-
For more information, see https://github.com/thekompanee/chamber/wiki/Environment-Variable-Coercions
|
178
|
+
For more information, see https://github.com/thekompanee/chamber/wiki/Environment-Variable-Coercions
|
180
179
|
HEREDOC
|
181
180
|
end
|
182
181
|
end
|
@@ -1,10 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'chamber/errors/decryption_failure'
|
4
|
+
require 'chamber/refinements/deep_dup'
|
4
5
|
|
5
6
|
module Chamber
|
6
7
|
module Filters
|
7
8
|
class FailedDecryptionFilter
|
9
|
+
using ::Chamber::Refinements::DeepDup
|
10
|
+
|
8
11
|
BASE64_STRING_PATTERN = %r{\A[A-Za-z0-9+/]{342}==\z}.freeze
|
9
12
|
|
10
13
|
def self.execute(**args)
|
@@ -15,7 +18,7 @@ class FailedDecryptionFilter
|
|
15
18
|
:secure_key_token
|
16
19
|
|
17
20
|
def initialize(data:, secure_key_prefix:, **_args)
|
18
|
-
self.data = data.
|
21
|
+
self.data = data.deep_dup
|
19
22
|
self.secure_key_token = /\A#{Regexp.escape(secure_key_prefix)}/
|
20
23
|
end
|
21
24
|
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'hashie/mash'
|
4
3
|
require 'chamber/filters/secure_filter'
|
5
4
|
|
6
5
|
module Chamber
|
@@ -22,7 +21,7 @@ class InsecureFilter < SecureFilter
|
|
22
21
|
|
23
22
|
def execute(raw_data = data) # rubocop:disable Metrics/CyclomaticComplexity
|
24
23
|
securable_settings = super
|
25
|
-
settings =
|
24
|
+
settings = {}
|
26
25
|
|
27
26
|
securable_settings.each_pair do |key, value|
|
28
27
|
value = if value.respond_to? :each_pair
|
@@ -1,10 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'chamber/refinements/deep_dup'
|
4
|
+
require 'chamber/refinements/hash'
|
4
5
|
|
5
6
|
module Chamber
|
6
7
|
module Filters
|
7
8
|
class NamespaceFilter
|
9
|
+
using ::Chamber::Refinements::DeepDup
|
10
|
+
using ::Chamber::Refinements::Hash
|
11
|
+
|
8
12
|
def self.execute(**args)
|
9
13
|
new(**args).__send__(:execute)
|
10
14
|
end
|
@@ -13,26 +17,24 @@ class NamespaceFilter
|
|
13
17
|
:namespaces
|
14
18
|
|
15
19
|
def initialize(data:, namespaces:, **_args)
|
16
|
-
self.data =
|
20
|
+
self.data = data.deep_dup
|
17
21
|
self.namespaces = namespaces
|
18
22
|
end
|
19
23
|
|
20
24
|
protected
|
21
25
|
|
22
26
|
def execute
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
else
|
28
|
-
Hashie::Mash.new(data)
|
27
|
+
return data unless data_is_namespaced?
|
28
|
+
|
29
|
+
namespaces.each_with_object({}) do |namespace, filtered_data|
|
30
|
+
filtered_data.deep_merge!(data[namespace]) if data[namespace]
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
32
34
|
private
|
33
35
|
|
34
36
|
def data_is_namespaced?
|
35
|
-
@data_is_namespaced ||= data.keys.any? { |key| namespaces.include?
|
37
|
+
@data_is_namespaced ||= data.keys.any? { |key| namespaces.include?(key.to_s) }
|
36
38
|
end
|
37
39
|
end
|
38
40
|
end
|
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'chamber/refinements/deep_dup'
|
4
4
|
|
5
5
|
module Chamber
|
6
6
|
module Filters
|
7
7
|
class SecureFilter
|
8
|
+
using ::Chamber::Refinements::DeepDup
|
9
|
+
|
8
10
|
def self.execute(**args)
|
9
11
|
new(**args).__send__(:execute)
|
10
12
|
end
|
@@ -13,14 +15,14 @@ class SecureFilter
|
|
13
15
|
:secure_key_token
|
14
16
|
|
15
17
|
def initialize(data:, secure_key_prefix:, **_args)
|
16
|
-
self.data =
|
18
|
+
self.data = data.deep_dup
|
17
19
|
self.secure_key_token = /\A#{Regexp.escape(secure_key_prefix)}/
|
18
20
|
end
|
19
21
|
|
20
22
|
protected
|
21
23
|
|
22
24
|
def execute(raw_data = data)
|
23
|
-
settings =
|
25
|
+
settings = {}
|
24
26
|
|
25
27
|
raw_data.each_pair do |key, value|
|
26
28
|
secure_value = if value.respond_to? :each_pair
|
@@ -1,10 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'chamber/refinements/deep_dup'
|
4
4
|
|
5
5
|
module Chamber
|
6
6
|
module Filters
|
7
7
|
class TranslateSecureKeysFilter
|
8
|
+
using ::Chamber::Refinements::DeepDup
|
9
|
+
|
8
10
|
def self.execute(**args)
|
9
11
|
new(**args).__send__(:execute)
|
10
12
|
end
|
@@ -13,14 +15,14 @@ class TranslateSecureKeysFilter
|
|
13
15
|
:secure_key_token
|
14
16
|
|
15
17
|
def initialize(data:, secure_key_prefix:, **_args)
|
16
|
-
self.data = data.
|
18
|
+
self.data = data.deep_dup
|
17
19
|
self.secure_key_token = /\A#{Regexp.escape(secure_key_prefix)}/
|
18
20
|
end
|
19
21
|
|
20
22
|
protected
|
21
23
|
|
22
24
|
def execute(raw_data = data)
|
23
|
-
settings =
|
25
|
+
settings = {}
|
24
26
|
|
25
27
|
raw_data.each_pair do |key, value|
|
26
28
|
value = execute(value) if value.respond_to? :each_pair
|
data/lib/chamber/instance.rb
CHANGED
@@ -92,15 +92,5 @@ class Instance
|
|
92
92
|
)
|
93
93
|
.to_hash
|
94
94
|
end
|
95
|
-
|
96
|
-
def method_missing(name, *args)
|
97
|
-
return settings.public_send(name, *args) if settings.respond_to?(name)
|
98
|
-
|
99
|
-
super
|
100
|
-
end
|
101
|
-
|
102
|
-
def respond_to_missing?(name, include_private = false)
|
103
|
-
settings.respond_to?(name, include_private)
|
104
|
-
end
|
105
95
|
end
|
106
96
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Chamber
|
4
|
+
module Refinements
|
5
|
+
module DeepDup
|
6
|
+
refine ::Array do
|
7
|
+
def deep_dup
|
8
|
+
map { |i| i.respond_to?(:deep_dup) ? i.deep_dup : i.dup }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
refine ::Object do
|
13
|
+
def deep_dup
|
14
|
+
dup
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
refine ::Hash do
|
19
|
+
def deep_dup
|
20
|
+
dup.tap do |hash|
|
21
|
+
each_pair do |key, value|
|
22
|
+
if key.frozen? && key.is_a?(::String)
|
23
|
+
hash[key] = value.deep_dup
|
24
|
+
else
|
25
|
+
hash.delete(key)
|
26
|
+
hash[key.deep_dup] = value.deep_dup
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -9,8 +9,7 @@ class Enumerable
|
|
9
9
|
case object
|
10
10
|
when ::Hash
|
11
11
|
object.each do |(key, value)|
|
12
|
-
|
13
|
-
warn "WARNING: Non-String settings keys are deprecated and will be removed in Chamber 3.0. You attempted to access the '#{key}' setting. See https://github.com/thekompanee/chamber/wiki/Upgrading-To-Chamber-3.0#all-settings-keys-are-now-stored-as-strings for full details. Called from: '#{caller.to_a.first}'" unless key == yield(key) # rubocop:disable Layout/LineLength
|
12
|
+
fail ::Chamber::Errors::NonConformingKey unless key == yield(key)
|
14
13
|
|
15
14
|
deep_validate_keys(value, &block)
|
16
15
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Chamber
|
4
|
+
module Refinements
|
5
|
+
module Hash
|
6
|
+
refine ::Hash do
|
7
|
+
def deep_merge(other_hash, &block)
|
8
|
+
dup.deep_merge!(other_hash, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def deep_merge!(other_hash, &block)
|
12
|
+
merge!(other_hash) do |key, this_val, other_val|
|
13
|
+
if this_val.is_a?(::Hash) && other_val.is_a?(::Hash)
|
14
|
+
this_val.deep_merge(other_val, &block)
|
15
|
+
elsif block
|
16
|
+
yield(key, this_val, other_val)
|
17
|
+
else
|
18
|
+
other_val
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/chamber/settings.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'hashie/mash'
|
4
3
|
require 'chamber/namespace_set'
|
5
4
|
require 'chamber/filters/namespace_filter'
|
6
5
|
require 'chamber/filters/encryption_filter'
|
@@ -10,13 +9,18 @@ require 'chamber/filters/secure_filter'
|
|
10
9
|
require 'chamber/filters/translate_secure_keys_filter'
|
11
10
|
require 'chamber/filters/insecure_filter'
|
12
11
|
require 'chamber/filters/failed_decryption_filter'
|
12
|
+
require 'chamber/refinements/deep_dup'
|
13
13
|
require 'chamber/refinements/enumerable'
|
14
|
+
require 'chamber/refinements/hash'
|
14
15
|
|
15
16
|
###
|
16
17
|
# Internal: Represents the base settings storage needed for Chamber.
|
17
18
|
#
|
18
19
|
module Chamber
|
19
20
|
class Settings
|
21
|
+
using ::Chamber::Refinements::Hash
|
22
|
+
using ::Chamber::Refinements::DeepDup
|
23
|
+
|
20
24
|
attr_accessor :decryption_keys,
|
21
25
|
:encryption_keys,
|
22
26
|
:post_filters,
|
@@ -45,12 +49,12 @@ class Settings
|
|
45
49
|
|
46
50
|
::Chamber::Refinements::Enumerable.deep_validate_keys(settings, &:to_s)
|
47
51
|
|
48
|
-
self.decryption_keys = decryption_keys
|
49
|
-
self.encryption_keys = encryption_keys
|
50
|
-
self.namespaces = namespaces
|
52
|
+
self.decryption_keys = (decryption_keys || {}).transform_keys(&:to_s)
|
53
|
+
self.encryption_keys = (encryption_keys || {}).transform_keys(&:to_s)
|
54
|
+
self.namespaces = NamespaceSet.new(namespaces)
|
51
55
|
self.post_filters = post_filters
|
52
56
|
self.pre_filters = pre_filters
|
53
|
-
self.raw_data = settings
|
57
|
+
self.raw_data = settings.deep_dup
|
54
58
|
self.secure_key_prefix = secure_key_prefix
|
55
59
|
end
|
56
60
|
# rubocop:enable Metrics/ParameterLists
|
@@ -113,7 +117,7 @@ class Settings
|
|
113
117
|
# Returns a Hash
|
114
118
|
#
|
115
119
|
def to_hash
|
116
|
-
data.
|
120
|
+
data.deep_dup
|
117
121
|
end
|
118
122
|
|
119
123
|
###
|
@@ -205,7 +209,7 @@ class Settings
|
|
205
209
|
encryption_keys: encryption_keys.any? ? encryption_keys : other_settings.encryption_keys,
|
206
210
|
decryption_keys: decryption_keys.any? ? decryption_keys : other_settings.decryption_keys,
|
207
211
|
namespaces: (namespaces + other_settings.namespaces),
|
208
|
-
settings: raw_data.
|
212
|
+
settings: raw_data.deep_merge(other_settings.raw_data),
|
209
213
|
)
|
210
214
|
# rubocop:enable Layout/LineLength
|
211
215
|
end
|
@@ -232,10 +236,9 @@ class Settings
|
|
232
236
|
end
|
233
237
|
|
234
238
|
def [](key)
|
235
|
-
|
236
|
-
warn "WARNING: Accessing a non-existent key ('#{key}') with brackets will fail in Chamber 3.0. See https://github.com/thekompanee/chamber/wiki/Upgrading-To-Chamber-3.0#bracket-access-now-fails-on-non-existent-keys for full details. Called from: '#{caller.to_a.first}'" unless data.has_key?(key) # rubocop:disable Layout/LineLength
|
239
|
+
fail ::ArgumentError, 'Bracket access with anything other than a String is unsupported.' unless key.is_a?(::String)
|
237
240
|
|
238
|
-
data.
|
241
|
+
data.fetch(key)
|
239
242
|
end
|
240
243
|
|
241
244
|
def dig!(*args)
|
@@ -275,30 +278,10 @@ class Settings
|
|
275
278
|
))
|
276
279
|
end
|
277
280
|
|
278
|
-
def method_missing(name, *args)
|
279
|
-
if data.respond_to?(name)
|
280
|
-
warn "WARNING: Object notation access is deprecated and will be removed in Chamber 3.0. You attempted to access the '#{name}' setting. See https://github.com/thekompanee/chamber/wiki/Upgrading-To-Chamber-3.0#removal-of-object-notation-access for full details. Called from: '#{caller.to_a.first}'" # rubocop:disable Layout/LineLength
|
281
|
-
warn "WARNING: Predicate methods are deprecated and will be removed in Chamber 3.0. You attempted to access the '#{name}' setting. See https://github.com/thekompanee/chamber/wiki/Upgrading-To-Chamber-3.0#removal-of-predicate-accessors for full details. Called from: '#{caller.to_a.first}'" if name.to_s.end_with?('?') # rubocop:disable Layout/LineLength
|
282
|
-
|
283
|
-
data.public_send(name, *args)
|
284
|
-
else
|
285
|
-
super
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
def respond_to_missing?(name, include_private = false)
|
290
|
-
data.respond_to?(name, include_private)
|
291
|
-
end
|
292
|
-
|
293
281
|
protected
|
294
282
|
|
295
|
-
|
296
|
-
|
297
|
-
end
|
298
|
-
|
299
|
-
def namespaces=(raw_namespaces)
|
300
|
-
@namespaces = NamespaceSet.new(raw_namespaces)
|
301
|
-
end
|
283
|
+
attr_writer :namespaces,
|
284
|
+
:raw_data
|
302
285
|
|
303
286
|
# rubocop:disable Naming/MemoizedInstanceVariableName
|
304
287
|
def raw_data
|
@@ -40,7 +40,7 @@ class Secured < CHAMBER_TYPE_VALUE_SUPERCLASS
|
|
40
40
|
when Hash
|
41
41
|
value
|
42
42
|
when String
|
43
|
-
::
|
43
|
+
::JSON.parse(value)
|
44
44
|
when NilClass
|
45
45
|
nil
|
46
46
|
else
|
@@ -63,10 +63,10 @@ class Secured < CHAMBER_TYPE_VALUE_SUPERCLASS
|
|
63
63
|
def serialize(value)
|
64
64
|
fail ArgumentError, 'Any attributes encrypted with Chamber must be a Hash' unless value.is_a?(Hash)
|
65
65
|
|
66
|
-
::
|
67
|
-
Chamber.encrypt(value,
|
68
|
-
|
69
|
-
|
66
|
+
::JSON.dump(
|
67
|
+
::Chamber.encrypt(value,
|
68
|
+
decryption_keys: decryption_keys,
|
69
|
+
encryption_keys: encryption_keys),
|
70
70
|
)
|
71
71
|
end
|
72
72
|
alias type_cast_for_database serialize
|
data/lib/chamber/version.rb
CHANGED
data/lib/chamber.rb
CHANGED
@@ -11,10 +11,6 @@ module Chamber
|
|
11
11
|
self.instance = Instance.new(**args)
|
12
12
|
end
|
13
13
|
|
14
|
-
def env
|
15
|
-
instance.settings
|
16
|
-
end
|
17
|
-
|
18
14
|
def instance
|
19
15
|
@instance ||= Instance.new
|
20
16
|
end
|
@@ -81,29 +77,17 @@ module Chamber
|
|
81
77
|
instance.to_s(**args)
|
82
78
|
end
|
83
79
|
|
84
|
-
def method_missing(name, *args)
|
85
|
-
return instance.public_send(name, *args) if instance.respond_to?(name)
|
86
|
-
|
87
|
-
super
|
88
|
-
end
|
89
|
-
|
90
|
-
def respond_to_missing?(name, include_private = false)
|
91
|
-
instance.respond_to?(name, include_private)
|
92
|
-
end
|
93
|
-
|
94
80
|
module_function :[],
|
95
81
|
:configuration,
|
96
82
|
:decrypt,
|
97
83
|
:dig!,
|
98
84
|
:dig,
|
99
85
|
:encrypt,
|
100
|
-
:env,
|
101
86
|
:filenames,
|
102
87
|
:files,
|
103
88
|
:instance,
|
104
89
|
:instance=,
|
105
90
|
:load,
|
106
|
-
:method_missing,
|
107
91
|
:namespaces,
|
108
92
|
:respond_to_missing?,
|
109
93
|
:secure,
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chamber
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0rc2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- thekompanee
|
@@ -38,7 +38,7 @@ cert_chain:
|
|
38
38
|
ZjvLRaDI6IVoq0skZju//VZLiN6slVhAYYQj0uka/T0DZieabVYDcT4BVpa9M7Gz
|
39
39
|
CDW/VDWjvEEbsCIW0oYhtUrkqE8GLIdrpLUjefOERbS5TslD7lG/MH5k
|
40
40
|
-----END CERTIFICATE-----
|
41
|
-
date: 2022-03-
|
41
|
+
date: 2022-03-06 00:00:00.000000000 Z
|
42
42
|
dependencies:
|
43
43
|
- !ruby/object:Gem::Dependency
|
44
44
|
name: thor
|
@@ -60,20 +60,6 @@ dependencies:
|
|
60
60
|
- - "<"
|
61
61
|
- !ruby/object:Gem::Version
|
62
62
|
version: '2.0'
|
63
|
-
- !ruby/object:Gem::Dependency
|
64
|
-
name: hashie
|
65
|
-
requirement: !ruby/object:Gem::Requirement
|
66
|
-
requirements:
|
67
|
-
- - "~>"
|
68
|
-
- !ruby/object:Gem::Version
|
69
|
-
version: '3.3'
|
70
|
-
type: :runtime
|
71
|
-
prerelease: false
|
72
|
-
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
requirements:
|
74
|
-
- - "~>"
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: '3.3'
|
77
63
|
- !ruby/object:Gem::Dependency
|
78
64
|
name: rspec
|
79
65
|
requirement: !ruby/object:Gem::Requirement
|
@@ -183,11 +169,11 @@ files:
|
|
183
169
|
- lib/chamber/commands/verify.rb
|
184
170
|
- lib/chamber/configuration.rb
|
185
171
|
- lib/chamber/context_resolver.rb
|
186
|
-
- lib/chamber/core_ext/hash.rb
|
187
172
|
- lib/chamber/encryption_methods/none.rb
|
188
173
|
- lib/chamber/encryption_methods/public_key.rb
|
189
174
|
- lib/chamber/encryption_methods/ssl.rb
|
190
175
|
- lib/chamber/errors/decryption_failure.rb
|
176
|
+
- lib/chamber/errors/disallowed_class.rb
|
191
177
|
- lib/chamber/errors/environment_conversion.rb
|
192
178
|
- lib/chamber/errors/non_conforming_key.rb
|
193
179
|
- lib/chamber/file.rb
|
@@ -210,7 +196,9 @@ files:
|
|
210
196
|
- lib/chamber/keys/encryption.rb
|
211
197
|
- lib/chamber/namespace_set.rb
|
212
198
|
- lib/chamber/rails.rb
|
199
|
+
- lib/chamber/refinements/deep_dup.rb
|
213
200
|
- lib/chamber/refinements/enumerable.rb
|
201
|
+
- lib/chamber/refinements/hash.rb
|
214
202
|
- lib/chamber/rubinius_fix.rb
|
215
203
|
- lib/chamber/settings.rb
|
216
204
|
- lib/chamber/types/secured.rb
|
@@ -235,14 +223,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
235
223
|
requirements:
|
236
224
|
- - ">="
|
237
225
|
- !ruby/object:Gem::Version
|
238
|
-
version: 2.
|
226
|
+
version: 2.7.5
|
239
227
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
240
228
|
requirements:
|
241
|
-
- - "
|
229
|
+
- - ">"
|
242
230
|
- !ruby/object:Gem::Version
|
243
|
-
version:
|
231
|
+
version: 1.3.1
|
244
232
|
requirements: []
|
245
|
-
rubygems_version: 3.1.
|
233
|
+
rubygems_version: 3.1.6
|
246
234
|
signing_key:
|
247
235
|
specification_version: 4
|
248
236
|
summary: A surprisingly configurable convention-based approach to managing your application's
|
metadata.gz.sig
CHANGED
Binary file
|