opensecret 0.0.988 → 0.0.9925
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 +5 -5
- data/README.md +56 -159
- data/bin/opensecret +2 -2
- data/bin/ops +17 -2
- data/lib/extension/string.rb +14 -16
- data/lib/{interpreter.rb → interprete.rb} +53 -29
- data/lib/keytools/binary.map.rb +49 -0
- data/lib/keytools/kdf.api.rb +249 -0
- data/lib/keytools/kdf.bcrypt.rb +64 -29
- data/lib/keytools/kdf.pbkdf2.rb +92 -83
- data/lib/keytools/kdf.scrypt.rb +190 -0
- data/lib/keytools/key.64.rb +326 -0
- data/lib/keytools/key.algo.rb +109 -0
- data/lib/keytools/key.api.rb +1281 -0
- data/lib/keytools/key.db.rb +265 -0
- data/lib/keytools/{key.module.rb → key.docs.rb} +55 -0
- data/lib/keytools/key.error.rb +110 -0
- data/lib/keytools/key.id.rb +271 -0
- data/lib/keytools/key.iv.rb +107 -0
- data/lib/keytools/key.local.rb +265 -0
- data/lib/keytools/key.mach.rb +248 -0
- data/lib/keytools/key.now.rb +402 -0
- data/lib/keytools/key.pair.rb +259 -0
- data/lib/keytools/key.pass.rb +120 -0
- data/lib/keytools/key.rb +428 -298
- data/lib/keytools/keydebug.txt +295 -0
- data/lib/logging/gem.logging.rb +3 -3
- data/lib/modules/cryptology/collect.rb +20 -0
- data/lib/session/require.gem.rb +1 -1
- data/lib/usecase/cmd.rb +417 -0
- data/lib/usecase/id.rb +36 -0
- data/lib/usecase/import.rb +174 -0
- data/lib/usecase/init.rb +78 -0
- data/lib/usecase/login.rb +70 -0
- data/lib/usecase/logout.rb +30 -0
- data/lib/usecase/open.rb +126 -0
- data/lib/{interprete → usecase}/put.rb +100 -47
- data/lib/usecase/read.rb +89 -0
- data/lib/{interprete → usecase}/safe.rb +0 -0
- data/lib/{interprete → usecase}/set.rb +0 -0
- data/lib/usecase/token.rb +111 -0
- data/lib/{interprete → usecase}/use.rb +0 -0
- data/lib/version.rb +1 -1
- data/opensecret.gemspec +4 -3
- metadata +39 -33
- data/lib/exception/cli.error.rb +0 -53
- data/lib/exception/errors/cli.errors.rb +0 -31
- data/lib/interprete/begin.rb +0 -232
- data/lib/interprete/cmd.rb +0 -621
- data/lib/interprete/export.rb +0 -163
- data/lib/interprete/init.rb +0 -205
- data/lib/interprete/key.rb +0 -119
- data/lib/interprete/open.rb +0 -148
- data/lib/interprete/seal.rb +0 -129
- data/lib/keytools/digester.rb +0 -245
- data/lib/keytools/key.data.rb +0 -227
- data/lib/keytools/key.derivation.rb +0 -341
- data/lib/modules/mappers/collateral.rb +0 -282
- data/lib/modules/mappers/envelope.rb +0 -127
- data/lib/modules/mappers/settings.rb +0 -170
- data/lib/notepad/scratch.pad.rb +0 -224
- 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
|