opensecret 0.0.941 → 0.0.946
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/crypto/amalgam.rb +22 -159
- data/lib/crypto/blowfish.rb +85 -0
- data/lib/crypto/collect.rb +1 -0
- data/lib/crypto/engineer.rb +27 -147
- data/lib/crypto/open.bcrypt.rb +170 -0
- data/lib/crypto/verify.rb +1 -1
- data/lib/{session/exceptions.rb → exception/cli.error.rb} +2 -2
- data/lib/exception/errors/cli.errors.rb +31 -0
- data/lib/factbase/facts.opensecret.io.ini +1 -1
- data/lib/notepad/blow.rb +14 -0
- data/lib/opensecret.rb +11 -3
- data/lib/opensecret/commons/eco.system.rb +1 -1
- data/lib/opensecret/executors/crypt.keys/crypt.keys.rb +1 -1
- data/lib/opensecret/executors/decrypt/decrypt.rb +1 -1
- data/lib/opensecret/executors/encrypt/encrypt.rb +1 -1
- data/lib/plugins/cipher.rb +179 -0
- data/lib/plugins/ciphers/aes-256.rb +162 -0
- data/lib/plugins/ciphers/blowfish.rb +223 -0
- data/lib/plugins/stores/store.rb +4 -0
- data/lib/{usecase → plugins}/usecase.rb +3 -12
- data/lib/{usecase → plugins}/usecases/init.rb +29 -41
- data/lib/{usecase → plugins}/usecases/on.rb +0 -0
- data/lib/{usecase → plugins}/usecases/safe.rb +2 -4
- data/lib/session/require.gem.rb +107 -0
- data/lib/version.rb +1 -1
- metadata +16 -8
- data/lib/config.opensecret.ini +0 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f03e1b5d062560593f42736baf5a2af7794a4c0b
|
4
|
+
data.tar.gz: ed65d8e10bd446f1413d9e0473b7291ec01f34a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57989150d89ee5cc20d5950bd008b5bc97f4b23455dc690b66f791d1b3d1330a7550ce888715c73abf4bf43dd4ce80e409202c5393a7b32cc1bc41d75d97e047
|
7
|
+
data.tar.gz: 842b02b7f3a2fbf99fdd3c9d4acbeeabcf16bed137894cf8d2ad1cc4aed54f6d39975c2d16714e3d8e16eb62bc9271d2a2a60bee2d6bd12c954bfeef0b71cb3b
|
data/lib/crypto/amalgam.rb
CHANGED
@@ -2,45 +2,33 @@
|
|
2
2
|
|
3
3
|
module OpenSecret
|
4
4
|
|
5
|
-
# This class
|
6
|
-
#
|
7
|
-
# Ubuntu, Windows, RHEL, CoreOS, iOS or CentOS command line interface.
|
5
|
+
# This class knows how to amalgamate passwords, keys and string data in
|
6
|
+
# a manner that is the cryptographical equivalent of synergy.
|
8
7
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
class
|
8
|
+
# The amalgamated keys are synergially (cryptographically) greater than
|
9
|
+
# the sum of their parts.
|
10
|
+
class Amalgam
|
12
11
|
|
13
|
-
#
|
12
|
+
# Amalgamate the two parameter passwords in a manner that is the
|
13
|
+
# cryptographical equivalent of synergy. The amalgamated keys are
|
14
|
+
# synergially greater than the sum of their parts.
|
14
15
|
#
|
15
|
-
#
|
16
|
-
#
|
16
|
+
# -- Get a viable machine password taking into account the human
|
17
|
+
# -- password length and the specified mix_ratio.
|
17
18
|
#
|
18
|
-
# The domain will be extended to cover verified internet domains.
|
19
|
-
# They will also latch onto LDAP domains so when admins add, revoke
|
20
|
-
# or remove users, their opensecret access is adjusted accordingly.
|
21
19
|
#
|
22
|
-
# @param
|
23
|
-
# @param
|
20
|
+
# @param human_password [String] the password originating from a human
|
21
|
+
# @param machine_key [String] a machine engineered ascii password (key)
|
22
|
+
# @mixparam machine_key [String] a machine engineered ascii password (key)
|
24
23
|
#
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
|
37
|
-
# --
|
38
|
-
# -- Get a viable machine password taking into account the human
|
39
|
-
# -- password length and the specified mix_ratio.
|
40
|
-
# --
|
41
|
-
# -- machine password length = human password length * mix_ratio - 1
|
42
|
-
# --
|
43
|
-
def self.get_amalgam_password human_password, machine_password, mix_ratio
|
24
|
+
# @return [String] the union of the two parameter passwords
|
25
|
+
#
|
26
|
+
# @raise [ArgumentError] when the size of the two passwords and the
|
27
|
+
# mix ratio do not conform to the constraint imposed by the below
|
28
|
+
# equation which must hold true.
|
29
|
+
# <tt>machine password length = human password length * mix_ratio - 1</tt>
|
30
|
+
#
|
31
|
+
def self.passwords human_password, machine_password, mix_ratio
|
44
32
|
|
45
33
|
size_error_msg = "Human pass length times mix_ratio must equal machine pass length."
|
46
34
|
lengths_are_perfect = human_password.length * mix_ratio == machine_password.length
|
@@ -70,132 +58,7 @@ module OpenSecret
|
|
70
58
|
end
|
71
59
|
|
72
60
|
|
73
|
-
# --
|
74
|
-
# -- Get a viable machine password taking into account the human
|
75
|
-
# -- password length and the specified mix_ratio.
|
76
|
-
# --
|
77
|
-
# -- machine password length = human password length * mix_ratio - 1
|
78
|
-
# --
|
79
|
-
def self.get_machine_password human_password_length, mix_ratio
|
80
|
-
|
81
|
-
machine_raw_secret = engineer_password( human_password_length * ( mix_ratio + 1) )
|
82
|
-
return machine_raw_secret[ 0..( human_password_length * mix_ratio - 1 ) ]
|
83
|
-
|
84
|
-
end
|
85
|
-
|
86
|
-
|
87
|
-
# --
|
88
|
-
# -- Collect a password from the user with a minimum length
|
89
|
-
# -- specified in the parameter.
|
90
|
-
# --
|
91
|
-
# -- An exception is raised if the minimum length is not at
|
92
|
-
# -- least 8 characters.
|
93
|
-
# --
|
94
|
-
def self.collect_secret minimum_size, prompt_1, prompt_2
|
95
|
-
|
96
|
-
assert_min_size minimum_size
|
97
|
-
|
98
|
-
sleep(1)
|
99
|
-
puts "\n#{prompt_1} : "
|
100
|
-
first_secret = STDIN.noecho(&:gets).chomp
|
101
|
-
|
102
|
-
assert_input_text_size first_secret.length, minimum_size
|
103
|
-
|
104
|
-
sleep(1)
|
105
|
-
puts "\n#{prompt_2} : "
|
106
|
-
check_secret = STDIN.noecho(&:gets).chomp
|
107
|
-
|
108
|
-
assert_same_size_text first_secret, check_secret
|
109
|
-
|
110
|
-
return first_secret
|
111
|
-
|
112
|
-
end
|
113
|
-
|
114
|
-
|
115
|
-
# --
|
116
|
-
# -- Engineer a raw password that is similar (approximate) in
|
117
|
-
# -- length to the integer parameter.
|
118
|
-
# --
|
119
|
-
def self.engineer_password approx_length
|
120
|
-
|
121
|
-
non_alphanum = SecureRandom.urlsafe_base64(approx_length);
|
122
|
-
return non_alphanum.delete("-_")
|
123
|
-
|
124
|
-
end
|
125
|
-
|
126
|
-
|
127
|
-
# --
|
128
|
-
# -- Raise an exception if asked to collect text that is less
|
129
|
-
# -- than 3 characters in length.
|
130
|
-
# --
|
131
|
-
def self.assert_min_size minimum_size
|
132
|
-
|
133
|
-
min_length_msg = "\n\nCrypts with 2 (or less) characters open up exploitable holes.\n\n"
|
134
|
-
raise ArgumentError.new min_length_msg if minimum_size < 3
|
135
|
-
|
136
|
-
end
|
137
|
-
|
138
|
-
|
139
|
-
# --
|
140
|
-
# -- Output an error message and then exit if the entered input
|
141
|
-
# -- text size does not meet the minimum requirements.
|
142
|
-
# --
|
143
|
-
def self.assert_input_text_size input_size, minimum_size
|
144
|
-
|
145
|
-
if( input_size < minimum_size )
|
146
|
-
|
147
|
-
puts
|
148
|
-
puts "Input is too short. Please enter at least #{minimum_size} characters."
|
149
|
-
puts
|
150
|
-
|
151
|
-
exit
|
152
|
-
|
153
|
-
end
|
154
|
-
|
155
|
-
end
|
156
|
-
|
157
|
-
|
158
|
-
# --
|
159
|
-
# -- Assert that the text entered the second time is exactly (case sensitive)
|
160
|
-
# -- the same as the text entered the first time.
|
161
|
-
# --
|
162
|
-
def self.assert_same_size_text first_text, second_text
|
163
|
-
|
164
|
-
unless( first_text.eql? second_text )
|
165
|
-
|
166
|
-
puts
|
167
|
-
puts "Those two bits of text are not the same (in my book)!"
|
168
|
-
puts
|
169
|
-
|
170
|
-
exit
|
171
|
-
|
172
|
-
end
|
173
|
-
|
174
|
-
end
|
175
|
-
|
176
|
-
|
177
|
-
# --
|
178
|
-
# -- Print out the machine password that is to be kept as an environment variable
|
179
|
-
# -- on any workstation used for material decryption.
|
180
|
-
# --
|
181
|
-
# -- Remember that neither the human nor machine passwords are required for the
|
182
|
-
# -- encryption phase. That is the beauty of assymetric cryptography - you don't
|
183
|
-
# -- need a private key to encrypt - just the end user's public key.
|
184
|
-
# --
|
185
|
-
def self.print_secret_env_var env_var_name, env_var_value
|
186
|
-
|
187
|
-
machine_to_env_txt = "sudo echo \"#{env_var_name}=#{env_var_value}\" >> /etc/environment"
|
188
|
-
|
189
|
-
puts
|
190
|
-
puts "@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
191
|
-
puts "@@@ Add as environment variable @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
192
|
-
puts "@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
193
|
-
puts machine_to_env_txt
|
194
|
-
puts "@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
195
|
-
puts
|
196
|
-
|
197
|
-
end
|
198
|
-
|
199
61
|
end
|
200
62
|
|
63
|
+
|
201
64
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
class BF < Struct.new(:key, :pad_with_spaces)
|
6
|
+
def encrypt(str)
|
7
|
+
cipher = OpenSSL::Cipher.new('bf-ecb').encrypt
|
8
|
+
if pad_with_spaces
|
9
|
+
str += " " until str.bytesize % 8 == 0
|
10
|
+
cipher.padding = 0
|
11
|
+
end
|
12
|
+
cipher.key = key
|
13
|
+
binary_data = cipher.update(str) << cipher.final
|
14
|
+
hex_encoded = binary_data.unpack('H*').first
|
15
|
+
end
|
16
|
+
|
17
|
+
def decrypt(hex_encoded)
|
18
|
+
cipher = OpenSSL::Cipher.new('bf-ecb').decrypt
|
19
|
+
cipher.padding = 0 if pad_with_spaces
|
20
|
+
cipher.key = key
|
21
|
+
binary_data = [hex_encoded].pack('H*')
|
22
|
+
str = cipher.update(binary_data) << cipher.final
|
23
|
+
str.force_encoding(Encoding::UTF_8)
|
24
|
+
str
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
=begin
|
29
|
+
# Choose the encryption key. Its length must be a multiple of 8 and no longer than 56
|
30
|
+
bf = BF.new("x"*56, true)
|
31
|
+
sentence = ARGV[0] || "foo bar foo bar foo bar foo bar foo bar foo bar baz"
|
32
|
+
encrypted = bf.encrypt(sentence)
|
33
|
+
puts encrypted.length
|
34
|
+
puts sentence.inspect
|
35
|
+
puts "Encrypt: #{encrypted}"
|
36
|
+
puts "Decoded: #{bf.decrypt encrypted}"
|
37
|
+
=end
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
=begin
|
42
|
+
require 'openssl'
|
43
|
+
module Blowfish
|
44
|
+
def self.cipher(mode, key, data)
|
45
|
+
cipher = OpenSSL::Cipher::Cipher.new('bf-cbc').send(mode)
|
46
|
+
cipher.key = Digest::SHA256.digest(key)
|
47
|
+
cipher.update(data) << cipher.final
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.encrypt(key, data)
|
51
|
+
cipher(:encrypt, key, data)
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.decrypt(key, text)
|
55
|
+
cipher(:decrypt, key, text)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
if $0 == __FILE__
|
60
|
+
p "text" == Blowfish.decrypt("key", Blowfish.encrypt("key", "text"))
|
61
|
+
end
|
62
|
+
=end
|
63
|
+
|
64
|
+
=begin
|
65
|
+
module Blowfish
|
66
|
+
def self.cipher(mode, key, data)
|
67
|
+
cipher = OpenSSL::Cipher::Cipher.new('bf-cbc').send(mode)
|
68
|
+
cipher.key = Digest::SHA256.digest(key)
|
69
|
+
cipher.update(data) << cipher.final
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.encrypt(key, data)
|
73
|
+
cipher(:encrypt, key, data)
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.decrypt(key, text)
|
77
|
+
cipher(:decrypt, key, text)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
if $0 == __FILE__
|
82
|
+
p "text" == Blowfish.decrypt("key", Blowfish.encrypt("key", "text"))
|
83
|
+
end
|
84
|
+
|
85
|
+
=end
|
data/lib/crypto/collect.rb
CHANGED
data/lib/crypto/engineer.rb
CHANGED
@@ -2,73 +2,15 @@
|
|
2
2
|
|
3
3
|
module OpenSecret
|
4
4
|
|
5
|
+
require 'securerandom'
|
6
|
+
|
5
7
|
# This class will be refactored into an interface implemented by a set
|
6
8
|
# of plugins that will capture sensitive information from users from an
|
7
9
|
# Ubuntu, Windows, RHEL, CoreOS, iOS or CentOS command line interface.
|
8
10
|
#
|
9
11
|
# An equivalent REST API will also be available for bringing in sensitive
|
10
12
|
# information in the most secure (but simple) manner.
|
11
|
-
class
|
12
|
-
|
13
|
-
# Register two fundamental opensecret crypt pointers
|
14
|
-
#
|
15
|
-
# - an opensecret domain like » **lecturers@harvard**
|
16
|
-
# - the url to a backend store like Git, S3 or an SSH accessible drive.
|
17
|
-
#
|
18
|
-
# The domain will be extended to cover verified internet domains.
|
19
|
-
# They will also latch onto LDAP domains so when admins add, revoke
|
20
|
-
# or remove users, their opensecret access is adjusted accordingly.
|
21
|
-
#
|
22
|
-
# @param domain [String] the DOMAIN eg lecturers@harvard for your family or work group.
|
23
|
-
# @param store_url [String] the STORE_URL for connecting to the backend storage service
|
24
|
-
#
|
25
|
-
def self.register_domain domain, store_url
|
26
|
-
|
27
|
-
# -> read config file map
|
28
|
-
# -> create new domain in map
|
29
|
-
# -> add type and store url to map
|
30
|
-
# -> backup configuration
|
31
|
-
# -> overwrite the ini config file
|
32
|
-
puts "hello i am registering this super domain #{domain} at #{store_url}"
|
33
|
-
|
34
|
-
end
|
35
|
-
|
36
|
-
|
37
|
-
# --
|
38
|
-
# -- Get a viable machine password taking into account the human
|
39
|
-
# -- password length and the specified mix_ratio.
|
40
|
-
# --
|
41
|
-
# -- machine password length = human password length * mix_ratio - 1
|
42
|
-
# --
|
43
|
-
def self.get_amalgam_password human_password, machine_password, mix_ratio
|
44
|
-
|
45
|
-
size_error_msg = "Human pass length times mix_ratio must equal machine pass length."
|
46
|
-
lengths_are_perfect = human_password.length * mix_ratio == machine_password.length
|
47
|
-
raise ArgumentError.new size_error_msg unless lengths_are_perfect
|
48
|
-
|
49
|
-
machine_passwd_chunk = 0
|
50
|
-
amalgam_passwd_index = 0
|
51
|
-
amalgamated_password = ""
|
52
|
-
|
53
|
-
human_password.each_char do |passwd_char|
|
54
|
-
|
55
|
-
amalgamated_password[amalgam_passwd_index] = passwd_char
|
56
|
-
amalgam_passwd_index += 1
|
57
|
-
|
58
|
-
for i in 0..(mix_ratio-1) do
|
59
|
-
machine_pass_index = machine_passwd_chunk * mix_ratio + i
|
60
|
-
amalgamated_password[amalgam_passwd_index] = machine_password[machine_pass_index]
|
61
|
-
amalgam_passwd_index += 1
|
62
|
-
end
|
63
|
-
|
64
|
-
machine_passwd_chunk += 1
|
65
|
-
|
66
|
-
end
|
67
|
-
|
68
|
-
return amalgamated_password
|
69
|
-
|
70
|
-
end
|
71
|
-
|
13
|
+
class Engineer
|
72
14
|
|
73
15
|
# --
|
74
16
|
# -- Get a viable machine password taking into account the human
|
@@ -76,7 +18,7 @@ module OpenSecret
|
|
76
18
|
# --
|
77
19
|
# -- machine password length = human password length * mix_ratio - 1
|
78
20
|
# --
|
79
|
-
def self.
|
21
|
+
def self.machine_key human_password_length, mix_ratio
|
80
22
|
|
81
23
|
machine_raw_secret = engineer_password( human_password_length * ( mix_ratio + 1) )
|
82
24
|
return machine_raw_secret[ 0..( human_password_length * mix_ratio - 1 ) ]
|
@@ -84,34 +26,6 @@ module OpenSecret
|
|
84
26
|
end
|
85
27
|
|
86
28
|
|
87
|
-
# --
|
88
|
-
# -- Collect a password from the user with a minimum length
|
89
|
-
# -- specified in the parameter.
|
90
|
-
# --
|
91
|
-
# -- An exception is raised if the minimum length is not at
|
92
|
-
# -- least 8 characters.
|
93
|
-
# --
|
94
|
-
def self.collect_secret minimum_size, prompt_1, prompt_2
|
95
|
-
|
96
|
-
assert_min_size minimum_size
|
97
|
-
|
98
|
-
sleep(1)
|
99
|
-
puts "\n#{prompt_1} : "
|
100
|
-
first_secret = STDIN.noecho(&:gets).chomp
|
101
|
-
|
102
|
-
assert_input_text_size first_secret.length, minimum_size
|
103
|
-
|
104
|
-
sleep(1)
|
105
|
-
puts "\n#{prompt_2} : "
|
106
|
-
check_secret = STDIN.noecho(&:gets).chomp
|
107
|
-
|
108
|
-
assert_same_size_text first_secret, check_secret
|
109
|
-
|
110
|
-
return first_secret
|
111
|
-
|
112
|
-
end
|
113
|
-
|
114
|
-
|
115
29
|
# --
|
116
30
|
# -- Engineer a raw password that is similar (approximate) in
|
117
31
|
# -- length to the integer parameter.
|
@@ -124,78 +38,44 @@ module OpenSecret
|
|
124
38
|
end
|
125
39
|
|
126
40
|
|
127
|
-
# --
|
128
|
-
# -- Raise an exception if asked to collect text that is less
|
129
|
-
# -- than 3 characters in length.
|
130
|
-
# --
|
131
|
-
def self.assert_min_size minimum_size
|
132
|
-
|
133
|
-
min_length_msg = "\n\nCrypts with 2 (or less) characters open up exploitable holes.\n\n"
|
134
|
-
raise ArgumentError.new min_length_msg if minimum_size < 3
|
135
|
-
|
136
|
-
end
|
137
|
-
|
138
41
|
|
139
42
|
# --
|
140
|
-
# --
|
141
|
-
# --
|
142
|
-
# --
|
143
|
-
def self.assert_input_text_size input_size, minimum_size
|
144
|
-
|
145
|
-
if( input_size < minimum_size )
|
146
|
-
|
147
|
-
puts
|
148
|
-
puts "Input is too short. Please enter at least #{minimum_size} characters."
|
149
|
-
puts
|
150
|
-
|
151
|
-
exit
|
152
|
-
|
153
|
-
end
|
154
|
-
|
155
|
-
end
|
156
|
-
|
157
|
-
|
43
|
+
# -- Get a viable machine password taking into account the human
|
44
|
+
# -- password length and the specified mix_ratio.
|
158
45
|
# --
|
159
|
-
# --
|
160
|
-
# -- the same as the text entered the first time.
|
46
|
+
# -- machine password length = human password length * mix_ratio - 1
|
161
47
|
# --
|
162
|
-
def self.
|
163
|
-
|
164
|
-
unless( first_text.eql? second_text )
|
48
|
+
def self.get_amalgam_password human_password, machine_password, mix_ratio
|
165
49
|
|
166
|
-
|
167
|
-
|
168
|
-
|
50
|
+
size_error_msg = "Human pass length times mix_ratio must equal machine pass length."
|
51
|
+
lengths_are_perfect = human_password.length * mix_ratio == machine_password.length
|
52
|
+
raise ArgumentError.new size_error_msg unless lengths_are_perfect
|
169
53
|
|
170
|
-
|
54
|
+
machine_passwd_chunk = 0
|
55
|
+
amalgam_passwd_index = 0
|
56
|
+
amalgamated_password = ""
|
171
57
|
|
172
|
-
|
58
|
+
human_password.each_char do |passwd_char|
|
173
59
|
|
174
|
-
|
60
|
+
amalgamated_password[amalgam_passwd_index] = passwd_char
|
61
|
+
amalgam_passwd_index += 1
|
175
62
|
|
63
|
+
for i in 0..(mix_ratio-1) do
|
64
|
+
machine_pass_index = machine_passwd_chunk * mix_ratio + i
|
65
|
+
amalgamated_password[amalgam_passwd_index] = machine_password[machine_pass_index]
|
66
|
+
amalgam_passwd_index += 1
|
67
|
+
end
|
176
68
|
|
177
|
-
|
178
|
-
# -- Print out the machine password that is to be kept as an environment variable
|
179
|
-
# -- on any workstation used for material decryption.
|
180
|
-
# --
|
181
|
-
# -- Remember that neither the human nor machine passwords are required for the
|
182
|
-
# -- encryption phase. That is the beauty of assymetric cryptography - you don't
|
183
|
-
# -- need a private key to encrypt - just the end user's public key.
|
184
|
-
# --
|
185
|
-
def self.print_secret_env_var env_var_name, env_var_value
|
69
|
+
machine_passwd_chunk += 1
|
186
70
|
|
187
|
-
|
71
|
+
end
|
188
72
|
|
189
|
-
|
190
|
-
puts "@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
191
|
-
puts "@@@ Add as environment variable @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
192
|
-
puts "@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
193
|
-
puts machine_to_env_txt
|
194
|
-
puts "@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"
|
195
|
-
puts
|
73
|
+
return amalgamated_password
|
196
74
|
|
197
75
|
end
|
198
76
|
|
77
|
+
|
199
78
|
end
|
200
79
|
|
80
|
+
|
201
81
|
end
|