keybox 1.1.0 → 1.1.1
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.
- data/CHANGES +10 -0
- data/lib/keybox.rb +1 -1
- data/lib/keybox/application/base.rb +10 -0
- data/lib/keybox/application/password_safe.rb +5 -5
- data/lib/keybox/highline_util.rb +6 -9
- data/lib/keybox/storage/container.rb +10 -5
- data/lib/keybox/storage/record.rb +6 -0
- data/spec/base_app_spec.rb +15 -17
- data/spec/convert_csv_spec.rb +13 -11
- data/spec/entry_spec.rb +32 -32
- data/spec/keybox_app_spec.rb +85 -78
- data/spec/kpg_app_spec.rb +33 -40
- data/spec/password_hash_spec.rb +3 -3
- data/spec/randomizer_spec.rb +53 -54
- data/spec/storage_container_spec.rb +39 -29
- data/spec/storage_record_spec.rb +21 -21
- data/spec/string_generator_spec.rb +39 -41
- data/spec/uuid_spec.rb +22 -21
- data/vendor/highline/highline.rb +54 -14
- data/vendor/highline/highline/system_extensions.rb +1 -1
- metadata +11 -11
data/spec/storage_record_spec.rb
CHANGED
@@ -1,63 +1,63 @@
|
|
1
1
|
require 'keybox/storage'
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
describe 'a storage record entry' do
|
4
|
+
before(:each) do
|
5
5
|
@data_fields = %w(title username password url additional_data)
|
6
6
|
end
|
7
|
-
|
7
|
+
it 'has a creation date set on instantiation' do
|
8
8
|
e = Keybox::Storage::Record.new
|
9
|
-
e.creation_time.
|
9
|
+
e.creation_time.should be_instance_of(Time)
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
it "assigning to a non-existant field creates the appropriate member " do
|
13
13
|
e = Keybox::Storage::Record.new
|
14
14
|
e.junk = "junk"
|
15
15
|
e.junk.should == "junk"
|
16
16
|
end
|
17
17
|
|
18
|
-
|
18
|
+
it 'default values for non-existant fields is nil' do
|
19
19
|
e = Keybox::Storage::Record.new
|
20
20
|
@data_fields.each do |f|
|
21
|
-
e.send(f).
|
21
|
+
e.send(f).should == nil
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
it "assigning to a field makes the modification time > creation time" do
|
26
26
|
e = Keybox::Storage::Record.new
|
27
27
|
sleep 1
|
28
28
|
e.testing = "testing"
|
29
|
-
e.modification_time.
|
29
|
+
e.modification_time.should > e.creation_time
|
30
30
|
e.last_access_time.should == e.modification_time
|
31
31
|
end
|
32
32
|
|
33
|
-
|
33
|
+
it "reading a field after assignment the access time > modification time " do
|
34
34
|
e = Keybox::Storage::Record.new
|
35
35
|
e.testing = "testing"
|
36
36
|
sleep 1
|
37
37
|
e.testing
|
38
|
-
e.last_access_time.
|
39
|
-
e.last_access_time.
|
38
|
+
e.last_access_time.should > e.creation_time
|
39
|
+
e.last_access_time.should > e.modification_time
|
40
40
|
end
|
41
41
|
|
42
|
-
|
42
|
+
it "assigning to a modification, creation or acces_time should raise and exception " do
|
43
43
|
e = Keybox::Storage::Record.new
|
44
|
-
lambda {e.modification_time = Time.now}.
|
44
|
+
lambda {e.modification_time = Time.now}.should raise_error(NoMethodError)
|
45
45
|
end
|
46
46
|
|
47
|
-
|
47
|
+
it "assiging multiple items should raise an argument exception" do
|
48
48
|
e = Keybox::Storage::Record.new
|
49
|
-
lambda {e.send(:stuff=,1,2)}.
|
49
|
+
lambda {e.send(:stuff=,1,2)}.should raise_error(ArgumentError)
|
50
50
|
end
|
51
51
|
|
52
|
-
|
52
|
+
it "calling a method with arguments should raise exception" do
|
53
53
|
e = Keybox::Storage::Record.new
|
54
|
-
lambda {e.stuff(1,2)}.
|
54
|
+
lambda {e.stuff(1,2)}.should raise_error(NoMethodError)
|
55
55
|
end
|
56
56
|
|
57
|
-
|
57
|
+
it "comparison between records is valid" do
|
58
58
|
e = Keybox::Storage::Record.new
|
59
59
|
f = e.dup
|
60
|
-
e.
|
61
|
-
e.
|
60
|
+
e.should == e.uuid
|
61
|
+
e.should == f
|
62
62
|
end
|
63
63
|
end
|
@@ -1,114 +1,112 @@
|
|
1
1
|
require 'keybox'
|
2
|
-
|
3
|
-
|
2
|
+
describe Keybox::StringGenerator do
|
3
|
+
before(:each) do
|
4
4
|
@generator = Keybox::StringGenerator.new
|
5
5
|
end
|
6
6
|
|
7
|
-
|
8
|
-
lambda { @generator.generate }.
|
7
|
+
it "should not be used alone" do
|
8
|
+
lambda { @generator.generate }.should raise_error(Keybox::KeyboxError)
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
it "cannot have a min length greater than a max length" do
|
12
12
|
@generator.min_length = 90
|
13
|
-
lambda { @generator.generate }.
|
14
|
-
@generator.min_length = 8
|
13
|
+
lambda { @generator.generate }.should raise_error(Keybox::ValidationError)
|
15
14
|
end
|
16
15
|
|
17
|
-
|
16
|
+
it "cannot have a max length less than a min length" do
|
18
17
|
@generator.max_length = 2
|
19
|
-
lambda { @generator.generate }.
|
20
|
-
@generator.max_length = 10
|
18
|
+
lambda { @generator.generate }.should raise_error(Keybox::ValidationError)
|
21
19
|
end
|
22
20
|
|
23
|
-
|
24
|
-
@generator.chunks.
|
21
|
+
it "initially there are no chunks" do
|
22
|
+
@generator.chunks.should have(0).entries
|
25
23
|
end
|
26
24
|
end
|
27
25
|
|
28
|
-
|
29
|
-
|
26
|
+
describe "chargram generator" do
|
27
|
+
before(:each) do
|
30
28
|
@generator = Keybox::CharGramGenerator.new
|
31
29
|
end
|
32
30
|
|
33
|
-
|
34
|
-
@generator.size.
|
31
|
+
it "should have a positive size" do
|
32
|
+
@generator.size.should > 26
|
35
33
|
end
|
36
34
|
|
37
|
-
|
38
|
-
@generator.generate_chunk.size.
|
35
|
+
it "should emit a string with length > 0" do
|
36
|
+
@generator.generate_chunk.size.should > 0
|
39
37
|
end
|
40
38
|
|
41
|
-
|
42
|
-
@generator.generate_chunk.
|
39
|
+
it "should emit an array " do
|
40
|
+
@generator.generate_chunk.should be_instance_of(String)
|
43
41
|
end
|
44
42
|
|
45
|
-
|
43
|
+
it "2 succesive emits should have a common first and last character" do
|
46
44
|
one = @generator.generate_chunk
|
47
45
|
two = @generator.generate_chunk
|
48
46
|
one[-1].should == two[0]
|
49
47
|
end
|
50
48
|
|
51
|
-
|
49
|
+
it "2 calls to generate_chunk should have a string that is 1 less than the 2 chunks" do
|
52
50
|
one = @generator.generate_chunk
|
53
51
|
two = @generator.generate_chunk
|
54
52
|
@generator.to_s.length.should == (one.length + two.length - 1)
|
55
53
|
end
|
56
54
|
end
|
57
55
|
|
58
|
-
|
59
|
-
|
56
|
+
describe "SymbolSetGenerator" do
|
57
|
+
before(:each) do
|
60
58
|
@generator = Keybox::SymbolSetGenerator.new
|
61
59
|
end
|
62
60
|
|
63
|
-
|
61
|
+
it "symbol sets have the right number or characters" do
|
64
62
|
Keybox::SymbolSetGenerator::ALL.size.should == 92
|
65
63
|
end
|
66
64
|
|
67
|
-
|
65
|
+
it "generating chunks should produce an array" do
|
68
66
|
12.times do
|
69
67
|
@generator.generate_chunk
|
70
68
|
end
|
71
|
-
@generator.chunks.
|
69
|
+
@generator.chunks.should have(12).entries
|
72
70
|
end
|
73
71
|
|
74
|
-
|
75
|
-
@generator.generate.
|
76
|
-
@generator.to_s.size.
|
72
|
+
it "generate should produce a string" do
|
73
|
+
@generator.generate.should be_instance_of(String)
|
74
|
+
@generator.to_s.size.should > 0
|
77
75
|
end
|
78
76
|
|
79
|
-
|
77
|
+
it "generating chunks can be cleared" do
|
80
78
|
@generator.generate
|
81
79
|
@generator.clear
|
82
|
-
@generator.chunks.
|
80
|
+
@generator.chunks.should have(0).entries
|
83
81
|
end
|
84
82
|
|
85
|
-
|
83
|
+
it "min and max lengths are respected" do
|
86
84
|
@generator.max_length = 25
|
87
85
|
@generator.min_length = 25
|
88
|
-
@generator.generate.size.
|
86
|
+
@generator.generate.size.should == 25
|
89
87
|
end
|
90
88
|
|
91
|
-
|
89
|
+
it "required sets are utilized" do
|
92
90
|
gen = Keybox::SymbolSetGenerator.new([Keybox::SymbolSet::NUMERAL_ASCII, Keybox::SymbolSet::LOWER_ASCII])
|
93
91
|
gen.required_sets << Keybox::SymbolSet::UPPER_ASCII
|
94
92
|
p = gen.generate
|
95
|
-
gen.required_sets.flatten.uniq.
|
93
|
+
gen.required_sets.flatten.uniq.should be_include(p[0].chr)
|
96
94
|
end
|
97
|
-
|
95
|
+
it "required sets are merged with symbol sets" do
|
98
96
|
gen = Keybox::SymbolSetGenerator.new([Keybox::SymbolSet::NUMERAL_ASCII, Keybox::SymbolSet::LOWER_ASCII])
|
99
97
|
gen.required_sets << Keybox::SymbolSet::UPPER_ASCII
|
100
98
|
gen.required_sets.flatten.uniq.each do |c|
|
101
|
-
gen.symbols.
|
99
|
+
gen.symbols.should be_include(c)
|
102
100
|
end
|
103
101
|
end
|
104
102
|
|
105
|
-
|
103
|
+
it "generated passwords autoclear" do
|
106
104
|
@generator.generate.should_not == @generator.generate
|
107
105
|
end
|
108
106
|
|
109
|
-
|
107
|
+
it "setting min and max should not affect " do
|
110
108
|
g = Keybox::SymbolSetGenerator.new(Keybox::SymbolSet::ALL)
|
111
|
-
g.generate.
|
109
|
+
g.generate.should be_instance_of(String)
|
112
110
|
end
|
113
111
|
|
114
112
|
end
|
data/spec/uuid_spec.rb
CHANGED
@@ -1,29 +1,30 @@
|
|
1
1
|
require 'keybox/uuid'
|
2
|
-
|
3
|
-
|
2
|
+
describe "UUID class" do
|
3
|
+
it "should have 16 bytes" do
|
4
4
|
uuid = Keybox::UUID.new
|
5
5
|
uuid.bytes.size.should == 16
|
6
6
|
end
|
7
7
|
|
8
|
-
|
8
|
+
it "as an array should have 16 members" do
|
9
9
|
uuid = Keybox::UUID.new
|
10
10
|
uuid.to_a.size.should == 16
|
11
11
|
end
|
12
12
|
|
13
|
-
|
13
|
+
it "array elements should have values between 0 and 256 " do
|
14
14
|
uuid = Keybox::UUID.new
|
15
15
|
uuid.to_a.each do |b|
|
16
|
-
b.
|
16
|
+
b.should >= 0
|
17
|
+
b.should <= 256
|
17
18
|
end
|
18
19
|
end
|
19
20
|
|
20
|
-
|
21
|
+
it "as a string should match regex" do
|
21
22
|
regex = Keybox::UUID::REGEX
|
22
23
|
uuid = Keybox::UUID.new
|
23
|
-
uuid.to_s.
|
24
|
+
uuid.to_s.should =~ regex
|
24
25
|
end
|
25
26
|
|
26
|
-
|
27
|
+
it "initialized with a string should give a valid uuid" do
|
27
28
|
s = "0123456789abcdef"
|
28
29
|
s_a = s.unpack("C*")
|
29
30
|
s_uuid = sprintf(Keybox::UUID::FORMAT,*s_a)
|
@@ -31,44 +32,44 @@ context "UUID class" do
|
|
31
32
|
uuid.to_s.should == s_uuid
|
32
33
|
end
|
33
34
|
|
34
|
-
|
35
|
+
it "initialized with a string in the format of a uuid is valid " do
|
35
36
|
s = "c8b5a23a-2507-4834-ab19-60f2cb2a5271"
|
36
37
|
uuid = Keybox::UUID.new(s)
|
37
38
|
uuid.to_s.should == s
|
38
39
|
end
|
39
40
|
|
40
|
-
|
41
|
+
it "not enough bytes should throw an expeption" do
|
41
42
|
s = "0123456789"
|
42
|
-
lambda { Keybox::UUID.new(s) }.
|
43
|
+
lambda { Keybox::UUID.new(s) }.should raise_error(ArgumentError)
|
43
44
|
end
|
44
45
|
|
45
|
-
|
46
|
+
it "invalid uuid string should throw an exception" do
|
46
47
|
s = "z8b5a23a-2507-4834-ab19-60f2cb2a5271"
|
47
|
-
lambda { Keybox::UUID.new(s) }.
|
48
|
+
lambda { Keybox::UUID.new(s) }.should raise_error(ArgumentError)
|
48
49
|
end
|
49
50
|
|
50
|
-
|
51
|
-
lambda { Keybox::UUID.new(42) }.
|
51
|
+
it "initialing with a non-string raises an exception" do
|
52
|
+
lambda { Keybox::UUID.new(42) }.should raise_error(ArgumentError)
|
52
53
|
end
|
53
54
|
|
54
|
-
|
55
|
+
it "should equal another keybox created with same data" do
|
55
56
|
s = "c8b5a23a-2507-4834-ab19-60f2cb2a5271"
|
56
57
|
one = Keybox::UUID.new(s)
|
57
58
|
two = Keybox::UUID.new(s)
|
58
59
|
one.should == two
|
59
60
|
end
|
60
61
|
|
61
|
-
|
62
|
+
it "should equal a string that is the same uuid" do
|
62
63
|
s = "c8b5a23a-2507-4834-ab19-60f2cb2a5271"
|
63
64
|
one = Keybox::UUID.new(s)
|
64
65
|
one.should == s
|
65
66
|
end
|
66
67
|
|
67
|
-
|
68
|
+
it "should not equal some other uuid or random string" do
|
68
69
|
s = "c8b5a23a-2507-4834-ab19-60f2cb2a5271"
|
69
70
|
one = Keybox::UUID.new(s)
|
70
|
-
one.
|
71
|
-
one.
|
72
|
-
one.
|
71
|
+
one.should_not == Keybox::UUID.new
|
72
|
+
one.should_not == "i love ruby"
|
73
|
+
one.should_not == 4
|
73
74
|
end
|
74
75
|
end
|
data/vendor/highline/highline.rb
CHANGED
@@ -29,7 +29,7 @@ require "abbrev"
|
|
29
29
|
#
|
30
30
|
class HighLine
|
31
31
|
# The version of the installed library.
|
32
|
-
VERSION = "1.2.
|
32
|
+
VERSION = "1.2.9".freeze
|
33
33
|
|
34
34
|
# An internal HighLine error. User code does not need to trap this.
|
35
35
|
class QuestionError < StandardError
|
@@ -48,6 +48,19 @@ class HighLine
|
|
48
48
|
def self.use_color?
|
49
49
|
@@use_color
|
50
50
|
end
|
51
|
+
|
52
|
+
# The setting used to disable EOF tracking.
|
53
|
+
@@track_eof = true
|
54
|
+
|
55
|
+
# Pass +false+ to _setting_ to turn off HighLine's EOF tracking.
|
56
|
+
def self.track_eof=( setting )
|
57
|
+
@@track_eof = setting
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns true if HighLine is currently tracking EOF for input.
|
61
|
+
def self.track_eof?
|
62
|
+
@@track_eof
|
63
|
+
end
|
51
64
|
|
52
65
|
# The setting used to control color schemes.
|
53
66
|
@@color_scheme = nil
|
@@ -75,7 +88,9 @@ class HighLine
|
|
75
88
|
# An alias for CLEAR.
|
76
89
|
RESET = CLEAR
|
77
90
|
# Erase the current line of terminal output.
|
78
|
-
ERASE_LINE = "\e[K"
|
91
|
+
ERASE_LINE = "\e[K"
|
92
|
+
# Erase the character under the cursor.
|
93
|
+
ERASE_CHAR = "\e[P"
|
79
94
|
# The start of an ANSI bold sequence.
|
80
95
|
BOLD = "\e[1m"
|
81
96
|
# The start of an ANSI dark sequence. (Terminal support uncommon.)
|
@@ -189,9 +204,11 @@ class HighLine
|
|
189
204
|
@question ||= Question.new(question, answer_type, &details)
|
190
205
|
|
191
206
|
return gather if @question.gather
|
192
|
-
|
193
|
-
# readline() needs to handle it's own output
|
194
|
-
|
207
|
+
|
208
|
+
# readline() needs to handle it's own output, but readline only supports
|
209
|
+
# full line reading. Therefore if @question.echo is anything but true,
|
210
|
+
# the prompt will not be issued. And we have to account for that now.
|
211
|
+
say(@question) unless (@question.readline and @question.echo == true)
|
195
212
|
begin
|
196
213
|
@answer = @question.answer_or_default(get_response)
|
197
214
|
unless @question.valid_answer?(@answer)
|
@@ -573,7 +590,8 @@ class HighLine
|
|
573
590
|
|
574
591
|
answer
|
575
592
|
else
|
576
|
-
raise EOFError, "The input stream is exhausted." if
|
593
|
+
raise EOFError, "The input stream is exhausted." if @@track_eof and
|
594
|
+
@input.eof?
|
577
595
|
|
578
596
|
@question.change_case(@question.remove_whitespace(@input.gets))
|
579
597
|
end
|
@@ -598,24 +616,46 @@ class HighLine
|
|
598
616
|
raw_no_echo_mode if stty = CHARACTER_MODE == "stty"
|
599
617
|
|
600
618
|
line = ""
|
619
|
+
backspace_limit = 0
|
601
620
|
begin
|
621
|
+
|
602
622
|
while character = (stty ? @input.getc : get_character(@input))
|
603
|
-
|
623
|
+
# honor backspace and delete
|
624
|
+
if character == 127 or character == 8
|
625
|
+
line.slice!(-1, 1)
|
626
|
+
backspace_limit -= 1
|
627
|
+
else
|
628
|
+
line << character.chr
|
629
|
+
backspace_limit = line.size
|
630
|
+
end
|
604
631
|
# looking for carriage return (decimal 13) or
|
605
632
|
# newline (decimal 10) in raw input
|
606
633
|
break if character == 13 or character == 10 or
|
607
634
|
(@question.limit and line.size == @question.limit)
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
635
|
+
if @question.echo != false
|
636
|
+
if character == 127 or character == 8
|
637
|
+
# only backspace if we have characters on the line to
|
638
|
+
# eliminate, otherwise we'll tromp over the prompt
|
639
|
+
if backspace_limit >= 0 then
|
640
|
+
@output.print("\b#{ERASE_CHAR}")
|
641
|
+
else
|
642
|
+
# do nothing
|
643
|
+
end
|
644
|
+
else
|
645
|
+
@output.print(@question.echo)
|
646
|
+
end
|
647
|
+
@output.flush
|
648
|
+
end
|
615
649
|
end
|
616
650
|
ensure
|
617
651
|
restore_mode if stty
|
618
652
|
end
|
653
|
+
if @question.overwrite
|
654
|
+
@output.print("\r#{ERASE_LINE}")
|
655
|
+
@output.flush
|
656
|
+
else
|
657
|
+
say("\n")
|
658
|
+
end
|
619
659
|
|
620
660
|
@question.change_case(@question.remove_whitespace(line))
|
621
661
|
end
|