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.
- 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
|