opensecret 0.0.951 → 0.0.957

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/extension/array.rb +29 -0
  3. data/lib/extension/string.rb +31 -0
  4. data/lib/factbase/facts.opensecret.io.ini +17 -9
  5. data/lib/notepad/blow.rb +108 -5
  6. data/lib/opensecret.rb +32 -6
  7. data/lib/plugins/cipher.rb +7 -7
  8. data/lib/plugins/ciphers/blowfish.rb +63 -157
  9. data/lib/plugins/usecase.rb +1 -1
  10. data/lib/plugins/usecases/init.rb +57 -116
  11. data/lib/plugins/usecases/lock.rb +178 -0
  12. data/lib/plugins/usecases/open.rb +17 -86
  13. data/lib/plugins/usecases/put.rb +137 -0
  14. data/lib/plugins/usecases/safe.rb +8 -10
  15. data/lib/session/attributes.rb +16 -11
  16. data/lib/session/dictionary.rb +191 -0
  17. data/lib/session/session.rb +80 -0
  18. data/lib/session/time.stamp.rb +89 -106
  19. data/lib/using.txt +100 -0
  20. data/lib/version.rb +1 -1
  21. metadata +6 -15
  22. data/lib/opensecret/commons/eco.faculty.rb +0 -364
  23. data/lib/opensecret/commons/eco.system.rb +0 -437
  24. data/lib/opensecret/commons/eco.systems.rb +0 -98
  25. data/lib/opensecret/factbase/hub-runtime.ini +0 -123
  26. data/lib/opensecret/factbase/known-hosts.ini +0 -75
  27. data/lib/opensecret/factbase/published.facts/blobbolicious-facts.ini +0 -553
  28. data/lib/opensecret/factbase/published.facts/credential-facts.ini +0 -40
  29. data/lib/opensecret/factbase/published.facts/infrastructure-facts.ini +0 -63
  30. data/lib/opensecret/factbase/readme.md +0 -24
  31. data/lib/opensecret/factbase/retired.facts/maven.database.ide.facts.ini +0 -127
  32. data/lib/opensecret/factbase/retired.facts/s3-upload-block-facts.ini +0 -17
  33. data/lib/opensecret/plugins.io/file/file.rb +0 -483
  34. data/lib/plugins/usecases/on.rb +0 -33
@@ -0,0 +1,137 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module OpenSecret
4
+
5
+ require 'openssl'
6
+
7
+ # The <b>put use case</b> follows <b>open</b> and it adds secrets into an
8
+ # <em>(encrypted at rest)</em> opened file. Put can be called many times to
9
+ # add secrets. Finally the <b>lock use case</b> commits all opened secrets
10
+ # into the configured storage engines.
11
+ #
12
+ # Calling <em>put</em> <b>before</b> calling open or <b>after</b> calling lock
13
+ # is not allowed and will result in an error.
14
+ #
15
+ # == Put Pre-Conditions
16
+ #
17
+ # When the put use case is called - the below conditions ring true.
18
+ #
19
+ # - the <b>folder path</b> ending in ../../my must exist
20
+ # - a session id, filename and encryption key ( in workstation config )
21
+ #
22
+ # == Observable Value
23
+ #
24
+ # The observable value delivered by +put+ boils down to
25
+ #
26
+ # - a new <b>friends.xyz123abc.os.txt</b> file if this is the first put.
27
+ # - a new group_name/key_name (like monica/surname) entry is added if required
28
+ # - a secret value is added against the key or updated if it already exists
29
+ # - a new session id and encryption key is generated and used to re-encrypt
30
+ #
31
+ # == The Encrypted Session Bucket
32
+ #
33
+ # After the example commands we can visualize the <b><em>encrypted</em></b>
34
+ # bucket like this.
35
+ #
36
+ # [monica]
37
+ # surname = lewinsky
38
+ # from = April 1989
39
+ # to = September 1994
40
+ #
41
+ # [hilary]
42
+ # surname = clinton
43
+ # from = Feb 1982
44
+ # to = Present Day
45
+ #
46
+ # == Bill Clinton's Lady Friends
47
+ #
48
+ # In our fictitious example Bill Clinton uses opensecret to lock away the
49
+ # names and dates of his lady riends.
50
+ #
51
+ # @example
52
+ #
53
+ # $ opensecret email bill.clinton@example.com
54
+ # $ opensecret init
55
+ # $ opensecret open my/friends
56
+ #
57
+ # $ opensecret put monica/surname lewinsky
58
+ # $ opensecret put monica/from "April 1989"
59
+ # $ opensecret put monica/to "September 1994"
60
+ #
61
+ # $ opensecret put hilary/surname clinton
62
+ # $ opensecret put hilary/from "January 1988"
63
+ # $ opensecret put hilary/to "Present Day"
64
+ #
65
+ # $ opensecret lock
66
+ #
67
+ class Put < OpenSession::UseCase
68
+
69
+ attr_writer :secret_id, :secret_value
70
+ @@context_name = "opensecret"
71
+
72
+ # The <b>put use case</b> follows <b>open</b> and it adds secrets into an
73
+ # <em>(encrypted at rest)</em> opened file. Put can be called many times to
74
+ # add secrets. Finally the <b>lock use case</b> commits all opened secrets
75
+ # into the configured storage engines.
76
+ #
77
+ # Calling <em>put</em> <b>before</b> calling open or <b>after</b> calling lock
78
+ # is not allowed and will result in an error.
79
+ #
80
+ # == Put Pre-Conditions
81
+ #
82
+ # When the put use case is called - the below conditions ring true.
83
+ #
84
+ # - the <b>folder path</b> ending in ../../my must exist
85
+ # - a session id, filename and encryption key ( in workstation config )
86
+ #
87
+ # == Observable Value
88
+ #
89
+ # The observable value delivered by +put+ boils down to
90
+ #
91
+ # - a new <b>friends.xyz123abc.os.txt</b> file if this is the first put.
92
+ # - a new group_name/key_name (like monica/surname) entry is added if required
93
+ # - a secret value is added against the key or updated if it already exists
94
+ # - a new session id and encryption key is generated and used to re-encrypt
95
+ def execute
96
+
97
+ session_id = OpenSession::Attributes.instance.get_value @@context_name, @c[:open][:open_name], @c[:open][:open_idname]
98
+ encrypt_key = OpenSession::Attributes.instance.get_value @@context_name, @c[:open][:open_name], @c[:open][:open_keyname]
99
+ rel_filepath = OpenSession::Attributes.instance.get_value @@context_name, @c[:open][:open_name], @c[:open][:open_pathname]
100
+
101
+ put_filepath = File.join @c[:open][:open_dirpath], rel_filepath
102
+
103
+ x_dictionary = OpenSession::Dictionary.new
104
+ x_dictionary.read put_filepath, true, encrypt_key
105
+
106
+ secret_ids = @secret_id.split("/")
107
+ if ( x_dictionary.has_key? secret_ids.first )
108
+ x_dictionary[secret_ids.first][secret_ids.last] = @secret_value
109
+ else
110
+ x_dictionary[secret_ids.first] = { secret_ids.last => @secret_value }
111
+ end
112
+
113
+ new_encryption_key = Engineer.strong_key @c[:open][:open_keylen]
114
+ OpenSession::Attributes.stash @@context_name, @c[:open][:open_name], @c[:open][:open_keyname], new_encryption_key
115
+ x_dictionary.write new_encryption_key
116
+
117
+ end
118
+
119
+
120
+ # Perform pre-conditional validations in preparation to executing the main flow
121
+ # of events for this use case. This method may throw the below exceptions.
122
+ #
123
+ # @raise [SafeDirNotConfigured] if the safe's url has not been configured
124
+ # @raise [EmailAddrNotConfigured] if the email address has not been configured
125
+ # @raise [StoreUrlNotConfigured] if the crypt store url is not configured
126
+ def pre_validation
127
+
128
+
129
+ end
130
+
131
+
132
+ end
133
+
134
+
135
+ end
136
+
137
+
@@ -2,23 +2,17 @@
2
2
 
3
3
  module OpenSecret
4
4
 
5
- ##### require "usecase/usecase"
6
- ##### require "session/attributes"
7
-
8
5
  # This is the [On] usecase that is triggered when a user would like
9
6
  # to start a locking (encryption) session.
10
7
  #
11
8
  # Pre-Conditions
12
9
  #
13
10
  # - [session.config.file] exists with domain,user,email,store_id => store_url
14
- # -
15
- # -
16
- #
17
11
  #
18
12
  # Main Flow of Events
19
13
  #
20
- # -
21
- # -
14
+ # Stash the path into the host machine's configuration file and proceed
15
+ # to create the path directory chain if it does not already exist.
22
16
  #
23
17
  class Safe < OpenSession::UseCase
24
18
 
@@ -26,9 +20,13 @@ module OpenSecret
26
20
  @@context_name = "opensecret"
27
21
  @@prime_name = "opensecret.safe"
28
22
 
23
+ # The safe use case simply validates the presented path and when the
24
+ # execute method is called it stashes the path within the host machine's
25
+ # configuration file and proceeds to create the path directory chain
26
+ # if it does not already exist.
29
27
  def execute
30
28
 
31
- OpenSession::Attributes.stash @@context_name, "safe", @safe_path
29
+ OpenSession::Attributes.stash @@context_name, @@context_name, "safe", @safe_path
32
30
  FileUtils.mkdir_p @safe_path unless File.exists? @safe_path
33
31
 
34
32
  end
@@ -76,7 +74,7 @@ module OpenSecret
76
74
  # configurations right down to missing keys or even missing values.
77
75
  def post_validation
78
76
 
79
- configured_path = OpenSession::Attributes.instance.get_value @@context_name, "safe"
77
+ configured_path = OpenSession::Attributes.instance.get_value @@context_name, @@context_name, "safe"
80
78
  path_string_1 = " path 1 => #{configured_path}"
81
79
  path_string_2 = " path 2 => #{@safe_path}"
82
80
  mismatch_path = "Path mismatch to opensecret [safe] detected."
@@ -85,14 +85,18 @@ module OpenSession
85
85
  # Stash the attribute within the session's configuration file and
86
86
  # print out the current state of the configuration.
87
87
  #
88
+ # @param context_name [String] the context will define the folder and filepath
88
89
  # @param section_name [String] name grouping the section of config values
89
90
  # @param key_name [String] the name of the key whose value is to be written
90
91
  # @param key_value [String] the data item value of the key specified
91
- def self.stash section_name, key_name, key_value
92
+ def self.stash context_name, section_name, key_name, key_value
92
93
 
93
94
  the_session = OpenSession::Attributes.instance
94
- the_session.write_keyvalue section_name, key_name, key_value
95
- puts "\n" + File.read(the_session.get_filepath(section_name)) + "\n"
95
+ the_session.write_keyvalue context_name, section_name, key_name, key_value
96
+
97
+ puts ""
98
+ puts File.read(the_session.get_filepath(context_name))
99
+ puts ""
96
100
 
97
101
  end
98
102
 
@@ -138,10 +142,11 @@ module OpenSession
138
142
  # width = 3m
139
143
  #
140
144
  # @param context_name [String] name of program writing a session attribute
145
+ # @param section_name [String] name grouping the section of config values
141
146
  # @param key [String] the key name of config directive to be written into the file
142
147
  # @param value [String] value of the config directive to be written into the file
143
148
  #
144
- def write_keyvalue context_name, key, value
149
+ def write_keyvalue context_name, section_name, key, value
145
150
 
146
151
  config_file_dir = get_filedir(context_name)
147
152
  FileUtils.mkdir_p config_file_dir unless File.exists? config_file_dir
@@ -150,7 +155,7 @@ module OpenSession
150
155
  config_map = IniFile.new( :filename => config_filepath, :encoding => 'UTF-8' )
151
156
  config_map = IniFile.load( config_filepath ) if File.exists? config_filepath
152
157
 
153
- config_map[context_name][key] = value
158
+ config_map[section_name][key] = value
154
159
  config_map.write
155
160
 
156
161
  end
@@ -169,7 +174,7 @@ module OpenSession
169
174
  # cause the key value to not be retrieved. This can range from
170
175
  # non-existent directories and files, non readable files, incorrect
171
176
  # configurations right down to missing keys or even missing values.
172
- def get_value context_name, key_name
177
+ def get_value context_name, section_name, key_name
173
178
 
174
179
  the_file = get_filepath context_name
175
180
  raise ArgumentError.new "No configuration file found => [ #{the_file} ]" unless File.exists? the_file
@@ -178,14 +183,14 @@ module OpenSession
178
183
  raise ArgumentError.new "Configuration file is empty => [ #{the_file} ]" if the_text.empty?
179
184
 
180
185
  the_data = IniFile.load the_file
181
- key_exists = the_data[ context_name ].has_key?( key_name )
182
- raise ArgumentError.new "Key [#{key_name}] not configured => #{the_data.to_s}" unless key_exists
186
+ key_exists = the_data[ section_name ].has_key?( key_name )
187
+ raise ArgumentError.new "Key [#{key_name}] not found in section [#{section_name}] => #{the_data.to_s}" unless key_exists
183
188
 
184
- rawvalue = the_data[context_name][key_name]
185
- raise ArgumentError.new "Empty value 4 key [#{key_name}] => #{the_data.to_s}" if rawvalue.empty?
189
+ rawvalue = the_data[section_name][key_name]
190
+ raise ArgumentError.new "Empty value 4 key [#{section_name}][#{key_name}] => #{the_data.to_s}" if rawvalue.empty?
186
191
 
187
192
  keyvalue = rawvalue.chomp.strip
188
- raise ArgumentError.new "Whitespace value 4 key [#{key_name}] => #{the_data.to_s}" if keyvalue.empty?
193
+ raise ArgumentError.new "Whitespace value 4 key [#{section_name}][#{key_name}] => #{the_data.to_s}" if keyvalue.empty?
189
194
 
190
195
  return keyvalue
191
196
 
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/ruby
2
+ # coding: utf-8
3
+
4
+ module OpenSession
5
+
6
+ require 'inifile'
7
+
8
+
9
+ # An OpenSession dictionary is a +2D (two dimensional) hash+ data
10
+ # structure backed by a file that can optionally be +encrypted+.
11
+ #
12
+ # It supports operations to +read from+ and +write to+ a known filepath
13
+ # and can optionally be given a crypt key so that it can
14
+ #
15
+ # - decrypt +after reading from+ a file
16
+ # - encrypt +before writing to+ a file
17
+ #
18
+ # Dictionary extends {Hash} in order to deliver on its core key value
19
+ # store, report and retrieve use cases.
20
+ #
21
+ # @example
22
+ # This dictionary implementation is backed by an INI file
23
+ # that could initially look like this.
24
+ #
25
+ # [openbox]
26
+ # length = 2m
27
+ #
28
+ # Then we add a section called closedbox with two key value pairs.
29
+ # And we add width key with a value of 3m to the openbox section.
30
+ # The result will look like this.
31
+ #
32
+ # [closedbox]
33
+ # shape = cuboid
34
+ # color = blue
35
+ #
36
+ # [openbox]
37
+ # length = 2m
38
+ # width = 3m
39
+ #
40
+ class Dictionary < Hash
41
+
42
+
43
+ # Write the data in this dictionary hash map into a file-system
44
+ # backed mirror whose path was specified in the {self.read} method.
45
+ #
46
+ # Technology for encryption at rest is supported by this dictionary
47
+ # and a non-nil encryption key parameter is expected if this dictionary
48
+ # has been configured to encrypt data at rest.
49
+ #
50
+ # An argument error will result if a suitable key is not provided
51
+ # when encryption at rest is desired.
52
+ #
53
+ # Calling this {self.write} method when the file at the prescribed path
54
+ # does not exist results in the directory structure being created
55
+ # (if necessary) and then the (possibly encrypted) file being written.
56
+ #
57
+ # @param encrypt_key [String]
58
+ # if encryption at rest is required this parameter must contain a
59
+ # robust symmetric decryption key. The symmetric key will be used
60
+ # for the decryption after the read. Note that the decryption key
61
+ # does not linger meaning it isn't cached in an instance variable.
62
+ #
63
+ # @raise [ArgumentError] if +encryption at rest+ is prescribed for the
64
+ # dictionary but no encryption key is provided. The +converse+
65
+ # assertion will also be made.
66
+ def write encrypt_key = nil
67
+
68
+ file_exists = File.exists? @filepath
69
+ folder_path = File.dirname(@filepath) unless file_exists
70
+ FileUtils.mkdir_p folder_path unless file_exists
71
+
72
+ crypt_assertion encrypt_key
73
+ ini_file = IniFile.new
74
+
75
+ self.each_key do |section_name|
76
+ ini_file[section_name] = self[section_name]
77
+ end
78
+
79
+ ini_string = ini_file.to_s
80
+
81
+ puts ""
82
+ puts "============================"
83
+ puts "Before Encryption Dictionary"
84
+ puts "============================"
85
+ puts ini_string
86
+ puts "============================"
87
+ puts ""
88
+
89
+ ini_string = OpenSecret::Blowfish.new.encryptor(ini_string,encrypt_key) if @encrypt_at_rest
90
+
91
+ File.write @filepath, ini_string
92
+
93
+ end
94
+
95
+
96
+ # Read and inject into this dictionary, map data found in a fle
97
+ # at the path specified in the first parameter.
98
+ #
99
+ # Technology for encryption at rest is supported by this dictionary
100
+ # and the second parameter being TRUE denotes that we are required
101
+ # to encrypt before writing and decrypt after reading.
102
+ #
103
+ # An argument error will result if a suitable key is not provided
104
+ # when encryption at rest is desired.
105
+ #
106
+ # If the file does not exist (boundary condition) - this read method
107
+ # remembers the file path as well as remembering the need for encryption
108
+ # at rest.
109
+ #
110
+ # @param the_filepath [String] absolute path to the file mirroring this dictionary
111
+ # @param is_encrypted_at_rest [Boolean] true if dictionary encryption at rest is desired
112
+ # @param decrypt_key [String]
113
+ # if encryption at rest is required this parameter must contain a
114
+ # robust symmetric decryption key. The symmetric key will be used
115
+ # for the decryption after the read. Note that the decryption key
116
+ # does not linger meaning it isn't cached in an instance variable.
117
+ #
118
+ # @raise [ArgumentError] if +encryption at rest+ is prescribed for the
119
+ # dictionary but no encryption key is provided and the +converse+
120
+ # is also true.
121
+ def read the_filepath, is_encrypted_at_rest, decrypt_key = nil
122
+
123
+ @filepath = the_filepath
124
+ @encrypt_at_rest = is_encrypted_at_rest
125
+ return unless File.exists? @filepath
126
+ crypt_assertion decrypt_key
127
+
128
+ file_contents = File.read( @filepath ).strip
129
+ if @encrypt_at_rest then
130
+ file_contents = OpenSecret::Blowfish.new.decryptor( file_contents, decrypt_key )
131
+ end
132
+
133
+ puts ""
134
+ puts "==========================="
135
+ puts "After Decryption Dictionary"
136
+ puts "==========================="
137
+ puts file_contents
138
+ puts "==========================="
139
+ puts ""
140
+
141
+ ingest_contents file_contents
142
+
143
+ end
144
+
145
+
146
+ private
147
+
148
+
149
+ def ingest_contents the_contents
150
+
151
+ ini_file = IniFile.new( :content => the_contents )
152
+ ini_file.each do | data_group, data_key, data_value |
153
+ ingest_entry data_group, data_key, data_value
154
+ end
155
+
156
+ end
157
+
158
+
159
+ def ingest_entry section_name, key_name, value
160
+
161
+ msg = "A NIL object detected during ingestion of file [#{@filepath}]."
162
+ raise RuntimetError.new msg if section_name.nil? || key_name.nil? || value.nil?
163
+
164
+ if self.has_key? section_name then
165
+ self[section_name][key_name] = value
166
+ else
167
+ self.store section_name, { key_name => value }
168
+ end
169
+
170
+ end
171
+
172
+
173
+ def crypt_assertion with_crypt_key
174
+
175
+ if @encrypt_at_rest
176
+ msg1 = "Encryption at rest required but no (none whitespace) encryption key provided."
177
+ raise ArgumentError, msg1 unless !with_crypt_key.nil?
178
+ return
179
+ end
180
+
181
+ msg2 = "Encryption at rest not required but an encryption key was provided."
182
+ raise ArgumentError, msg2 unless with_crypt_key.nil?
183
+ return
184
+
185
+ end
186
+
187
+
188
+ end
189
+
190
+
191
+ end