opensecret 0.0.951 → 0.0.957

Sign up to get free protection for your applications and to get access to all the features.
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