opensecret 0.0.988 → 0.0.9925

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +56 -159
  3. data/bin/opensecret +2 -2
  4. data/bin/ops +17 -2
  5. data/lib/extension/string.rb +14 -16
  6. data/lib/{interpreter.rb → interprete.rb} +53 -29
  7. data/lib/keytools/binary.map.rb +49 -0
  8. data/lib/keytools/kdf.api.rb +249 -0
  9. data/lib/keytools/kdf.bcrypt.rb +64 -29
  10. data/lib/keytools/kdf.pbkdf2.rb +92 -83
  11. data/lib/keytools/kdf.scrypt.rb +190 -0
  12. data/lib/keytools/key.64.rb +326 -0
  13. data/lib/keytools/key.algo.rb +109 -0
  14. data/lib/keytools/key.api.rb +1281 -0
  15. data/lib/keytools/key.db.rb +265 -0
  16. data/lib/keytools/{key.module.rb → key.docs.rb} +55 -0
  17. data/lib/keytools/key.error.rb +110 -0
  18. data/lib/keytools/key.id.rb +271 -0
  19. data/lib/keytools/key.iv.rb +107 -0
  20. data/lib/keytools/key.local.rb +265 -0
  21. data/lib/keytools/key.mach.rb +248 -0
  22. data/lib/keytools/key.now.rb +402 -0
  23. data/lib/keytools/key.pair.rb +259 -0
  24. data/lib/keytools/key.pass.rb +120 -0
  25. data/lib/keytools/key.rb +428 -298
  26. data/lib/keytools/keydebug.txt +295 -0
  27. data/lib/logging/gem.logging.rb +3 -3
  28. data/lib/modules/cryptology/collect.rb +20 -0
  29. data/lib/session/require.gem.rb +1 -1
  30. data/lib/usecase/cmd.rb +417 -0
  31. data/lib/usecase/id.rb +36 -0
  32. data/lib/usecase/import.rb +174 -0
  33. data/lib/usecase/init.rb +78 -0
  34. data/lib/usecase/login.rb +70 -0
  35. data/lib/usecase/logout.rb +30 -0
  36. data/lib/usecase/open.rb +126 -0
  37. data/lib/{interprete → usecase}/put.rb +100 -47
  38. data/lib/usecase/read.rb +89 -0
  39. data/lib/{interprete → usecase}/safe.rb +0 -0
  40. data/lib/{interprete → usecase}/set.rb +0 -0
  41. data/lib/usecase/token.rb +111 -0
  42. data/lib/{interprete → usecase}/use.rb +0 -0
  43. data/lib/version.rb +1 -1
  44. data/opensecret.gemspec +4 -3
  45. metadata +39 -33
  46. data/lib/exception/cli.error.rb +0 -53
  47. data/lib/exception/errors/cli.errors.rb +0 -31
  48. data/lib/interprete/begin.rb +0 -232
  49. data/lib/interprete/cmd.rb +0 -621
  50. data/lib/interprete/export.rb +0 -163
  51. data/lib/interprete/init.rb +0 -205
  52. data/lib/interprete/key.rb +0 -119
  53. data/lib/interprete/open.rb +0 -148
  54. data/lib/interprete/seal.rb +0 -129
  55. data/lib/keytools/digester.rb +0 -245
  56. data/lib/keytools/key.data.rb +0 -227
  57. data/lib/keytools/key.derivation.rb +0 -341
  58. data/lib/modules/mappers/collateral.rb +0 -282
  59. data/lib/modules/mappers/envelope.rb +0 -127
  60. data/lib/modules/mappers/settings.rb +0 -170
  61. data/lib/notepad/scratch.pad.rb +0 -224
  62. data/lib/store-commands.txt +0 -180
@@ -0,0 +1,402 @@
1
+ #!/usr/bin/ruby
2
+
3
+ module OpenKey
4
+
5
+ require 'singleton'
6
+
7
+ # This stamp sits at the centre of a fundamental DevOps pattern concerned
8
+ # with infrastructure provisioning and configuraion management.
9
+ #
10
+ # The central idea behind the pattern is to link every infrastructure
11
+ # object created during a session with a reference accurate to the nearest
12
+ # centi-second denoting the moment the software runtime (session) began.
13
+ class KeyNow
14
+ include Singleton
15
+
16
+ attr_reader :time_now
17
+
18
+ # Return two digit [mo] month index from 01 to 12.
19
+ # @example 02 => in February
20
+ #
21
+ def self.mo
22
+ return KeyNow.instance.time_now.strftime "%m"
23
+ end
24
+
25
+
26
+ # Return three character abbreviated month name.
27
+ # @example feb => in February
28
+ #
29
+ def self.mmm
30
+ return KeyNow.instance.time_now.strftime( "%b" ).downcase
31
+ end
32
+
33
+
34
+ #
35
+ # Return three character abbreviated day of week.
36
+ # @example tue => on Tuesday
37
+ #
38
+ def self.ddd
39
+ return KeyNow.instance.time_now.strftime( "%a" ).downcase
40
+ end
41
+
42
+
43
+ #
44
+ # Return two digit (character) hour of day from 00 to 23.
45
+ # @example 22 => between 22.00.00 and 22.59.59 inclusive
46
+ #
47
+ def self.hh
48
+ return KeyNow.instance.time_now.strftime "%H"
49
+ end
50
+
51
+
52
+ #
53
+ # Return two digit minute of hour from [00] to [59].
54
+ #
55
+ def self.mm
56
+ return KeyNow.instance.time_now.strftime "%M"
57
+ end
58
+
59
+
60
+ #
61
+ # Return two digit second of minute from [00] to [59].
62
+ #
63
+ def self.ss
64
+ return KeyNow.instance.time_now.strftime "%S"
65
+ end
66
+
67
+
68
+ #
69
+ # Return a [3 digit] second and tenth of second
70
+ # representation.
71
+ #
72
+ # The final digit is derived from the 1000 sliced
73
+ # millisecond of second running from 000 to 999.
74
+ #
75
+ # <tt>Truncation (Not Rounding)</tt>
76
+ #
77
+ # The [final] digit is acquired by TRUNCATING
78
+ # (chopping off) the last 2 of the 3 millisecond
79
+ # digits. No rounding is applied.
80
+ #
81
+ # The 3 returned digits comprise of the
82
+ #
83
+ # - second of minute => 2 digits | [00] to [59] (and)
84
+ # - tenth of second => 1 digit from [0] to [9]
85
+ #
86
+ # @example
87
+ #
88
+ # => The time at the 562nd millisecond of the 49th
89
+ # second of the minute.
90
+ #
91
+ # => 3 chars
92
+ # => 495
93
+ #
94
+ #
95
+ def self.sst
96
+ millisec_string = KeyNow.instance.time_now.strftime "%L"
97
+ return "#{ss}#{millisec_string[0]}"
98
+ end
99
+
100
+
101
+ #
102
+ # Return the [two] digit year (eg 19 for 2019).
103
+ # that we are currently in.
104
+ #
105
+ def self.yy
106
+ return KeyNow.instance.time_now.strftime("%Y")[2..-1]
107
+ end
108
+
109
+
110
+ #
111
+ # Return the [four] digit year (eg 2019)
112
+ # that we are currently in.
113
+ #
114
+ def self.yyyy
115
+ return KeyNow.instance.time_now.strftime("%Y")
116
+ end
117
+
118
+
119
+ # ------------------------------------------------- -- #
120
+ # Return 3 digit julian day of year [001] to [366]. -- #
121
+ # ------------------------------------------------- -- #
122
+ def self.jjj
123
+ return KeyNow.instance.time_now.strftime "%j"
124
+ end
125
+
126
+
127
+ # [yymo_mmm] returns an amalgam of
128
+ #
129
+ # => the two-digit year
130
+ # => the two-digit month index (starting at 01)
131
+ # => a period (separator)
132
+ # => the abbreviated month name
133
+ #
134
+ # @example
135
+ # => 1908.aug
136
+ # => for August 2019
137
+ #
138
+ def self.yymo_mmm
139
+ return "#{yy}#{mo}.#{mmm}"
140
+ end
141
+
142
+
143
+ #
144
+ # Given two integer parameters (month index and 4 digit year) representing
145
+ # the month in question this method returns the [PREVIOUS MONTHS] character
146
+ # amalgam in the format [yymo_mmm] where
147
+ #
148
+ # => yy | previous month's two-digit year
149
+ # => mo | previous month's two-digit month index
150
+ # => . | a period (separator)
151
+ # => mmm | previous month's abbreviated month name
152
+ #
153
+ # -------------------
154
+ # Example 1 (Simple)
155
+ # -------------------
156
+ #
157
+ # returns char => 1907.jul
158
+ # 4 parameters => 8, 2019
159
+ # representing => August, 2019
160
+ #
161
+ # ----------------------
162
+ # Example 2 (Last Year)
163
+ # ----------------------
164
+ #
165
+ # returns char => 1812.dec
166
+ # 4 parameters => 1, 2019
167
+ # representing => January, 2019
168
+ #
169
+ def self.previous_month_chars this_month_index, this_4digit_year
170
+
171
+ prev_month_index = this_month_index == 1 ? 12 : ( this_month_index - 1 )
172
+ prev_2dig_mn_pad = sprintf '%02d', prev_month_index
173
+ prev_4digit_year = this_month_index == 1 ? ( this_4digit_year - 1 ) : this_4digit_year
174
+ prev_twodigit_yr = "#{prev_4digit_year.to_s}"[2..-1]
175
+ prev_months_name = Date::ABBR_MONTHNAMES[prev_month_index].downcase
176
+
177
+ return "#{prev_twodigit_yr}#{prev_2dig_mn_pad}.#{prev_months_name}"
178
+
179
+ end
180
+
181
+ #
182
+ # Using the current class time this method returns
183
+ # the character amalgam for the [PREVIOUS MONTH] in
184
+ # the format [yymo_mmm] where
185
+ #
186
+ # => yy | last month's two-digit year
187
+ # => mo | last month's two-digit month index
188
+ # => . | a period (separator)
189
+ # => mmm | last month's abbreviated month name
190
+ #
191
+ # -------------------
192
+ # Example 1 (Simple)
193
+ # -------------------
194
+ #
195
+ # returns => 1907.jul
196
+ # if this month is => August 2019
197
+ #
198
+ # ----------------------
199
+ # Example 2 (Last Year)
200
+ # ----------------------
201
+ #
202
+ # returns => 1812.dec
203
+ # if this month is => January 2019
204
+ #
205
+ def self.yymo_mmm_prev
206
+ return previous_month_chars mo.to_i, yyyy.to_i
207
+ end
208
+
209
+
210
+ # Return 5 digit amalgam of year and julian day.
211
+ # eg [19003] for [January 3rd 2019]
212
+ def self.yyjjj
213
+ return "#{yy}#{jjj}"
214
+ end
215
+
216
+
217
+ # Return the 4 digit amalgam of the hour and minute
218
+ # using the 24 hour clock.
219
+ #
220
+ # @example
221
+ # => 1525
222
+ # => 03:25 pm
223
+ #
224
+ def self.hhmm
225
+ return "#{hh}#{mm}"
226
+ end
227
+
228
+
229
+ #
230
+ # Return the time of day to a TENTH of a second accuracy.
231
+ # [8] characters will always be returned with the 5th one
232
+ # being the (period) separator.
233
+ #
234
+ # The first (separated) segment delivers a hhmm 24 hour
235
+ # clock representation of the stamped time.
236
+ #
237
+ # The 3 digits of the second segment comprise of
238
+ #
239
+ # second of minute => 2 digits | [00] to [59]
240
+ # tenth of second => 1 digit from [0] to [9]
241
+ #
242
+ # @example
243
+ # => The time at the 562nd millisecond of the 49th
244
+ # second of the 23rd minute of the 17th hour of
245
+ # the day ( 17:23:49.562 )
246
+ #
247
+ # => 8 chars
248
+ # => 1723.495
249
+ #
250
+ def self.hhmm_sst
251
+ return "#{hhmm}.#{sst}"
252
+ end
253
+
254
+
255
+ # Return a string timestampt that is a period separated
256
+ # amalgam of the 2 digit year, 3 digit julian day, 2 digit
257
+ # hour, 2 digit minute, 2 digit second and 1 digit rounded
258
+ # down tenth of second.
259
+ #
260
+ # @example
261
+ # => 19003.1025
262
+ # => 10:25 am on January 3rd 2019
263
+ #
264
+ #
265
+ # Return the time of day to a TENTH of a second accuracy.
266
+ # [8] characters will always be returned with the 5th one
267
+ # being the (period) separator.
268
+ #
269
+ # The first (separated) segment delivers a hhmm 24 hour
270
+ # clock representation of the stamped time.
271
+ #
272
+ # The 3 digits of the second segment comprise of
273
+ #
274
+ # - second of minute => 2 digits | [00] to [59]
275
+ # - tenth of second => 1 digit from [0] to [9]
276
+ #
277
+ # @example
278
+ # => The time at the 562nd millisecond of the 49th
279
+ # second of the 23rd minute of the 17th hour of
280
+ # the day ( 17:23:49.562 )
281
+ #
282
+ # => 8 chars
283
+ # => 1723.495
284
+ #
285
+ def self.yyjjj_hhmm_sst
286
+ return "#{yyjjj}.#{hhmm}.#{sst}"
287
+ end
288
+
289
+
290
+ # Return a string timestampt that is a period separated
291
+ # amalgam of the 2 digit year, 3 digit julian day, 2 digit
292
+ # hour, 2 digit minute, 2 digit second and <b>9 digit</b>
293
+ # nanosecond.
294
+ #
295
+ # @example
296
+ # return => 19003.1725.42.836592034
297
+ # 4 time => 17:25:42 am on January 3rd 2019
298
+ #
299
+ # As per the above example, the time returned
300
+ #
301
+ # - is the 836592034 <b>nanosecond</b>
302
+ # - of the 42nd <b>second</b>
303
+ # - of the 25th <b>minute</b>
304
+ # - of the 17th <b>hour</b>
305
+ # - of the 3rd <b>day</b>
306
+ # - of the 20th <b>year</b>
307
+ # - of the 21st <b>century</b>
308
+ #
309
+ # @return [String]
310
+ # Return the time of day to nanosecond accuracy.
311
+ # 23 characters are always returned with three (3) period
312
+ # separators at the 6th, 11th and 14th positions.
313
+ def self.yyjjj_hhmm_ss_nanosec
314
+ nanosec_str = KeyNow.instance.time_now.strftime "%9N"
315
+ return "#{yyjjj}.#{hhmm}.#{ss}.#{nanosec_str}"
316
+ end
317
+
318
+
319
+ # Fetch the double barreled time stamp that is an amalgam of
320
+ # the human readable time now and a machine time representation
321
+ # from the moment this class was initialized.
322
+ #
323
+ # See the {yyjjj_hhmm_ss_nanosec} method for documentation of
324
+ # the nanosecond accurate time stamp.
325
+ #
326
+ # @return [String]
327
+ # the double barreled time stamp containing a human readable
328
+ # (right this moment) time and a <b>class initialized time</b>
329
+ # representation with nanosecond accuracy.
330
+ def self.fetch
331
+ return "#{Time.now.ctime} ( #{yyjjj_hhmm_ss_nanosec} )"
332
+ end
333
+
334
+
335
+ # Grab the double barreled time stamp that is an amalgam of
336
+ # the human readable time now and a machine time representation
337
+ # from the moment this class was initialized.
338
+ #
339
+ # On Friday June the 8th at about 6:26 pm.
340
+ # Fri Jun 8 18:26:17 2018 ( 18159.1826.138 )
341
+ #
342
+ # See the {yyjjj_hhmm_sst} method for documentation of stamp
343
+ # that is accurate to the tenth of a second.
344
+ #
345
+ # @return [String]
346
+ # the double barreled time stamp containing a human readable
347
+ # (right this moment) time and a <b>class initialized time</b>
348
+ # representation with tenth of a second accuracy.
349
+ def self.grab
350
+ time_with_consecutive_spaces = Time.now.ctime
351
+ human_readable_str = time_with_consecutive_spaces.gsub( " ", " " )
352
+ return "#{human_readable_str} ( #{yyjjj_hhmm_sst} )"
353
+ end
354
+
355
+
356
+ # Return the Rubyfied time zone being used.
357
+ def self.zone
358
+ return KeyNow.instance.time_now.zone
359
+ end
360
+
361
+
362
+ # Log segments of time pertaining to the time stamp.
363
+ # @todo
364
+ # move method contents into test class
365
+ def self.log_instance_time
366
+
367
+ log.info(x) { "[stamp] -------------- => -------------------------------- #" }
368
+ log.info(x) { "[stamp] eco time stamp => [#{KeyNow.instance.time_now.ctime}]" }
369
+ log.info(x) { "[stamp] -------------- => -------------------------------- #" }
370
+ log.info(x) { "[stamp] Univ Time Zone => #{zone}" }
371
+ log.info(x) { "[stamp] Month Index is => #{mo}" }
372
+ log.info(x) { "[stamp] Month Name is => #{mmm}" }
373
+ log.info(x) { "[stamp] Day Of Week is => #{ddd}" }
374
+ log.info(x) { "[stamp] -------------- => -------------------------------- #" }
375
+ log.info(x) { "[stamp] Two Digit Year => #{yy}" }
376
+ log.info(x) { "[stamp] Julian Cal Day => #{jjj}" }
377
+ log.info(x) { "[stamp] Yr and Jul Day => #{yyjjj}" }
378
+ log.info(x) { "[stamp] Hour of Theday => #{hh}" }
379
+ log.info(x) { "[stamp] Minute of Hour => #{mm}" }
380
+ log.info(x) { "[stamp] Hour + Minute => #{hhmm}" }
381
+ log.info(x) { "[stamp] Second of Min => #{ss}" }
382
+ log.info(x) { "[stamp] 600 Min Slices => #{sst}" }
383
+ log.info(x) { "[stamp] -------------- => -------------------------------- #" }
384
+ log.info(x) { "[stamp] The Time Stamp => #{yyjjj_hhmm_sst}" }
385
+ log.info(x) { "[stamp] -------------- => -------------------------------- #" }
386
+
387
+ end
388
+
389
+
390
+ # This singleton (one instance) class sets the time just once.
391
+ def initialize
392
+ @time_now = Time.now;
393
+ end
394
+
395
+
396
+ KeyNow.log_instance_time
397
+
398
+
399
+ end
400
+
401
+
402
+ end
@@ -0,0 +1,259 @@
1
+ #!/usr/bin/ruby
2
+ # coding: utf-8
3
+
4
+ module OpenKey
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