opensecret 0.0.951 → 0.0.957
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/extension/array.rb +29 -0
- data/lib/extension/string.rb +31 -0
- data/lib/factbase/facts.opensecret.io.ini +17 -9
- data/lib/notepad/blow.rb +108 -5
- data/lib/opensecret.rb +32 -6
- data/lib/plugins/cipher.rb +7 -7
- data/lib/plugins/ciphers/blowfish.rb +63 -157
- data/lib/plugins/usecase.rb +1 -1
- data/lib/plugins/usecases/init.rb +57 -116
- data/lib/plugins/usecases/lock.rb +178 -0
- data/lib/plugins/usecases/open.rb +17 -86
- data/lib/plugins/usecases/put.rb +137 -0
- data/lib/plugins/usecases/safe.rb +8 -10
- data/lib/session/attributes.rb +16 -11
- data/lib/session/dictionary.rb +191 -0
- data/lib/session/session.rb +80 -0
- data/lib/session/time.stamp.rb +89 -106
- data/lib/using.txt +100 -0
- data/lib/version.rb +1 -1
- metadata +6 -15
- data/lib/opensecret/commons/eco.faculty.rb +0 -364
- data/lib/opensecret/commons/eco.system.rb +0 -437
- data/lib/opensecret/commons/eco.systems.rb +0 -98
- data/lib/opensecret/factbase/hub-runtime.ini +0 -123
- data/lib/opensecret/factbase/known-hosts.ini +0 -75
- data/lib/opensecret/factbase/published.facts/blobbolicious-facts.ini +0 -553
- data/lib/opensecret/factbase/published.facts/credential-facts.ini +0 -40
- data/lib/opensecret/factbase/published.facts/infrastructure-facts.ini +0 -63
- data/lib/opensecret/factbase/readme.md +0 -24
- data/lib/opensecret/factbase/retired.facts/maven.database.ide.facts.ini +0 -127
- data/lib/opensecret/factbase/retired.facts/s3-upload-block-facts.ini +0 -17
- data/lib/opensecret/plugins.io/file/file.rb +0 -483
- 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."
|
data/lib/session/attributes.rb
CHANGED
@@ -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
|
-
|
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[
|
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[
|
182
|
-
raise ArgumentError.new "Key [#{key_name}] not
|
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[
|
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
|