encrypt_env 1.3.1 → 1.3.4
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/bin/encrypt_env +71 -47
- data/lib/encrypt_env/version.rb +5 -0
- data/lib/encrypt_env.rb +134 -39
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0108116f53998a69c29a421d3f0726cbaeb9affa7a194b891a4bcec681d0823e'
|
4
|
+
data.tar.gz: 0e13e28fa7e990f0ffc3950fbe429e1c5b49b0f986c8ee26e6a45f7da3007b66
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5c0ad88fdf14079b84b9a0364a8ef1e1381e1862083b608adc15706f2bcbdcc305de6cd943d5cd49b6b4d2b947458ea222da9105cd686a86d447e01fff29f56b
|
7
|
+
data.tar.gz: 4ae071fc5a3ce618cec111bb75b665f084def3e75debee1da01f445c555e46d56f91c88af521b9c5ff48421e94397b22645e6ec545483e76a0f5c72b0646dd6e
|
data/bin/encrypt_env
CHANGED
@@ -3,61 +3,85 @@
|
|
3
3
|
# frozen_string_literal: true
|
4
4
|
|
5
5
|
require 'encrypt_env'
|
6
|
+
require 'optparse'
|
7
|
+
require_relative '../lib/encrypt_env/version'
|
8
|
+
|
9
|
+
options = {}
|
10
|
+
parsers = OptionParser.new do |parser|
|
11
|
+
parser.on('-e', '--environment ENVIRONMENT', 'environment')
|
12
|
+
parser.on('-s', '--set VALUE', 'value')
|
13
|
+
parser.on('-t', '--type TYPE', 'type of variable')
|
14
|
+
parser.on('-a', '--all', 'show all') do
|
15
|
+
EncryptEnv.show('all')
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
parser.on('-v', '--version', 'version') do
|
19
|
+
puts Version::VERSION
|
20
|
+
exit
|
21
|
+
end
|
22
|
+
parser.on('-h', '--help', 'help') do
|
23
|
+
puts <<~HELP
|
24
|
+
Usage:
|
25
|
+
encrypt_env setup # To setup for the firt time
|
26
|
+
|
27
|
+
encrypt_env show # To show environment variables of current environment
|
28
|
+
encrypt_env show -a # To show all environment variables
|
29
|
+
encrypt_env show -e [environment] # To show specific environment variables
|
30
|
+
encrypt_env show [variable_name] -e [environment] # To show value of specific variable
|
31
|
+
|
32
|
+
encrypt_env edit # To edit environment variables of current environment
|
33
|
+
encrypt_env edit -e [environment] # To edit specific environment variables
|
34
|
+
encrypt_env edit [variable_name] -e [environment] # To edit value of specific variable
|
35
|
+
|
36
|
+
encrypt_env create variable_name # To create environment variable in current environment
|
37
|
+
encrypt_env create variable_name -e [environment] # To create environment variable in specific environment
|
38
|
+
# To create environment variable in specific environment with value and type
|
39
|
+
encrypt_env create variable_name -s [value] -e [environment]
|
40
|
+
encrypt_env create variable_name -s [value] -e [environment] -t [type]
|
41
|
+
|
42
|
+
encrypt_env delete variable_name # To delete environment variable in current environment
|
43
|
+
encrypt_env delete variable_name -e [environment] # To delete environment variable in specific environment
|
44
|
+
|
45
|
+
Or: Visit "https://github.com/nnhutan/encrypt_env" for more information
|
46
|
+
HELP
|
47
|
+
exit
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
parsers.parse!(into: options)
|
6
52
|
|
7
53
|
argv = ARGV
|
8
54
|
action = argv.shift
|
55
|
+
variable_name = argv.shift
|
9
56
|
|
10
|
-
|
57
|
+
case action
|
58
|
+
when 'setup'
|
11
59
|
EncryptEnv.setup
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
60
|
+
|
61
|
+
when 'show', 'edit'
|
62
|
+
EncryptEnv.send(action, options[:environment], variable_name)
|
63
|
+
|
64
|
+
when 'create'
|
65
|
+
unless variable_name
|
66
|
+
puts "Please provide 'variable's name'!"
|
67
|
+
exit
|
18
68
|
end
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
exit 0
|
23
|
-
elsif action == 'edit'
|
24
|
-
if argv[0]
|
25
|
-
EncryptEnv.edit(argv[0])
|
69
|
+
|
70
|
+
if options[:set]
|
71
|
+
EncryptEnv.create_with_value(variable_name, options[:set], options[:environment], options[:type])
|
26
72
|
else
|
27
|
-
EncryptEnv.
|
73
|
+
EncryptEnv.send(action, variable_name, options[:environment])
|
74
|
+
end
|
75
|
+
|
76
|
+
when 'delete'
|
77
|
+
unless variable_name
|
78
|
+
puts "Please provide 'variable's name'!"
|
79
|
+
exit
|
28
80
|
end
|
29
|
-
|
30
|
-
|
31
|
-
key = argv[0]
|
32
|
-
env = argv[1]
|
33
|
-
EncryptEnv.valueof(key, env)
|
34
|
-
exit 0
|
35
|
-
elsif action == 'new'
|
36
|
-
key = argv[0]
|
37
|
-
env = argv[1]
|
38
|
-
EncryptEnv.update_variable(key, env, true)
|
39
|
-
exit 0
|
40
|
-
elsif action == 'update'
|
41
|
-
key = argv[0]
|
42
|
-
env = argv[1]
|
43
|
-
EncryptEnv.update_variable(key, env, false)
|
44
|
-
exit 0
|
45
|
-
elsif action == 'delete'
|
46
|
-
key = argv[0]
|
47
|
-
env = argv[1]
|
48
|
-
EncryptEnv.delete_variable(key, env)
|
49
|
-
exit 0
|
50
|
-
elsif ['help', '--help', '-h'].include?(action)
|
51
|
-
puts <<~HELP
|
52
|
-
Usage:
|
53
|
-
encrypt_env setup
|
54
|
-
encrypt_env secrets
|
55
|
-
encrypt_env secrets_all
|
56
|
-
encrypt_env edit
|
57
|
-
HELP
|
58
|
-
|
59
|
-
exit 0
|
81
|
+
|
82
|
+
EncryptEnv.send(action, variable_name, options[:environment])
|
60
83
|
else
|
61
84
|
puts "Unknown action: #{action}"
|
62
|
-
|
85
|
+
puts "Use 'encrypt_env -h' for more help"
|
86
|
+
exit
|
63
87
|
end
|
data/lib/encrypt_env.rb
CHANGED
@@ -11,6 +11,8 @@ require 'json'
|
|
11
11
|
# rubocop:disable Metrics/ClassLength
|
12
12
|
# rubocop:disable Metrics/MethodLength
|
13
13
|
class EncryptEnv
|
14
|
+
@root_path = Dir.pwd
|
15
|
+
|
14
16
|
private_class_method def self.define_option
|
15
17
|
puts "Options to 'encrypt secrets.yml' file"
|
16
18
|
puts '1. Generate only one master.key and one encrypted file for all environment'
|
@@ -27,9 +29,9 @@ class EncryptEnv
|
|
27
29
|
end
|
28
30
|
|
29
31
|
private_class_method def self.load_curr_opt
|
30
|
-
if File.file?("#{
|
32
|
+
if File.file?("#{@root_path}/config/secrets.yml.enc")
|
31
33
|
@opt = 1
|
32
|
-
elsif Dir["#{
|
34
|
+
elsif Dir["#{@root_path}/config/secrets_*.yml.enc"].length.positive?
|
33
35
|
@opt = 2
|
34
36
|
else
|
35
37
|
raise 'You must setup first to encrypt file!'
|
@@ -46,7 +48,7 @@ class EncryptEnv
|
|
46
48
|
|
47
49
|
private_class_method def self.check_key_existence(env = nil)
|
48
50
|
file_name = env.nil? ? 'master.key' : "master_#{env}.key"
|
49
|
-
return if File.file?("#{
|
51
|
+
return if File.file?("#{@root_path}/config/#{file_name}")
|
50
52
|
return if ENV.key?('MASTER_KEY')
|
51
53
|
|
52
54
|
message = env ? "Missing key of #{env} environment!" : 'Missing master key!'
|
@@ -60,7 +62,7 @@ class EncryptEnv
|
|
60
62
|
raise e.message
|
61
63
|
end
|
62
64
|
|
63
|
-
file_path = env ? "#{
|
65
|
+
file_path = env ? "#{@root_path}/config/master_#{env}.key" : "#{@root_path}/config/master.key"
|
64
66
|
key = File.file?(file_path) ? File.read(file_path).strip : ENV['MASTER_KEY']
|
65
67
|
@master_key = [key].pack('H*')
|
66
68
|
end
|
@@ -68,19 +70,19 @@ class EncryptEnv
|
|
68
70
|
private_class_method def self.generate_keys
|
69
71
|
if @opt == 1
|
70
72
|
key = OpenSSL::Random.random_bytes(16)
|
71
|
-
File.open("#{
|
73
|
+
File.open("#{@root_path}/config/master.key", 'w') { |file| file.write(key.unpack('H*')[0]) }
|
72
74
|
else
|
73
75
|
to_hash_type(@content_to_encrypt).each_key do |env|
|
74
76
|
next if env == 'default'
|
75
77
|
|
76
78
|
key = OpenSSL::Random.random_bytes(16)
|
77
|
-
File.open("#{
|
79
|
+
File.open("#{@root_path}/config/master_#{env}.key", 'w') { |file| file.write(key.unpack('H*')[0]) }
|
78
80
|
end
|
79
81
|
end
|
80
82
|
end
|
81
83
|
|
82
84
|
private_class_method def self.load_content_to_encrypt
|
83
|
-
secret_file = File.expand_path("#{
|
85
|
+
secret_file = File.expand_path("#{@root_path}/config/secrets.yml")
|
84
86
|
@content_to_encrypt = File.read(secret_file)
|
85
87
|
end
|
86
88
|
|
@@ -89,7 +91,7 @@ class EncryptEnv
|
|
89
91
|
end
|
90
92
|
|
91
93
|
private_class_method def self.load_encrypted_data(env = nil)
|
92
|
-
file_path = env ? "#{
|
94
|
+
file_path = env ? "#{@root_path}/config/secrets_#{env}.yml.enc" : "#{@root_path}/config/secrets.yml.enc"
|
93
95
|
hex_string = File.read(file_path)
|
94
96
|
raw_data = [hex_string].pack('H*')
|
95
97
|
|
@@ -100,7 +102,7 @@ class EncryptEnv
|
|
100
102
|
end
|
101
103
|
|
102
104
|
private_class_method def self.encrypt(content, typ = nil)
|
103
|
-
file_path = typ ? "#{
|
105
|
+
file_path = typ ? "#{@root_path}/config/secrets_#{typ}.yml.enc" : "#{@root_path}/config/secrets.yml.enc"
|
104
106
|
cipher = OpenSSL::Cipher.new('aes-128-gcm')
|
105
107
|
cipher.encrypt
|
106
108
|
cipher.key = @master_key
|
@@ -119,6 +121,7 @@ class EncryptEnv
|
|
119
121
|
raise e.message
|
120
122
|
end
|
121
123
|
|
124
|
+
puts 'Decrypting...'
|
122
125
|
decipher = OpenSSL::Cipher.new('aes-128-gcm')
|
123
126
|
decipher.decrypt
|
124
127
|
data = load_encrypted_data(env)
|
@@ -138,7 +141,7 @@ class EncryptEnv
|
|
138
141
|
|
139
142
|
private_class_method def self.all_decrypted_object
|
140
143
|
obj = {}
|
141
|
-
env_lst = Dir["#{
|
144
|
+
env_lst = Dir["#{@root_path}/config/secrets_*.yml.enc"].map do |path|
|
142
145
|
path.scan(/secrets_(.*)\.yml\.enc/).flatten.first
|
143
146
|
end
|
144
147
|
env_lst.each do |e|
|
@@ -151,19 +154,23 @@ class EncryptEnv
|
|
151
154
|
def self.secrets_all
|
152
155
|
return all_decrypted_object if @opt == 2
|
153
156
|
|
154
|
-
decrypt
|
157
|
+
decrypt unless @decrypted
|
155
158
|
@decrypted
|
156
159
|
end
|
157
160
|
|
158
161
|
def self.secrets(env = nil)
|
159
162
|
load_curr_opt unless @opt
|
160
|
-
|
163
|
+
if env == 'all'
|
164
|
+
result = secrets_all
|
165
|
+
@decrypted = nil
|
166
|
+
return result
|
167
|
+
end
|
161
168
|
|
162
169
|
if @opt == 1
|
163
|
-
decrypt
|
170
|
+
decrypt unless @decrypted
|
164
171
|
@decrypted[env || current_env]
|
165
172
|
else
|
166
|
-
decrypt(env || current_env)
|
173
|
+
decrypt(env || current_env) unless @decrypted
|
167
174
|
@decrypted
|
168
175
|
end
|
169
176
|
rescue StandardError => e
|
@@ -189,13 +196,15 @@ class EncryptEnv
|
|
189
196
|
end
|
190
197
|
end
|
191
198
|
|
192
|
-
File.rename("#{
|
193
|
-
system("echo '/config/master*.key' >> #{
|
194
|
-
system("echo '/config/secrets.yml.old' >> #{
|
199
|
+
File.rename("#{@root_path}/config/secrets.yml", "#{@root_path}/config/secrets.yml.old")
|
200
|
+
system("echo '/config/master*.key' >> #{@root_path}/.gitignore")
|
201
|
+
system("echo '/config/secrets.yml.old' >> #{@root_path}/.gitignore")
|
195
202
|
system("echo 'Set up complete!'")
|
196
203
|
end
|
197
204
|
|
198
|
-
def self.edit(env = nil)
|
205
|
+
def self.edit(env = nil, variable_name = nil)
|
206
|
+
variable_name && (return create(variable_name, env, true))
|
207
|
+
|
199
208
|
load_curr_opt unless @opt
|
200
209
|
env ||= current_env if @opt == 2
|
201
210
|
return unless decrypt(env)
|
@@ -212,33 +221,36 @@ class EncryptEnv
|
|
212
221
|
puts e.message
|
213
222
|
end
|
214
223
|
|
215
|
-
def self.show(env = nil)
|
216
|
-
|
224
|
+
def self.show(env = nil, variable_name = nil)
|
225
|
+
variable_name && (return valueof(variable_name, env))
|
226
|
+
|
227
|
+
require 'awesome_print'
|
228
|
+
require 'date'
|
217
229
|
value = secrets(env)
|
218
|
-
|
219
|
-
#
|
220
|
-
jj value unless @have_error
|
230
|
+
ap(value) unless @have_error
|
231
|
+
# jj value unless @have_error
|
221
232
|
@have_error = false
|
222
233
|
end
|
223
234
|
|
224
235
|
def self.valueof(key, env = nil)
|
236
|
+
tail_msg = env ? " in '#{env}' environent" : nil
|
225
237
|
value = secrets(env)
|
226
238
|
unless value.key?(key)
|
227
|
-
puts "key '#{key}' does not exist!"
|
239
|
+
puts "key '#{key}' does not exist#{tail_msg}!"
|
228
240
|
return
|
229
241
|
end
|
230
242
|
puts value[key]
|
231
243
|
end
|
232
244
|
|
233
|
-
def self.
|
245
|
+
def self.delete(key, env = nil)
|
234
246
|
load_curr_opt unless @opt
|
235
247
|
if @opt == 1
|
236
248
|
puts 'Only for option 2!'
|
237
249
|
return
|
238
250
|
end
|
239
251
|
|
240
|
-
|
241
|
-
confirm = "Really? You want to delete '#{key}'#{
|
252
|
+
tail_msg = env ? " in '#{env}' environent" : nil
|
253
|
+
confirm = "Really? You want to delete '#{key}'#{tail_msg}? (y/n)"
|
242
254
|
puts confirm
|
243
255
|
a = $stdin.gets.chomp
|
244
256
|
return unless a == 'y'
|
@@ -246,38 +258,108 @@ class EncryptEnv
|
|
246
258
|
value = secrets(env)
|
247
259
|
|
248
260
|
unless value.key?(key)
|
249
|
-
puts "#{key} does not exist!"
|
261
|
+
puts "#{key} does not exist#{tail_msg}!"
|
250
262
|
return
|
251
263
|
end
|
252
264
|
|
265
|
+
tmp_value = value[key]
|
253
266
|
value.delete(key)
|
254
267
|
encrypt(value.to_hash.to_yaml, env || current_env)
|
255
|
-
puts "
|
268
|
+
puts "Delete '#{key}' with value '#{tmp_value}' successfully!"
|
269
|
+
end
|
270
|
+
|
271
|
+
private_class_method def self.define_type_new_variable
|
272
|
+
types = {
|
273
|
+
'1' => 'integer',
|
274
|
+
'2' => 'float',
|
275
|
+
'3' => 'string',
|
276
|
+
'4' => 'boolean'
|
277
|
+
}
|
278
|
+
puts 'What is the type of variable? (1/2/3/4)'
|
279
|
+
puts "1.\t integer"
|
280
|
+
puts "2.\t float"
|
281
|
+
puts "3.\t string"
|
282
|
+
puts "4.\t boolean"
|
283
|
+
puts "Or enter 'q' to cancle!"
|
284
|
+
|
285
|
+
loop do
|
286
|
+
type = $stdin.gets.chomp
|
287
|
+
return types[type] if %w[1 2 3 4].include?(type)
|
288
|
+
|
289
|
+
exit if type == 'q'
|
290
|
+
|
291
|
+
puts 'Just "1", "2", "3", "4" or "q" to cancel!'
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
private_class_method def self.type_coercion(value, type)
|
296
|
+
unless %w[integer float string boolean].include?(type)
|
297
|
+
puts "Variable's type must be 'interger', 'float', 'string' or 'boolean'!"
|
298
|
+
exit
|
299
|
+
end
|
300
|
+
|
301
|
+
type = define_type_new_variable if type.nil?
|
302
|
+
|
303
|
+
case type
|
304
|
+
when 'integer'
|
305
|
+
value.to_i
|
306
|
+
when 'float'
|
307
|
+
value.to_f
|
308
|
+
when 'string'
|
309
|
+
value
|
310
|
+
when 'boolean'
|
311
|
+
(value == 'true')
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
def self.create_with_value(key, new_value, env = nil, type = nil)
|
316
|
+
load_curr_opt unless @opt
|
317
|
+
if @opt == 1
|
318
|
+
puts 'Only for option 2!'
|
319
|
+
return
|
320
|
+
end
|
321
|
+
|
322
|
+
new_value = type_coercion(new_value, type)
|
323
|
+
|
324
|
+
tail_msg = env ? " in '#{env}' environment" : nil
|
325
|
+
|
326
|
+
value = secrets(env)
|
327
|
+
|
328
|
+
if value.key?(key)
|
329
|
+
puts "Key existed#{tail_msg}!"
|
330
|
+
return
|
331
|
+
end
|
332
|
+
|
333
|
+
value[key] = new_value
|
334
|
+
encrypt(value.to_hash.to_yaml, env || current_env)
|
335
|
+
@decrypted = nil
|
336
|
+
puts "#{key}\t=>\t#{value[key]}"
|
256
337
|
end
|
257
338
|
|
258
|
-
def self.
|
339
|
+
def self.create(key, env = nil, is_edit = false)
|
259
340
|
load_curr_opt unless @opt
|
260
341
|
if @opt == 1
|
261
342
|
puts 'Only for option 2!'
|
262
343
|
return
|
263
344
|
end
|
345
|
+
tail_msg = env ? " in '#{env}' environment" : nil
|
264
346
|
|
265
347
|
value = secrets(env)
|
266
|
-
|
267
|
-
|
348
|
+
|
349
|
+
if !is_edit && value.key?(key)
|
350
|
+
puts "Key existed#{tail_msg}!"
|
268
351
|
return
|
269
352
|
end
|
270
353
|
|
271
|
-
if !value.key?(key) &&
|
272
|
-
tail_msg
|
273
|
-
puts "'#{key}' does not exist#{tail_msg}. You want to add '#{key}' as the new key? (y/n)"
|
354
|
+
if !value.key?(key) && is_edit
|
355
|
+
puts "'#{key}' does not exist#{tail_msg}. You want to create '#{key}' as the new key? (y/n)"
|
274
356
|
a = $stdin.gets.chomp
|
275
357
|
return unless a == 'y'
|
276
358
|
|
277
|
-
|
359
|
+
is_edit = false
|
278
360
|
end
|
279
361
|
|
280
|
-
action =
|
362
|
+
action = is_edit && 'edit' || 'create'
|
281
363
|
file_name = env ? "#{action}_#{key}_#{env}" : "#{action}_#{key}"
|
282
364
|
|
283
365
|
Tempfile.create(file_name) do |f|
|
@@ -285,11 +367,24 @@ class EncryptEnv
|
|
285
367
|
f.flush
|
286
368
|
f.rewind
|
287
369
|
system("vim #{f.path}")
|
288
|
-
new_value = File.read(f.path)
|
289
|
-
|
370
|
+
# new_value = File.read(f.path)
|
371
|
+
new_value = YAML.load_file(f.path)
|
372
|
+
# value[key] = new_value.strip
|
373
|
+
value[key] = new_value
|
290
374
|
encrypt(value.to_hash.to_yaml, env || current_env)
|
291
375
|
@decrypted = nil
|
292
376
|
end
|
377
|
+
|
378
|
+
puts "#{key}\t=>\t#{value[key]}"
|
379
|
+
end
|
380
|
+
|
381
|
+
# def self.get
|
382
|
+
# self
|
383
|
+
# end
|
384
|
+
|
385
|
+
def self.method_missing(key, *_args)
|
386
|
+
secrets unless @decrypted
|
387
|
+
@decrypted[key]
|
293
388
|
end
|
294
389
|
end
|
295
390
|
# rubocop:enable Metrics/ClassLength
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: encrypt_env
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nhu Tan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-08-
|
11
|
+
date: 2022-08-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: awesome_print
|
@@ -39,6 +39,7 @@ extra_rdoc_files: []
|
|
39
39
|
files:
|
40
40
|
- bin/encrypt_env
|
41
41
|
- lib/encrypt_env.rb
|
42
|
+
- lib/encrypt_env/version.rb
|
42
43
|
homepage: https://github.com/nnhutan/encrypt_env.git
|
43
44
|
licenses:
|
44
45
|
- MIT
|