safedb 0.01.0001

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.yardopts +3 -0
  4. data/Gemfile +10 -0
  5. data/LICENSE +21 -0
  6. data/README.md +793 -0
  7. data/Rakefile +16 -0
  8. data/bin/safe +5 -0
  9. data/lib/configs/README.md +58 -0
  10. data/lib/extension/array.rb +162 -0
  11. data/lib/extension/dir.rb +35 -0
  12. data/lib/extension/file.rb +123 -0
  13. data/lib/extension/hash.rb +33 -0
  14. data/lib/extension/string.rb +572 -0
  15. data/lib/factbase/facts.safedb.net.ini +38 -0
  16. data/lib/interprete.rb +462 -0
  17. data/lib/keytools/PRODUCE_RAND_SEQ_USING_DEV_URANDOM.txt +0 -0
  18. data/lib/keytools/kdf.api.rb +243 -0
  19. data/lib/keytools/kdf.bcrypt.rb +265 -0
  20. data/lib/keytools/kdf.pbkdf2.rb +262 -0
  21. data/lib/keytools/kdf.scrypt.rb +190 -0
  22. data/lib/keytools/key.64.rb +326 -0
  23. data/lib/keytools/key.algo.rb +109 -0
  24. data/lib/keytools/key.api.rb +1391 -0
  25. data/lib/keytools/key.db.rb +330 -0
  26. data/lib/keytools/key.docs.rb +195 -0
  27. data/lib/keytools/key.error.rb +110 -0
  28. data/lib/keytools/key.id.rb +271 -0
  29. data/lib/keytools/key.ident.rb +243 -0
  30. data/lib/keytools/key.iv.rb +107 -0
  31. data/lib/keytools/key.local.rb +259 -0
  32. data/lib/keytools/key.now.rb +402 -0
  33. data/lib/keytools/key.pair.rb +259 -0
  34. data/lib/keytools/key.pass.rb +120 -0
  35. data/lib/keytools/key.rb +585 -0
  36. data/lib/logging/gem.logging.rb +132 -0
  37. data/lib/modules/README.md +43 -0
  38. data/lib/modules/cryptology/aes-256.rb +154 -0
  39. data/lib/modules/cryptology/amalgam.rb +70 -0
  40. data/lib/modules/cryptology/blowfish.rb +130 -0
  41. data/lib/modules/cryptology/cipher.rb +207 -0
  42. data/lib/modules/cryptology/collect.rb +138 -0
  43. data/lib/modules/cryptology/crypt.io.rb +225 -0
  44. data/lib/modules/cryptology/engineer.rb +99 -0
  45. data/lib/modules/mappers/dictionary.rb +288 -0
  46. data/lib/modules/storage/coldstore.rb +186 -0
  47. data/lib/modules/storage/git.store.rb +399 -0
  48. data/lib/session/fact.finder.rb +334 -0
  49. data/lib/session/require.gem.rb +112 -0
  50. data/lib/session/time.stamp.rb +340 -0
  51. data/lib/session/user.home.rb +49 -0
  52. data/lib/usecase/cmd.rb +487 -0
  53. data/lib/usecase/config/README.md +57 -0
  54. data/lib/usecase/docker/README.md +146 -0
  55. data/lib/usecase/docker/docker.rb +49 -0
  56. data/lib/usecase/edit/README.md +43 -0
  57. data/lib/usecase/edit/delete.rb +46 -0
  58. data/lib/usecase/export.rb +40 -0
  59. data/lib/usecase/files/README.md +37 -0
  60. data/lib/usecase/files/eject.rb +56 -0
  61. data/lib/usecase/files/file_me.rb +78 -0
  62. data/lib/usecase/files/read.rb +169 -0
  63. data/lib/usecase/files/write.rb +89 -0
  64. data/lib/usecase/goto.rb +57 -0
  65. data/lib/usecase/id.rb +36 -0
  66. data/lib/usecase/import.rb +157 -0
  67. data/lib/usecase/init.rb +63 -0
  68. data/lib/usecase/jenkins/README.md +146 -0
  69. data/lib/usecase/jenkins/jenkins.rb +208 -0
  70. data/lib/usecase/login.rb +71 -0
  71. data/lib/usecase/logout.rb +28 -0
  72. data/lib/usecase/open.rb +71 -0
  73. data/lib/usecase/print.rb +40 -0
  74. data/lib/usecase/put.rb +81 -0
  75. data/lib/usecase/set.rb +44 -0
  76. data/lib/usecase/show.rb +138 -0
  77. data/lib/usecase/terraform/README.md +91 -0
  78. data/lib/usecase/terraform/terraform.rb +121 -0
  79. data/lib/usecase/token.rb +35 -0
  80. data/lib/usecase/update/README.md +55 -0
  81. data/lib/usecase/update/rename.rb +180 -0
  82. data/lib/usecase/use.rb +41 -0
  83. data/lib/usecase/verse.rb +20 -0
  84. data/lib/usecase/view.rb +71 -0
  85. data/lib/usecase/vpn/README.md +150 -0
  86. data/lib/usecase/vpn/vpn.ini +31 -0
  87. data/lib/usecase/vpn/vpn.rb +54 -0
  88. data/lib/version.rb +3 -0
  89. data/safedb.gemspec +34 -0
  90. metadata +193 -0
@@ -0,0 +1,259 @@
1
+ #!/usr/bin/ruby
2
+ # coding: utf-8
3
+
4
+ module SafeDb
5
+
6
+ require 'inifile'
7
+
8
+ # KeyPair is a <b>key-value</b> store backed by a plain-text file in
9
+ # an <b>INI format</b> that sits on an accessible file-system.
10
+ #
11
+ #
12
+ # == Example Data Exchange
13
+ #
14
+ # Issue the below ruby calls and specify a /path/to/file
15
+ #
16
+ # keymap = KeyPair.new "/path/to/file"
17
+ #
18
+ # keymap.use "phone_numbers"
19
+ # keymap.set "joe", "0044 7500 123456"
20
+ # keymap.set "amy", "0044 7678 123456"
21
+ #
22
+ # Now visit the file to see your exchanged data.
23
+ #
24
+ # [phone_numbers]
25
+ # joe = 0044 7500 123456
26
+ # amy = 0044 7678 123456
27
+ #
28
+ #
29
+ # == The <em>Current</em> Section
30
+ #
31
+ # You can set the <b>current section</b> with the {use} method and then
32
+ # subsequent read, write, or query behaviour will reference the section that
33
+ # you stated.
34
+ #
35
+ # You do not need a new object to switch sections - just go ahead and
36
+ # use another another one.
37
+ #
38
+ # Remember that KeyPair is <b>two-dimensional</b> data structure so all
39
+ # key-value pairs are stored under the auspices of a section.
40
+ #
41
+ # == Key-Value Pair Exchanges
42
+ #
43
+ # Representational state transfer occurs with four methods with
44
+ #
45
+ # - custom sections referenced through {read} and {write}
46
+ # - said sections transfered via ubiquitous {get} and {set}
47
+ #
48
+ # The name given to the default group can be specified to the constructor.
49
+ # If none is provided the aptly named "default" is used.
50
+ class KeyPair
51
+
52
+ # Initialize the key value store and auto write a time stamp that
53
+ # has nano-second accuracy with a key whose name is gleened from
54
+ # the constant {KeyData::INIT_TIME_STAMP_NAME}.
55
+ #
56
+ # The path to the backing INI file is gleened from the first
57
+ # backing file path parameter.
58
+ #
59
+ # @param backing_file_path [String]
60
+ # the expected location of the file-backed key-value store.
61
+ # If the folder and/or file do not exist the folder is created
62
+ # and then the file is created along with the time stamps.
63
+ #
64
+ # @param the_default_group [String]
65
+ # the name of the default group. If none is presented this value
66
+ # will default to the aptly named "default".
67
+ def initialize backing_file_path
68
+ @file_path = backing_file_path
69
+ create_dir_if_necessary
70
+ end
71
+
72
+
73
+ # Set the section to use for future data exchanges via the ubiquitous {get}
74
+ # and {set} methods as well as the query {contains} key method.
75
+ #
76
+ # @param the_section_name [String]
77
+ # the non-nil and non whitespace only section name that will lead a
78
+ # set of key-value pairs in the INI formatted file.
79
+ def use the_section_name
80
+ raise ArgumentError, "Cannot use a Nil section name." if the_section_name.nil?
81
+ @section_to_use = the_section_name
82
+ end
83
+
84
+ # Stash the setting directive and its value into the configuration file
85
+ # using the default settings group.
86
+ #
87
+ # @param key_name [String] the name of the key whose value is to be written
88
+ # @param key_value [String] the data item value of the key specified
89
+ def set key_name, key_value
90
+ raise ArgumentError, "Cannot set a Nil section name." if @section_to_use.nil?
91
+ write @section_to_use, key_name, key_value
92
+ end
93
+
94
+
95
+ # Stash the setting directive and its value into the configuration file
96
+ # using the default settings group.
97
+ #
98
+ # @param key_name [String] the name of the key whose value is to be written
99
+ # @return [String]
100
+ # return the value of the configuration directive in the default group
101
+ def get key_name
102
+ raise ArgumentError, "Cannot get from a Nil section name." if @section_to_use.nil?
103
+ read @section_to_use, key_name
104
+ end
105
+
106
+
107
+ # Write the key/value pair in the parameter into this key/value store's
108
+ # base file-system backing INI file.
109
+ #
110
+ # This method assumes the existence of the backing configuration file at
111
+ # the @file_path instance variable that was set during initialization.
112
+ #
113
+ # Observable value is the written key/value pair within the specified
114
+ # section. The alternate flows are
115
+ #
116
+ # - if the section does not exist it is created
117
+ # - if the section and key exist the value is inserted or overwritten
118
+ #
119
+ # @param section_name [String] name grouping the section of config values
120
+ # @param key [String] the key name of config directive to be written into the file
121
+ # @param value [String] value of the config directive to be written into the file
122
+ #
123
+ def write section_name, key, value
124
+
125
+ config_map = IniFile.new( :filename => @file_path, :encoding => 'UTF-8' )
126
+ config_map = IniFile.load( @file_path ) if File.file? @file_path
127
+ config_map[section_name][key] = value
128
+ config_map.write
129
+
130
+ end
131
+
132
+
133
+ # Given the configuration key name and the context name, get the
134
+ # corresponding key value from the configuration file whose path
135
+ # is acquired using the {self#get_filepath} method.
136
+ #
137
+ # @param key_name [String] the key whose value is to be retrieved
138
+ #
139
+ # @return [String] the value configured for the parameter key
140
+ #
141
+ # @raise ArgumentError for any one of a long list of reasons that
142
+ # cause the key value to not be retrieved. This can range from
143
+ # non-existent directories and files, non readable files, incorrect
144
+ # configurations right down to missing keys or even missing values.
145
+ def read section_name, key_name
146
+
147
+ raise ArgumentError.new "No section given." if section_name.nil? || section_name.strip.empty?
148
+ raise ArgumentError.new "No parameter key given." if key_name.nil? || key_name.strip.empty?
149
+ raise ArgumentError.new "No file found at [ #{@file_path} ]" unless File.exists? @file_path
150
+ the_text = File.read @file_path
151
+ raise ArgumentError.new "This file is empty => [ #{@file_path} ]" if the_text.empty?
152
+
153
+ the_data = IniFile.load @file_path
154
+ key_exists = the_data[ section_name ].has_key?( key_name )
155
+ key_err_msg = "Key [#{key_name}] not found in section [#{section_name}]"
156
+ raise ArgumentError, key_err_msg unless key_exists
157
+
158
+ rawvalue = the_data[section_name][key_name]
159
+ key_val_msg = "Nil empty or whitespace value for key [#{section_name}][#{key_name}]"
160
+ nil_empty_or_whitespace = rawvalue.nil? || rawvalue.chomp.strip.empty?
161
+ raise ArgumentError, key_val_msg if nil_empty_or_whitespace
162
+
163
+ return rawvalue.chomp.strip
164
+
165
+ end
166
+
167
+
168
+ # Return true if the settings configuration file contains the specified
169
+ # parameter key within the current section name that has been set via
170
+ # the {use} method.
171
+ #
172
+ # This method does not check the contents (value) of the key. Even if it
173
+ # is an empty string, this method returns true so long as the section
174
+ # exists and the key exists within that.
175
+ #
176
+ # @param key_name [String]
177
+ # does a key with this name exist within the current map section.
178
+ #
179
+ # @return [Boolean]
180
+ # return true if the current section exists and a key with the parameter
181
+ # name exists within it.
182
+ # return false if <b>either</b> the section <b>or</b> the key do not exist.
183
+ #
184
+ # raise [ArgumentError]
185
+ # if the configuration file does not exist or is empty
186
+ # if the paramter key_name is nil, empty or contains only whitespace
187
+ def contains? key_name
188
+
189
+ raise ArgumentError.new "No parameter key given." if key_name.nil? || key_name.strip.empty?
190
+ raise ArgumentError.new "No file found at [ #{@file_path} ]" unless File.exists? @file_path
191
+ the_text = File.read @file_path
192
+ raise ArgumentError.new "This file is empty => [ #{@file_path} ]" if the_text.empty?
193
+
194
+ the_data = IniFile.load @file_path
195
+ return false unless the_data.has_section?( @section_to_use )
196
+ return the_data[ @section_to_use ].has_key?( key_name )
197
+
198
+ end
199
+
200
+
201
+
202
+ # Return true if the settings configuration file contains the specified
203
+ # section name. This method ignores whatever section that may or may not
204
+ # have been pointed to by the use command.
205
+ #
206
+ # @param section_name [String]
207
+ # does a section with this name exist within the file data structure
208
+ #
209
+ # @return [Boolean]
210
+ # return true if a section exists with the specified name
211
+ def has_section? section_name
212
+
213
+ KeyError.not_new( section_name, self )
214
+
215
+ raise ArgumentError.new "No file found at [ #{@file_path} ]" unless File.exists? @file_path
216
+ the_text = File.read @file_path
217
+ raise ArgumentError.new "This file is empty => [ #{@file_path} ]" if the_text.empty?
218
+
219
+ the_data = IniFile.load @file_path
220
+ return the_data.has_section?( section_name )
221
+
222
+ end
223
+
224
+
225
+
226
+ # Get the time stamp that was written to the key-value store at
227
+ # the point it was first initialized and then subsequently written
228
+ # out (serialized) onto the file-system.
229
+ #
230
+ # The time stamp returned marks the first time this key-value store
231
+ # was conceived by a use case actor and subsequently serialized.
232
+ #
233
+ # @return [String]
234
+ # the string time stamp denoting the first time this key-value
235
+ # store was first initialized and then subsequently written out
236
+ # (serialized) onto the file-system.
237
+ def time_stamp
238
+ return get INIT_TIME_STAMP_NAME
239
+ end
240
+
241
+
242
+
243
+ private
244
+
245
+
246
+
247
+ def create_dir_if_necessary
248
+
249
+ config_directory = File.dirname @file_path
250
+ return if (File.exist? config_directory) && (File.directory? config_directory)
251
+ FileUtils.mkdir_p config_directory
252
+
253
+ end
254
+
255
+
256
+ end
257
+
258
+
259
+ end
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/ruby
2
+ # coding: utf-8
3
+
4
+ module SafeDb
5
+
6
+ class KeyPass
7
+
8
+
9
+ # <tt>Collect something sensitive from the command line</tt> with a
10
+ # minimum length specified in the first parameter. This method can't
11
+ # know whether the information is a password, a pin number or whatever
12
+ # so it takes the integer minimum size at its word.
13
+ #
14
+ # <b>Question 5 to App Config | What is the Secret?</b>
15
+ #
16
+ # The client may need to acquire the secret if the answer to question 4 indicates the need
17
+ # to instantiate the keys and encrypt the application's plaintext database. The application
18
+ # should facilitate communication of the secret via
19
+ #
20
+ # - an environment variable
21
+ # - the system clipboard (cleared after reading)
22
+ # - a file whose path is a command parameter
23
+ # - a file in a pre-agreed location
24
+ # - a file in the present directory (with a pre-agreed name)
25
+ # - a URL from a parameter or pre-agreed
26
+ # - the shell's secure password reader
27
+ # - the DConf / GConf or GSettings configuration stores
28
+ # - a REST API
29
+ # - password managers like LastPass, KeePassX or 1Pass
30
+ # - the Amazon KMS (Key Management Store)
31
+ # - vaults from Ansible, Terraform and Kubernetes
32
+ # - credential managers like GitSecrets and Credstash
33
+ #
34
+ # @param prompt_twice [Boolean] indicate whether the user should be
35
+ # prompted twice. If true the prompt_2 text must be provided and
36
+ # converse is also true. A true value asserts that both times the
37
+ # user enters the same (case sensitive) string.
38
+ #
39
+ # @return [String] the collected string text ( watch out for non-ascii chars)
40
+ # @raise [ArgumentError] if the minimum size is less than one
41
+ def self.password_from_shell prompt_twice
42
+
43
+ assert_min_size MINIMUM_PASSWORD_SIZE
44
+
45
+ sleep(1)
46
+ puts "Password:"
47
+ first_secret = STDIN.noecho(&:gets).chomp
48
+
49
+ assert_input_text_size first_secret.length, MINIMUM_PASSWORD_SIZE
50
+ return first_secret unless prompt_twice
51
+
52
+ sleep(1)
53
+ puts "Re-enter the password:"
54
+ check_secret = STDIN.noecho(&:gets).chomp
55
+
56
+ assert_same_size_text first_secret, check_secret
57
+
58
+ return first_secret
59
+
60
+ end
61
+
62
+
63
+ # --
64
+ # -- Raise an exception if asked to collect text that is less
65
+ # -- than 3 characters in length.
66
+ # --
67
+ def self.assert_min_size min_size
68
+
69
+ min_length_msg = "\n\nCrypts with 2 (or less) characters open up exploitable holes.\n\n"
70
+ raise ArgumentError.new min_length_msg if min_size < 3
71
+
72
+ end
73
+
74
+
75
+ # --
76
+ # -- Output an error message and then exit if the entered input
77
+ # -- text size does not meet the minimum requirements.
78
+ # --
79
+ def self.assert_input_text_size input_size, min_size
80
+
81
+ if( input_size < min_size )
82
+
83
+ puts
84
+ puts "Input is too short. Please enter at least #{min_size} characters."
85
+ puts
86
+
87
+ exit
88
+
89
+ end
90
+
91
+ end
92
+
93
+
94
+ # --
95
+ # -- Assert that the text entered the second time is exactly (case sensitive)
96
+ # -- the same as the text entered the first time.
97
+ # --
98
+ def self.assert_same_size_text first_text, second_text
99
+
100
+ unless( first_text.eql? second_text )
101
+
102
+ puts
103
+ puts "Those two bits of text are not the same (in my book)!"
104
+ puts
105
+
106
+ exit
107
+
108
+ end
109
+
110
+ end
111
+
112
+ private
113
+
114
+ MINIMUM_PASSWORD_SIZE = 4
115
+
116
+
117
+ end
118
+
119
+
120
+ end