opensecret 0.0.988 → 0.0.9925

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 (62) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +56 -159
  3. data/bin/opensecret +2 -2
  4. data/bin/ops +17 -2
  5. data/lib/extension/string.rb +14 -16
  6. data/lib/{interpreter.rb → interprete.rb} +53 -29
  7. data/lib/keytools/binary.map.rb +49 -0
  8. data/lib/keytools/kdf.api.rb +249 -0
  9. data/lib/keytools/kdf.bcrypt.rb +64 -29
  10. data/lib/keytools/kdf.pbkdf2.rb +92 -83
  11. data/lib/keytools/kdf.scrypt.rb +190 -0
  12. data/lib/keytools/key.64.rb +326 -0
  13. data/lib/keytools/key.algo.rb +109 -0
  14. data/lib/keytools/key.api.rb +1281 -0
  15. data/lib/keytools/key.db.rb +265 -0
  16. data/lib/keytools/{key.module.rb → key.docs.rb} +55 -0
  17. data/lib/keytools/key.error.rb +110 -0
  18. data/lib/keytools/key.id.rb +271 -0
  19. data/lib/keytools/key.iv.rb +107 -0
  20. data/lib/keytools/key.local.rb +265 -0
  21. data/lib/keytools/key.mach.rb +248 -0
  22. data/lib/keytools/key.now.rb +402 -0
  23. data/lib/keytools/key.pair.rb +259 -0
  24. data/lib/keytools/key.pass.rb +120 -0
  25. data/lib/keytools/key.rb +428 -298
  26. data/lib/keytools/keydebug.txt +295 -0
  27. data/lib/logging/gem.logging.rb +3 -3
  28. data/lib/modules/cryptology/collect.rb +20 -0
  29. data/lib/session/require.gem.rb +1 -1
  30. data/lib/usecase/cmd.rb +417 -0
  31. data/lib/usecase/id.rb +36 -0
  32. data/lib/usecase/import.rb +174 -0
  33. data/lib/usecase/init.rb +78 -0
  34. data/lib/usecase/login.rb +70 -0
  35. data/lib/usecase/logout.rb +30 -0
  36. data/lib/usecase/open.rb +126 -0
  37. data/lib/{interprete → usecase}/put.rb +100 -47
  38. data/lib/usecase/read.rb +89 -0
  39. data/lib/{interprete → usecase}/safe.rb +0 -0
  40. data/lib/{interprete → usecase}/set.rb +0 -0
  41. data/lib/usecase/token.rb +111 -0
  42. data/lib/{interprete → usecase}/use.rb +0 -0
  43. data/lib/version.rb +1 -1
  44. data/opensecret.gemspec +4 -3
  45. metadata +39 -33
  46. data/lib/exception/cli.error.rb +0 -53
  47. data/lib/exception/errors/cli.errors.rb +0 -31
  48. data/lib/interprete/begin.rb +0 -232
  49. data/lib/interprete/cmd.rb +0 -621
  50. data/lib/interprete/export.rb +0 -163
  51. data/lib/interprete/init.rb +0 -205
  52. data/lib/interprete/key.rb +0 -119
  53. data/lib/interprete/open.rb +0 -148
  54. data/lib/interprete/seal.rb +0 -129
  55. data/lib/keytools/digester.rb +0 -245
  56. data/lib/keytools/key.data.rb +0 -227
  57. data/lib/keytools/key.derivation.rb +0 -341
  58. data/lib/modules/mappers/collateral.rb +0 -282
  59. data/lib/modules/mappers/envelope.rb +0 -127
  60. data/lib/modules/mappers/settings.rb +0 -170
  61. data/lib/notepad/scratch.pad.rb +0 -224
  62. data/lib/store-commands.txt +0 -180
@@ -1,53 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- module OpenError
4
-
5
- # This class is the parent to all opensession errors
6
- # that originate from the command line.
7
- #
8
- # All opensession cli originating errors are about
9
- #
10
- # - a problem with the input or
11
- # - a problem with the current state or
12
- # - a predictable future problem
13
- class CliError < StandardError
14
-
15
-
16
- # Initialize the error and provide a culprit
17
- # object which will be to-stringed and given
18
- # out as evidence (look at this)!
19
- #
20
- # This method will take care of loggin the error.
21
- #
22
- # @param message [String] human readable error message
23
- # @param culprit [Object] object that is either pertinent, a culprit or culpable
24
- def initialize message, culprit
25
-
26
- super(message)
27
-
28
- @the_culprit = culprit
29
-
30
- log.info(x) { "An [Error] Occured => #{message}" }
31
- log.info(x) { "Object of Interest => #{culprit.to_s}" } unless culprit.nil?
32
- log.info(x) { "Class Name Culprit => #{culprit.class.name}" }
33
- log.info(x) { "Error Message From => #{self.class.name}" }
34
- e.backtrace.to_s.log_lines
35
-
36
- end
37
-
38
-
39
- # This method gives interested parties the object that
40
- # is at the centre of the exception. This object is either
41
- # very pertinent, culpable or at the very least, interesting.
42
- #
43
- # @return [String] string representation of culpable object
44
- def culprit
45
- return "No culprit identified." if @the_culprit.nil?
46
- return @the_culprit.to_s
47
- end
48
-
49
-
50
- end
51
-
52
-
53
- end
@@ -1,31 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- # XXXXXXXXXXXXXXXXXXXX is this printed by yard
4
- # XXXXXXXXXXXXXXXXXXXX is this printed by yard
5
- # XXXXXXXXXXXXXXXXXXXX is this printed by yard
6
- # XXXXXXXXXXXXXXXXXXXX is this printed by yard
7
- # @note are modules documented by yard
8
- # or are they simply ignored.
9
- module OpenError
10
-
11
- =begin
12
- # Throw this error if the configured safe directory points to a file.
13
- class SafeDirectoryIsFile < OpenError::CliError; end;
14
-
15
- # Throw this error if safe directory path is either nil or empty.
16
- class SafeDirNotConfigured < OpenError::CliError; end;
17
-
18
- # Throw this error if the email address is nil, empty or less than 5 characters.
19
- class EmailAddrNotConfigured < OpenError::CliError; end;
20
-
21
- # Throw this error if the store url is either nil or empty.
22
- class StoreUrlNotConfigured < OpenError::CliError; end;
23
-
24
- # Throw if "prime folder" name occurs 2 or more times in the path.
25
- class SafePrimeNameRepeated < OpenError::CliError; end;
26
-
27
- # Throw if "prime folder" name occurs 2 or more times in the path.
28
- class SafePrimeNameNotAtEnd < OpenError::CliError; end;
29
- =end
30
-
31
- end
@@ -1,232 +0,0 @@
1
- #!/usr/bin/ruby
2
-
3
- module OpenSecret
4
-
5
- require 'openssl'
6
-
7
- # Collecting and immediately <b>locking up the master password</b> is
8
- # the sole purpose of the <tt>begin use case</tt>.
9
- #
10
- # Under certain conditions this {Begin} use case takes the human (key)
11
- # password and transforms it using a powerful message digester and then
12
- # uses the decrypted form of the <b>OPS_KEY environment variable</b> to
13
- # securely encrypt the generated key.
14
- #
15
- # This use case then writes (or overwrites) into the workstation configuration
16
- # under the domain three (3) key/value pairs which are
17
- #
18
- # - the parent shell id encrypted using the decrypted OPS_KEY form
19
- # - the time stamp that will be used as a nonce by future cases
20
- # - the generated digested hash encrypted with the decrypted OPS_KEY
21
- #
22
- # Then the use case prints a success message and exits.
23
- #
24
- # <b>Laziness | The 4 Conditions Instigating Action</b>
25
- #
26
- # No state is changed unless 3 conditions are met. We take action only if
27
- # all four of the below conditions are true.
28
- #
29
- # - the encrypted private key is present under the domain's front end drive
30
- # - the OPS_KEY is present - Otherwise we report the error and then EXIT
31
- # - the decrypted PPID is not present or does not match - Otherwise all is good
32
- # - the password is found in at least 1 of 7 places - Otherwise we error EXIT
33
- #
34
- # If all four conditions are true then we take action and ultimately write
35
- # (or overwrite) the 3 key/value pairs stated above into the domain section of
36
- # the workstation's configuration file.
37
- #
38
- # == OPS_KEY environment variable | Pre-Condition
39
- #
40
- # We cannot securely lock the master password without the uncrackable
41
- # <b>48 character session key</b> encrypted so that it is only accessible
42
- # by the single shell that opensecret is being called from.
43
- #
44
- # Therefore it is a pre-requisite that the session key has been created
45
- # and locked down by the {key} use case using the below shell command.
46
- #
47
- # $ export OPS_KEY=`ops key` # Export the generated session key
48
- # $ env | grep OPS_KEY # Check that OPS_KEY indeed exists
49
- #
50
- # Note the <b>back-ticks</b> surrounding the <tt>ops key</tt> call.
51
- #
52
- # == Where Does {Begin} Fit?
53
- #
54
- # The <tt>ops begin</tt> use case is called near the beginning of EVERY
55
- # opensecret command session.
56
- #
57
- # <b>Called Before (once per domain)</b>
58
- #
59
- # $ ops init <<domain_name>>, <<drive_path>>
60
- #
61
- # <b>Called Before (once per session)</b>
62
- #
63
- # At the beginning of every sitting (session) we must create a session key.
64
- #
65
- # $ export OPS_KEY=`ops key` # Export the generated session key
66
- # $ ops begin # Kicks off the opensecret session
67
- #
68
- # The password will then be retrieved safely via a prompt. Note there are
69
- # several other ways to deliver a password securely and/or via non-human
70
- # actors <b>like scripts</b>.
71
- #
72
- # <b>Called After</b>
73
- #
74
- # A whole plethora of commands such as open, put, seal, post, reopen, read
75
- # write, import and export.
76
- #
77
- # The {end} use case safely cleans up and tears down session keys and data.
78
- #
79
- # $ ops end
80
- #
81
- # When the shell closes OPS_KEY disappears forever. However if you want to
82
- # continue using the same shell you can wipe this away.
83
- #
84
- # $ unset OPS_KEY # Delete the shell session key
85
- # $ env | grep OPS_KEY # Check OPS_KEY is deleted
86
- #
87
- # You can also delete every env var created by this shell.
88
- #
89
- # $ env -i bash # Rewind to (after) login variables
90
- #
91
- #
92
- # <b>The 7 Ways to Communicate a Password</b>
93
- #
94
- # Soon, seven secure methods of password delivery will be implemented and
95
- # will include
96
- #
97
- # - collection from an environment varialbe set before execution
98
- # - collection from a (possibly encrypted) local file
99
- # - collection key-value stores such as Redis, etcd and Cassandra
100
- # - collection via secure (https) including to tokenized S3 urls
101
- #
102
- class Begin < Command
103
-
104
- attr_writer :outer_path, :master_p4ss, :domain_name
105
-
106
-
107
- # If <b>4 conditions are met</b> this {Begin} use case takes the human (key)
108
- # password and transforms it using a powerful message digester and then
109
- # uses the decrypted form of the <b>OPS_KEY environment variable</b> to
110
- # securely encrypt the generated key.
111
- #
112
- # This use case then writes (or overwrites) into the workstation configuration
113
- # under the domain three (3) key/value pairs which are
114
- #
115
- # - the parent shell id encrypted using the decrypted OPS_KEY form
116
- # - the time stamp that will be used as a nonce by future cases
117
- # - the generated digested hash encrypted with the decrypted OPS_KEY
118
- #
119
- # Then the use case prints a success message and exits.
120
- #
121
- # <b>Laziness | The 4 Conditions Instigating Action</b>
122
- #
123
- # No state is changed unless 3 conditions are met. We take action only if
124
- # all four of the below conditions are true.
125
- #
126
- # - the encrypted private key is present under the domain's front end drive
127
- # - the OPS_KEY is present - Otherwise we report the error and then EXIT
128
- # - the decrypted PPID is not present or does not match - Otherwise all is good
129
- # - the password is found in at least 1 of 7 places - Otherwise we error EXIT
130
- #
131
- # If all four conditions are true then we take action and ultimately write
132
- # (or overwrite) the 3 key/value pairs stated above into the domain section of
133
- # the workstation's configuration file.
134
- #
135
- #
136
- # <b>The 7 Ways to Communicate a Password</b>
137
- #
138
- # Soon, seven secure methods of password delivery will be implemented and
139
- # will include
140
- #
141
- # - collection from an environment varialbe set before execution
142
- # - collection from a (possibly encrypted) local file
143
- # - collection key-value stores such as Redis, etcd and Cassandra
144
- # - collection via secure (https) including to tokenized S3 urls
145
- #
146
- # <b>Begin | Observable Value</b>
147
- #
148
- # There are three valuable state changes enacted by this use case.
149
- #
150
- # - the <b>password for the domain is collected</b> (in one of several ways)
151
- # - the <b>session key</b> is acquired from crypted OPS_KEY environment variable
152
- # - an <b>encrypted password</b> results from locking password with session key
153
- # - the <b>encrypted password</b> is put into the domain's configuration keystore
154
- # - a <b>timestamped session folder</b> is created to harbour session artifacts
155
- #
156
- # <b>Summary </b>
157
- #
158
- # Observable value is the opensecret domain password locked with a robust
159
- # symmetric encryption key that is at least 48 characters in length and
160
- # placed into the domain's keystore configuration file.
161
- def execute
162
-
163
- hash_dict = OpenKey::Dictionary.create_with_section "/home/apollo/.opensecret.io/tmp.backing.file.txt", "this.section"
164
- OpenKey::Key256.generate( "human_secret", hash_dict )
165
-
166
- exit
167
-
168
- for n in 0 .. 63
169
-
170
- bcrypt_key = OpenKey::BCryptKeyGen.new.generate_key("human_secret")
171
- bcrypt_len = bcrypt_key.to_s.length
172
- pbkdf2_key = OpenKey::Pbkdf2KeyGen.new.generate_key("human_secret")
173
- pbkdf2_len = pbkdf2_key.to_s.length
174
-
175
- index = "%02d" % [ n.to_s ]
176
-
177
- puts "---------------------------------------------------------------------"
178
- puts "Calculation Number [#{index}]"
179
- puts "---------------------------------------------------------------------"
180
- puts "Len #{bcrypt_key.to_oc64.length} => #{bcrypt_key.to_oc64}"
181
- puts "Len #{bcrypt_len} => #{bcrypt_key.to_s}"
182
- puts "Len #{pbkdf2_key.to_oc64.length} => #{pbkdf2_key.to_oc64}"
183
- puts "Len #{pbkdf2_len} => #{pbkdf2_key.to_s}"
184
-
185
- end
186
-
187
- exit
188
-
189
-
190
-
191
- return unless ops_key_exists?
192
-
193
- instantiate_collateral
194
- @domain_name = @collateral.domain_name
195
-
196
- return unless private_key_exists?
197
-
198
- lock_stored = Mapper::Settings.contains_key?( session_id, MASTER_LOCK_KEY_NAME )
199
- print_success_initializing if lock_stored
200
- return if lock_stored
201
-
202
- unless @master_p4ss
203
- @master_p4ss = ToolBelt::Collect.secret_text(
204
- @c[:global][:min_passwd_len],
205
- false,
206
- "Enter Ops Password "
207
- )
208
- end
209
-
210
- create_crypt_store_locking_key
211
- print_success_initializing
212
-
213
- end
214
-
215
-
216
- # Perform pre-conditional validations in preparation to executing the main flow
217
- # of events for this use case. This method may throw the below exceptions.
218
- #
219
- # @raise [SafeDirNotConfigured] if the safe's url has not been configured
220
- # @raise [EmailAddrNotConfigured] if the email address has not been configured
221
- # @raise [StoreUrlNotConfigured] if the crypt store url is not configured
222
- def pre_validation
223
-
224
- end
225
-
226
-
227
- end
228
-
229
-
230
- end
231
-
232
-
@@ -1,621 +0,0 @@
1
- #!/usr/bin/ruby
2
- # coding: utf-8
3
-
4
- module OpenSecret
5
-
6
- # The parent OpenSecret use case is designed to be extended by the cli
7
- # (command line) use cases like {OpenSecret::Open}, {OpenSecret::Put} and
8
- # {OpenSecret::Lock} because it describes behaviour common to at least two
9
- # (but usually more) of the use cases.
10
- #
11
- # == Common Use Case Behaviour
12
- #
13
- # This {OpenSecret::Command} use case is designed to be extended and does preparatory
14
- # work to create favourable and useful conditions to make use cases readable,
15
- # less repetitive, simpler and concise.
16
- class Command
17
-
18
-
19
- # Get the envelope that <b>was opened</b> by the open command but
20
- # <b>not locked</b> with the lock command.
21
- #
22
- # @return [Envelope]
23
- # return the Envelope that has been opened. The state carried alongside an
24
- # open envelope is an id, an encryption key and a filepath all inside the
25
- # userhome configuration file.
26
- def get_envelope
27
-
28
- encrypt_key = Mapper::Settings.read @c[:open][:open_name], @c[:open][:open_keyname]
29
- rel_filepath = Mapper::Settings.read @c[:open][:open_name], @c[:open][:open_pathname]
30
-
31
- put_filepath = File.join( Mapper::Collateral.instance.session_envelopes_path, rel_filepath )
32
- the_envelope = Mapper::Envelope.new
33
- the_envelope.read put_filepath, encrypt_key
34
- return the_envelope
35
-
36
- end
37
-
38
-
39
- # This method uses a one-way function to return a combinatorial digested
40
- # session identification string using a number of distinct parameters that
41
- # deliver the important behaviours of changing in certain circumstances
42
- # and remaining unchanged in others.
43
- #
44
- # <b>Change | When Should the Session ID Change?</b>
45
- #
46
- # The session id is not a secret but it has to be unique due to its role
47
- # in indexing the session envelopes and their changes.
48
- #
49
- # What is really important is that the <b>session id changes</b> when
50
- #
51
- # - the <b>domain</b> being used changes
52
- # - the <b>command shell</b> changes
53
- # - the user <b>switches to another workstation user</b>
54
- # - the <b>workstation host</b> is changed
55
- # - the <b>OPS KEY</b> environment variable changes
56
- # - the user <b>SSH's</b> into another shell
57
- #
58
- # A distinct workstation is identified by the first MAC address and the
59
- # hostname of the machine.
60
- #
61
- # <b>Unchanged | When Should it Remain Unchanged?</b>
62
- #
63
- # Remaining <b>unchanged</b> in certain scenarious is a session ID feature
64
- # that is just as important as it changing in others.
65
- #
66
- # The session ID <b>must remain unchanged</b> when
67
- #
68
- # - the <b>user returns to a command shell</b>
69
- # - the user <b>switches back to using a domain</b>
70
- # - the user exits their <b>remote SSH session</b>
71
- # - <b>sudo is used</b> to execute the commands
72
- # - the user comes back to their <b>workstation</b>
73
- # - the clock ticks into another day, month, year ...
74
- #
75
- # The pre-hash inputs are an amalgam of the below example data.
76
- #
77
- # Mac Address => 20cf3067dec3
78
- # Parent PID => 5817
79
- # Machine Host => data-cruncher
80
- # Session Time => 18083.0310.41.796577366
81
- #
82
- # @return [String]
83
- # the session id
84
- def session_id
85
-
86
- require 'macaddr'
87
- session_data_points = [
88
- Mac.addr.to_alphanumeric,
89
- Process.ppid.to_s,
90
- Socket.gethostname,
91
- ENV[ Mapper::Collateral::ENV_OPS_KEY_NAME ].strip,
92
- OpenSession::Home.instance.username,
93
- @domain_name
94
- ].join
95
-
96
- return OpenKey::Digester.mash( session_data_points, SESSION_ID_SIZE )
97
-
98
- end
99
-
100
-
101
- # Get the session key that is used for symmetric encryption and decryption
102
- # of secret material pertinent to the opensecret use case.
103
- #
104
- # This depends on the {Command.session_key_password} for engineering the
105
- # password using information specific to the workstation and the parent
106
- # (bash) shell being used to execute opensecret.
107
- #
108
- # <b>Substituting Equals Back In</b>
109
- #
110
- # An environment variable holds the key's value and the <b>equals sign</b>
111
- # is not allowed within environment variables (in some operating systems)
112
- # mainly due to the fact that it is used as the key/value separator.
113
- #
114
- # The url safe base64 coding may produce one, two or three equal signs in
115
- # a bid to pad the string into a multiple of 4 length.
116
- #
117
- # In this case, we replaced equals signs with @ symbols when encoding so
118
- # we must reciprocate this action when decoding here.
119
- #
120
- # @return [String]
121
- # Return the original key generated by the {OpenSecret::Key} usecase.
122
- #
123
- # @raise [RuntimeError]
124
- # if either the ENV["OPS_KEY"] environment variable is not present or an
125
- # exception is thrown during decryption. An error is also thrown if the
126
- # environment variable or the key to be returned have a length less than
127
- # 40 characters.
128
- def get_session_key
129
-
130
- key_ciphertext = mandatory_environment_variable Mapper::Collateral::ENV_OPS_KEY_NAME, 40
131
- decoded_crypt = Base64.urlsafe_decode64( key_ciphertext.gsub("@","=") )
132
- return ToolBelt::Blowfish.decryptor( decoded_crypt, session_key_password )
133
-
134
- end
135
-
136
-
137
- # @todo
138
- # this method should be within the env var services class.
139
- #
140
- # Return the contents of the environment variable key specified
141
- # in the first parameter. The returned value is striped of both
142
- # leading and trailing whitespace before it is returned.
143
- #
144
- # @param env_var_name [String]
145
- # the (uppercase) name of the environment variable to collect
146
- #
147
- # @param min_size [Number]
148
- # the minimum number of characters the environment variable's
149
- # value is allowed to contain.
150
- #
151
- # @return [String]
152
- # Return the <b>stripped</b> environment variable value whose
153
- # name matches the one specified by the first parameter.
154
- #
155
- # @raise [RuntimeError]
156
- # if either the environment variable is not present or the length
157
- # of the string value is less than the number of charactes
158
- # specified in the second parameterr.
159
- def mandatory_environment_variable env_var_name, min_size
160
-
161
- raw_env_var_value = ENV[env_var_name]
162
- raise_error( env_var_name, "not present") unless raw_env_var_value
163
-
164
- env_var_value = raw_env_var_value.strip
165
- raise_error( env_var_name, "consists only of whitespace") if raw_env_var_value.empty?
166
-
167
- size_msg = "length should be at [least] #{min_size} characters"
168
- raise_error( env_var_name, size_msg ) unless env_var_value.length >= min_size
169
-
170
- return env_var_value
171
-
172
- end
173
-
174
-
175
- # Instantiate the collateral object which is the single
176
- # source of knowledge for any client wishing to know the
177
- # path to a particular resource (collateral) file or
178
- # directory on the accessible file system.
179
- #
180
- # This method simply enables, for all (child) use cases,
181
- # the @collateral instance variable.
182
- def instantiate_collateral
183
-
184
- @collateral = Mapper::Collateral.instance
185
-
186
- the_domain_name = Mapper::Settings.grab @c[:global][:domain_now_id]
187
- the_frontend_path = Mapper::Settings.read( the_domain_name, @c[:global][:front_path_id] )
188
- @collateral.domain_name = the_domain_name
189
- @collateral.frontend_path = the_frontend_path
190
-
191
- end
192
-
193
-
194
- # Unlock the {OpenSSL::PKey::RSA} private key and return the cipher object
195
- # usable for asymmetric encryption, decryption, signing and signature
196
- # verification use cases.
197
- #
198
- # The returned private key can be used to generate its twin public key
199
- # and should be used to verify the same public key as (if) and when the
200
- # need arises.
201
- #
202
- # @param locked_private_key [String]
203
- # the locked up private key ciphertext
204
- #
205
- # @param unlock_key [String]
206
- # the symmetric encryption key that can be used to unlock the private
207
- # key ciphertext in the first parameter.
208
- #
209
- # @return [OpenSSL::PKey::RSA]
210
- # return the {OpenSSL::PKey::RSA} private key that will be
211
- # usable for asymmetric encryption, decryption, signing and signature
212
- # verification.
213
- def unlock_private_key locked_private_key, unlock_key
214
- return OpenSSL::PKey::RSA.new locked_private_key, unlock_key
215
- end
216
-
217
-
218
- # Return the {OpenSSL::PKey::RSA} private key which is a cipher object
219
- # usable for asymmetric encryption, decryption, signing and signature
220
- # verification use cases.
221
- #
222
- # The returned private key can be used to generate its twin public key
223
- # and should be used to verify the same public key as (if) and when the
224
- # need arises.
225
- #
226
- # @param private_key_text [String]
227
- # the private key plain text
228
- #
229
- # @return [OpenSSL::PKey::RSA]
230
- # return the {OpenSSL::PKey::RSA} private key that will be
231
- # usable for asymmetric encryption, decryption, signing and signature
232
- # verification.
233
- def to_private_key private_key_text
234
- return OpenSSL::PKey::RSA.new private_key_text
235
- end
236
-
237
-
238
- # Execute the use cases's flow from beginning when
239
- # you validate the input and parameters through the
240
- # memorize, execute and the final cleanup.
241
- def flow_of_events
242
-
243
- check_pre_conditions
244
- pre_memorize
245
- execute
246
- post_memorize
247
- cleanup
248
- check_post_conditions
249
-
250
- end
251
-
252
-
253
- # Validate the input parameters and check that the current
254
- # state is perfect for executing the use case.
255
- #
256
- # If either of the above fail - the validation function should
257
- # set a human readable string and then throw an exception.
258
- def check_pre_conditions
259
-
260
-
261
- begin
262
-
263
- pre_validation
264
-
265
- rescue OpenError::CliError => e
266
-
267
- puts ""
268
- puts "Your command did not complete successfully."
269
- puts "Pre validation checks failed."
270
- puts ""
271
- puts " => #{e.message}"
272
- puts ""
273
- abort e.message
274
- end
275
-
276
-
277
- end
278
-
279
-
280
- # After the main flow of events certain state conditions
281
- # must hold true thus demonstrating that the observable
282
- # value has indeed ben delivered.
283
- #
284
- # Child classes should subclass this method and place any
285
- # post execution (post condition) checks in it and then
286
- # make a call to this method through the "super" keyword.
287
- def check_post_conditions
288
-
289
- begin
290
-
291
- post_validation
292
-
293
- rescue OpenError::CliError => e
294
-
295
- puts ""
296
- puts "Your command did not complete successfully."
297
- puts "Post validation checks failed."
298
- puts ""
299
- puts " => #{e.message}"
300
- #### puts " => #{e.culprit}"
301
- puts ""
302
- abort e.message
303
- end
304
-
305
- end
306
-
307
-
308
- # Child classes should subclass this method and place any
309
- # post execution (post condition) checks in it and then
310
- # make a call to this method through the "super" keyword if
311
- # this method gets any global behaviour in it worth calling.
312
- def post_validation
313
-
314
- end
315
-
316
-
317
-
318
- # (Pre) memorize adds to permanent storage a configuration
319
- # directive and its value <tt>provided by the user</tt>
320
- # primarily because it avoids repitition in subsequent
321
- # use case commands.
322
- def pre_memorize
323
-
324
- end
325
-
326
-
327
-
328
- # Execute the main flow of events of the use case. Any
329
- # exceptions thrown are captured and if the instance
330
- # variale [@human_readable_message] is set - tell the
331
- # user about it. Without any message - just tell the
332
- # user something went wrong and tell them where the logs
333
- # are that might carry more information.
334
- def execute
335
-
336
- end
337
-
338
-
339
-
340
- # (Post) memorize will add to permanent storage) any
341
- # key/values that have been derived or looked up during
342
- # use case execution. This allows subsequent use case
343
- # commands to
344
- #
345
- # - capitalize on
346
- # - take direction from
347
- # - and/or simply use
348
- #
349
- # the value in later use cases or processing.
350
- def post_memorize
351
-
352
- end
353
-
354
-
355
-
356
- # If the use case validation went well, the memorization
357
- # went well the
358
- def cleanup
359
-
360
- end
361
-
362
-
363
-
364
- # Resolve +two attached fact files+ with the first being general and
365
- # relevant to every use case in the parameter specified domain, and
366
- # the second being specific to this use case.
367
- #
368
- # The <b><em>general factfile</em></b> is expected to be on the class (load) path
369
- # and below are paths for a generic domain name and for an example domain
370
- # name of *openpost.io*
371
- #
372
- # - <tt>factbase/facts.<<domain>>.ini</tt>
373
- # - <tt>factbase/facts.openpost.io.ini</tt>
374
- #
375
- # The <b><em>use case specific factfile</em></b> is also _expected_ to be on the class
376
- # (load) path and below is a generic and a use case specific path using
377
- # the example <tt>deliver</tt> use case.
378
- #
379
- # - <tt>factbase/facts.<<uc-name>>.usecase.ini</tt>
380
- # - <tt>factbase/facts.deliver.usecase.ini</tt>
381
- #
382
- # The domain name is delivered in the parameter whilst the use case
383
- # name is derived from the (extension) class name.
384
- #
385
- # @param fact_domain [String] domain of the general attached factfile
386
- # @return [Hash] a 2d (two-dimensional) hash of keys and their corresponding values
387
- def attached_facts fact_domain
388
-
389
- end
390
-
391
-
392
- # This use case is initialized primary by resolving the configured
393
- # +general and use case specific facts+. To access the general facts,
394
- # a domain name is expected in the parameter delegated by the extension
395
- # use case classes.
396
- def initialize
397
-
398
-
399
- class_name = self.class.name.downcase.split(":").last
400
- is_pre_init_usecase = [ "safe", "store", "email" ].include? class_name
401
- return if is_pre_init_usecase
402
-
403
- @ucid_str = self.class.name.do_flatten
404
- log.info(x) { "Usecase class [self.class.name] converted to => #{@ucid_str}" }
405
- @ucid_sym = @ucid_str.gsub(".", "_").to_sym
406
-
407
- OpenSession::FactFind.instance.instantiate @ucid_str
408
- OpenSession::FactFind.instance.assimilate "facts.opensecret.io.ini"
409
-
410
- @c = OpenSession::FactFind.instance.f
411
- @i = OpenSession::FactFind.instance.i
412
- @p = OpenSession::FactFind.instance.f[@ucid_sym]
413
-
414
- log.info(x) { "assimilated [#{@p.length}] facts specific to the [#{@ucid_str}] use case." }
415
-
416
- end
417
-
418
-
419
- private
420
-
421
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
422
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
423
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
424
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
425
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
426
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
427
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
428
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
429
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
430
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
431
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
432
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
433
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
434
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
435
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
436
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
437
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
438
- ## Important Refactor is to move Session behaviour to an OpenKey Session class.
439
-
440
-
441
-
442
- OUTER_PATH = "outer.path"
443
- INNER_PATH = "inner.path"
444
-
445
- LAST_ACCESSED = "last.accessed.time"
446
-
447
- SESSION_DICT_LOCK_SIZE = 32
448
-
449
- SESSION_DICT_LOCK_NAME = "crypted.session.dict.lock"
450
-
451
- ENVELOPE_KEY_SIZE = 32
452
-
453
- ENVELOPE_KEY_NAME = "crypted.envelope.key"
454
-
455
- ENVELOPE_ID_SIZE = 16
456
-
457
- ENVELOPE_ID_NAME = "crypted.envelope.id"
458
-
459
- SESSION_ID_SIZE = 64
460
-
461
- SESSION_FILENAME_ID_SIZE = 24
462
-
463
- SESSION_START_TIMESTAMP_NAME = "session.creation.time"
464
-
465
- MASTER_LOCK_KEY_NAME = "master.session.lock.key"
466
-
467
- def raise_error env_var_name, message
468
-
469
- puts ""
470
- puts "#{env_var_name} environment variable #{message}."
471
- puts "To instantiate it you can use the below command."
472
- puts ""
473
- puts "$ export OPS_KEY=`ops key`"
474
- puts ""
475
- puts "ps => those are backticks around `ops key` (not apostrophes)."
476
- puts ""
477
-
478
- raise RuntimeError, "#{env_var_name} environment variable #{message}."
479
-
480
- end
481
-
482
-
483
-
484
- def ops_key_exists?
485
-
486
- if ( ENV.has_key? Mapper::Collateral::ENV_OPS_KEY_NAME )
487
- return true
488
- end
489
-
490
- puts ""
491
- puts "opensecret needs you to create a session key."
492
- puts "To automate this step see the documentation."
493
- puts "To create the key run the below command."
494
- puts ""
495
- puts " export OPS_KEY=`ops key`"
496
- puts ""
497
- puts "Those are backticks surrounding `ops key`"
498
- puts "Not apostrophes."
499
- puts ""
500
-
501
- return false
502
-
503
- end
504
-
505
-
506
- def private_key_exists?
507
-
508
- if @collateral.private_key_exists?
509
- return true
510
- end
511
-
512
- puts ""
513
- puts "Domain [ #{@domain_name} ] has not been initialized."
514
- puts "Have you run the ops init command?"
515
- puts ""
516
- puts " ops init #{@domain_name} $HOME/ops.#{@domain_name}"
517
- puts ""
518
-
519
- return false
520
-
521
- end
522
-
523
-
524
- def get_session_dictionary
525
-
526
- session_index_filepath = @collateral.session_index_file( session_id[0 .. (SESSION_FILENAME_ID_SIZE-1)] )
527
-
528
- unless File.file? session_index_filepath
529
- return OpenKey::Dictionary.create_with_section( session_index_filepath, create_envelope_id )
530
- end
531
-
532
- return OpenKey::Dictionary.create_with_section( session_index_filepath, read_envelope_id, read_session_dict_lock )
533
-
534
- end
535
-
536
-
537
- def create_session_dict_lock
538
- session_dict_lock = OpenSecret::ToolBelt::Engineer.strong_key SESSION_DICT_LOCK_SIZE
539
- session_dict_lock_crypt = session_dict_lock.encrypt_url_encode( get_session_key )
540
- Mapper::Settings.write session_id, SESSION_DICT_LOCK_NAME, session_dict_lock_crypt
541
- return session_dict_lock
542
- end
543
-
544
-
545
- def read_session_dict_lock
546
- session_dict_lock_crypt = Mapper::Settings.read session_id, SESSION_DICT_LOCK_NAME
547
- return session_dict_lock_crypt.url_decode_decrypt( get_session_key )
548
- end
549
-
550
-
551
- def create_envelope_key
552
- envelope_key = OpenSecret::ToolBelt::Engineer.strong_key ENVELOPE_KEY_SIZE
553
- envelope_key_crypt = envelope_key.encrypt_url_encode( get_session_key )
554
- Mapper::Settings.write session_id, ENVELOPE_KEY_NAME, envelope_key_crypt
555
- return envelope_key
556
- end
557
-
558
-
559
- def read_envelope_key
560
- envelope_key_crypt = Mapper::Settings.read session_id, ENVELOPE_KEY_NAME
561
- return envelope_key_crypt.url_decode_decrypt( get_session_key )
562
- end
563
-
564
-
565
- def create_envelope_id
566
- envelope_id = OpenSecret::ToolBelt::Engineer.strong_key ENVELOPE_ID_SIZE
567
- envelope_id_crypt = envelope_id.encrypt_url_encode( get_session_key )
568
- Mapper::Settings.write session_id, ENVELOPE_ID_NAME, envelope_id_crypt
569
- return envelope_id
570
- end
571
-
572
-
573
- def read_envelope_id
574
- envelope_id_crypt = Mapper::Settings.read session_id, ENVELOPE_ID_NAME
575
- return envelope_id_crypt.url_decode_decrypt( get_session_key )
576
- end
577
-
578
-
579
- #### [cGWy7vU4WwxcTQ5X710kVQGWD5EujUco0WiaxyLrMFzXMdNhCAYAba3DXENKVz94]
580
- #### master.session.lock.key = FY27lfm96o6KlIXHS3u8tsmh9oBJiS5IU-oUkn4CLCkVAsOx_E2Wkzm2-d3ZIHfhG35ik1ENjhHcBJO4JebYQ-TR-t7xI8AVKC8jS3Y40qUbeCjFHjGDbpJI0RNYEWdyr4iSMygI6FbH-iCg9V4awA==
581
- #### session.creation.time = 18092.2238.43.302186561
582
- #### crypted.envelope.id = iPamzaAD17vmOH72DLikbwadIMc5HW8IBS88mxUseks8il74JEXuLpJI0RNYEWdyr4iSMygI6FbH-iCg9V4awA==
583
- #### crypted.session.dict.lock = iSbFR3ZFGWzkFEXHMByugL_09FJL3wVRnmgjxqsvd5ds8zpfeQT-7ERiAAst49gQr4iSMygI6FbH-iCg9V4awA==
584
-
585
- def create_crypt_store_locking_key
586
-
587
- config_keystore = Mapper::KeyStore.new( @collateral.domain_config_file, @domain_name )
588
- digester = OpenKey::Digester.new( config_keystore.time_stamp )
589
-
590
- locking_key = digester.generate @master_p4ss
591
- config_keystore.set_init_vector( digester.encrypted_iv )
592
-
593
- session_key_crypt = Base64.urlsafe_encode64( ToolBelt::Blowfish.encryptor( locking_key, get_session_key ) )
594
-
595
- Mapper::Settings.write session_id, MASTER_LOCK_KEY_NAME, session_key_crypt
596
- Mapper::Settings.write session_id, SESSION_START_TIMESTAMP_NAME, OpenSession::Stamp.yyjjj_hhmm_ss_nanosec
597
-
598
- return locking_key
599
-
600
- end
601
-
602
-
603
- def print_success_initializing
604
-
605
- puts ""
606
- puts "Success - now open a secret envelope, put, then seal."
607
- puts ""
608
- puts " ops open aws.credentials:s3reader"
609
- puts " ops put access_key ABCD1234"
610
- puts " ops put secret_key FGHIJ56789"
611
- puts " ops put region_key eu-central-1"
612
- puts " ops seal"
613
- puts ""
614
-
615
- end
616
-
617
-
618
- end
619
-
620
-
621
- end