encrypt_env 1.1.6 → 1.2.1

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/bin/encrypt_env +11 -3
  3. data/lib/encrypt_env.rb +147 -71
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c832448cf2b0a36f7c9670495393c18b1fa3210bee11ff4218327bae0ff0caf6
4
- data.tar.gz: a692c2b86a27381592355ceb78521f46d2a3b73389b51ea4b3dc1b19dd8b5de8
3
+ metadata.gz: 6d696c60bf3a51762a466ccae6de5a7fea2a18b9e5c9ee744708e9541e097f2c
4
+ data.tar.gz: 36d4248ccbcf1c5121c28248dd045f40f3806c23be0519a3f01624148bb7c172
5
5
  SHA512:
6
- metadata.gz: 5a20fa7185459b94ce647ca1222da11d667b4ad8fdb8436c6c755d34c568fc3a52cff4b82a75770faf5d00e76ffbade05f6bfb061bd924d83c0a6c345c319458
7
- data.tar.gz: 52375f8d2461d89ded146e7b678e60d2dfc38389f6da2401a731e812290a784df2a2b1cf6163589d10eb50158f1a3b6e87974e81d2efb40b7e17cc0fb187c7c9
6
+ metadata.gz: ebb16a54fda48f54342a9d2987dcdf95d37b2c32b20ee304428e4d435d794d1b6e5a303233e2c26104c3534756d37c1f1dc554025becb72ef55e3a6b9f62fa69
7
+ data.tar.gz: 3add45fbf64eef00a7f0d131229bb9dab796f99bf43d0529d9f34b8dbd635a5e198d32afaed210cfd3c356dcfa7184215bfda83fca47b145d6cf6d1371fad1a9
data/bin/encrypt_env CHANGED
@@ -11,13 +11,21 @@ if action == 'setup'
11
11
  EncryptEnv.setup
12
12
  exit 0
13
13
  elsif action == 'show'
14
- EncryptEnv.show
14
+ if argv[0]
15
+ EncryptEnv.show(argv[0])
16
+ else
17
+ EncryptEnv.show
18
+ end
15
19
  exit 0
16
20
  elsif action == 'all'
17
- EncryptEnv.show_all
21
+ EncryptEnv.show('all')
18
22
  exit 0
19
23
  elsif action == 'edit'
20
- EncryptEnv.edit
24
+ if argv[0]
25
+ EncryptEnv.edit(argv[0])
26
+ else
27
+ EncryptEnv.edit
28
+ end
21
29
  exit 0
22
30
  elsif ['help', '--help', '-h'].include?(action)
23
31
  puts <<~HELP
data/lib/encrypt_env.rb CHANGED
@@ -8,32 +8,96 @@ require 'tempfile'
8
8
  require 'json'
9
9
 
10
10
  # gem 'encrypt_env'
11
+ # rubocop:disable Metrics/ClassLength
12
+ # rubocop:disable Metrics/MethodLength
11
13
  class EncryptEnv
12
- private_class_method def self.master_key
13
- if File.file?("#{@path_root}/config/master.key")
14
- key = File.read("#{@path_root}/config/master.key").strip
15
- @master_key = [key].pack('H*')
16
- puts 'Get master key success!'
17
- true
18
- elsif ENV.key?('MASTER_KEY')
19
- @master_key = [ENV['MASTER_KEY']].pack('H*')
20
- puts 'Get master key success!'
21
- true
14
+ private_class_method def self.define_option
15
+ puts "Options to 'encrypt secrets.yml' file"
16
+ puts '1. Generate only one master.key and one encrypted file for all environment'
17
+ puts '2. Generate master.key and encrypted file for each environment'
18
+
19
+ loop do
20
+ @opt = gets.chomp.to_i
21
+ break if @opt == 1 || @opt == 2
22
+
23
+ puts "Please enter '1' or '2'!"
24
+ end
25
+
26
+ puts "Your option is #{@opt}"
27
+ end
28
+
29
+ private_class_method def self.load_curr_opt
30
+ if File.file?("#{Dir.pwd}/config/secrets.yml.enc")
31
+ @opt = 1
32
+ elsif Dir["#{Dir.pwd}/config/secrets_*.yml.enc"].length.positive?
33
+ @opt = 2
22
34
  else
23
- puts 'Get master key fail!'
24
- false
35
+ puts 'You must setup first to encrypt file!'
36
+ exit
37
+ end
38
+ end
39
+
40
+ private_class_method def self.current_env
41
+ unless defined?(Rails)
42
+ env = `rails r "print Rails.env"`
43
+ return env
25
44
  end
45
+ Rails.env
26
46
  end
27
47
 
28
- private_class_method def self.data_decrypt(raw_data)
48
+ private_class_method def self.check_key_existence(env = nil)
49
+ file_name = env.nil? ? 'master.key' : "master_#{env}.key"
50
+ return if File.file?("#{Dir.pwd}/config/#{file_name}")
51
+ # return if Dir["#{Dir.pwd}/config/master_*.key"].length.positive? && @opt == 2
52
+ return if ENV.key?('MASTER_KEY')
53
+
54
+ puts 'Please provide master key!'
55
+ exit
56
+ end
57
+
58
+ private_class_method def self.load_master_key(env = nil)
59
+ check_key_existence(env)
60
+ file_path = env ? "#{Dir.pwd}/config/master_#{env}.key" : "#{Dir.pwd}/config/master.key"
61
+ key = File.file?(file_path) ? File.read(file_path).strip : ENV['MASTER_KEY']
62
+ @master_key = [key].pack('H*')
63
+ end
64
+
65
+ private_class_method def self.generate_keys
66
+ if @opt == 1
67
+ key = OpenSSL::Random.random_bytes(16)
68
+ File.open("#{Dir.pwd}/config/master.key", 'w') { |file| file.write(key.unpack('H*')[0]) }
69
+ else
70
+ to_hash_type(@content_to_encrypt).each_key do |env|
71
+ next if env == 'default'
72
+
73
+ key = OpenSSL::Random.random_bytes(16)
74
+ File.open("#{Dir.pwd}/config/master_#{env}.key", 'w') { |file| file.write(key.unpack('H*')[0]) }
75
+ end
76
+ end
77
+ end
78
+
79
+ private_class_method def self.load_content_to_encrypt
80
+ secret_file = File.expand_path("#{Dir.pwd}/config/secrets.yml")
81
+ @content_to_encrypt = File.read(secret_file)
82
+ end
83
+
84
+ private_class_method def self.to_hash_type(raw_data)
85
+ HashWithIndifferentAccess.new(YAML.load(raw_data, aliases: true))
86
+ end
87
+
88
+ private_class_method def self.load_encrypted_data(env = nil)
89
+ file_path = env ? "#{Dir.pwd}/config/secrets_#{env}.yml.enc" : "#{Dir.pwd}/config/secrets.yml.enc"
90
+ hex_string = File.read(file_path)
91
+ raw_data = [hex_string].pack('H*')
92
+
29
93
  encrypted = raw_data.slice(0, raw_data.length - 28)
30
94
  iv = raw_data.slice(raw_data.length - 28, 12)
31
95
  tag = raw_data.slice(raw_data.length - 16, 16)
32
96
  { encrypted: encrypted, iv: iv, tag: tag }
33
97
  end
34
98
 
35
- private_class_method def self.encrypt(content)
36
- master_key unless @master_key
99
+ private_class_method def self.encrypt(content, typ = nil)
100
+ file_path = typ ? "#{Dir.pwd}/config/secrets_#{typ}.yml.enc" : "#{Dir.pwd}/config/secrets.yml.enc"
37
101
  cipher = OpenSSL::Cipher.new('aes-128-gcm')
38
102
  cipher.encrypt
39
103
  cipher.key = @master_key
@@ -42,20 +106,15 @@ class EncryptEnv
42
106
  encrypted = cipher.update(content) + cipher.final
43
107
  tag = cipher.auth_tag
44
108
  hex_string = (encrypted + iv + tag).unpack('H*')[0]
45
- File.open("#{@path_root}/config/secrets.yml.enc", 'w') { |file| file.write(hex_string) }
109
+ File.open(file_path, 'w') { |file| file.write(hex_string) }
46
110
  end
47
111
 
48
- private_class_method def self.decrypt
49
- path_root unless @path_root
50
- if @master_key.nil? && !master_key
51
- puts "master key not found in 'config/master.key' file and 'MASTER_KEY' environment variable!"
52
- @raw_decrypted = ''
53
- return false
54
- end
112
+ private_class_method def self.decrypt(env = nil)
113
+ load_master_key(env)
114
+
55
115
  decipher = OpenSSL::Cipher.new('aes-128-gcm')
56
116
  decipher.decrypt
57
- hex_string = File.read("#{@path_root}/config/secrets.yml.enc")
58
- data = data_decrypt([hex_string].pack('H*'))
117
+ data = load_encrypted_data(env)
59
118
  encrypted = data[:encrypted]
60
119
  decipher.key = @master_key
61
120
  decipher.iv = data[:iv]
@@ -63,69 +122,86 @@ class EncryptEnv
63
122
  decipher.auth_data = ''
64
123
 
65
124
  @raw_decrypted = decipher.update(encrypted) + decipher.final
66
- @decrypted = HashWithIndifferentAccess.new(YAML.load(@raw_decrypted, aliases: true))
67
- true
125
+ @decrypted = to_hash_type(@raw_decrypted)
126
+ # Catch error if master key is wrong
127
+ rescue OpenSSL::Cipher::CipherError
128
+ puts 'Master key is wrong!'
129
+ exit
68
130
  end
69
131
 
70
- private_class_method def self.path_root
71
- @path_root = if defined?(Rails)
72
- Rails.root.to_s
73
- elsif defined?(Bundler)
74
- Bundler.root.to_s
75
- else
76
- Dir.pwd
77
- end
132
+ private_class_method def self.all_decrypted_object
133
+ obj = {}
134
+ env_lst = Dir["#{Dir.pwd}/config/secrets_*.yml.enc"].map do |path|
135
+ path.scan(/secrets_(.*)\.yml\.enc/).flatten.first
136
+ end
137
+ env_lst.each do |e|
138
+ decrypt(e)
139
+ obj[e] = @decrypted
140
+ end
141
+ obj
78
142
  end
79
143
 
80
- def self.setup
81
- path_root
82
- @secret_file = File.expand_path("#{@path_root}/config/secrets.yml")
83
- key = OpenSSL::Random.random_bytes(16)
84
- # save key in master.key file
85
- File.open("#{@path_root}/config/master.key", 'w') { |file| file.write(key.unpack('H*')[0]) }
86
- encrypt(File.read(@secret_file))
87
- File.rename(@secret_file, "#{@path_root}/config/secrets.yml.old")
88
- system("echo '/config/master.key' >> #{@path_root}/.gitignore")
89
- system("echo '/config/secrets.yml.old' >> #{@path_root}/.gitignore")
90
- system("echo 'Set up complete!'")
144
+ def self.secrets_all
145
+ return all_decrypted_object if @opt == 2
146
+
147
+ decrypt
148
+ @decrypted
91
149
  end
92
150
 
93
- def self.edit
94
- return unless decrypt
151
+ def self.secrets(env = nil)
152
+ load_curr_opt unless @opt
153
+ return secrets_all if env == 'all'
95
154
 
96
- Tempfile.create('secrets.yml') do |f|
97
- f.write(@raw_decrypted)
98
- f.flush
99
- f.rewind
100
- system("vim #{f.path}")
101
- encrypt(File.read(f.path))
102
- @decrypted = nil
155
+ if @opt == 1
156
+ decrypt
157
+ @decrypted[env || current_env]
158
+ else
159
+ decrypt(env || current_env)
160
+ @decrypted
103
161
  end
104
162
  end
105
163
 
106
- def self.secrets_all
107
- return @decrypted if @decrypted
164
+ def self.setup
165
+ define_option
166
+ load_content_to_encrypt
167
+ generate_keys
168
+
169
+ if @opt == 1
170
+ load_master_key
171
+ encrypt(@content_to_encrypt)
172
+ else
173
+ to_hash_type(@content_to_encrypt).each do |env, value|
174
+ next if env == 'default'
108
175
 
109
- return @decrypted if decrypt
176
+ load_master_key(env)
177
+ encrypt(value.to_hash.to_yaml, env)
178
+ end
179
+ end
110
180
 
111
- {}
181
+ File.rename("#{Dir.pwd}/config/secrets.yml", "#{Dir.pwd}/config/secrets.yml.old")
182
+ system("echo '/config/master*.key' >> #{Dir.pwd}/.gitignore")
183
+ system("echo '/config/secrets.yml.old' >> #{Dir.pwd}/.gitignore")
184
+ system("echo 'Set up complete!'")
112
185
  end
113
186
 
114
- def self.secrets
115
- return {} if !@decrypted && !decrypt
187
+ def self.edit(env = nil)
188
+ load_curr_opt unless @opt
189
+ env ||= current_env if @opt == 2
190
+ return unless decrypt(env)
116
191
 
117
- unless defined?(Rails)
118
- env = `rails r "print Rails.env"`.to_sym
119
- return @decrypted[env]
192
+ Tempfile.create("secrets_#{env}.yml") do |f|
193
+ f.write(@raw_decrypted)
194
+ f.flush
195
+ f.rewind
196
+ system("vim #{f.path}")
197
+ encrypt(File.read(f.path), env)
198
+ @decrypted = nil
120
199
  end
121
- @decrypted[Rails.env.to_sym]
122
- end
123
-
124
- def self.show
125
- jj secrets
126
200
  end
127
201
 
128
- def self.show_all
129
- jj secrets_all
202
+ def self.show(env = nil)
203
+ jj secrets(env)
130
204
  end
131
205
  end
206
+ # rubocop:enable Metrics/ClassLength
207
+ # rubocop:enable Metrics/MethodLength
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.1.6
4
+ version: 1.2.1
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-08 00:00:00.000000000 Z
11
+ date: 2022-08-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Encrypts and decrypts environment variables
14
14
  email: nhutan2001@gmail.com