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/kpg_app_spec.rb
CHANGED
@@ -1,132 +1,125 @@
|
|
1
1
|
require 'keybox'
|
2
2
|
require 'keybox/application/password_generator'
|
3
3
|
|
4
|
-
|
5
|
-
setup do
|
6
|
-
end
|
4
|
+
describe "Keybox Password Generator Application" do
|
7
5
|
|
8
|
-
|
6
|
+
it "nil argv should do nothing" do
|
9
7
|
kpg = Keybox::Application::PasswordGenerator.new(nil)
|
10
|
-
kpg.error_message.
|
8
|
+
kpg.error_message.should == nil
|
11
9
|
end
|
12
10
|
|
13
|
-
|
11
|
+
it "invalid options set the error message, exit 1 and have output on stderr" do
|
14
12
|
kpg = Keybox::Application::PasswordGenerator.new(["--invalid-option"])
|
15
13
|
kpg.set_io(StringIO.new,StringIO.new,StringIO.new)
|
16
14
|
begin
|
17
15
|
kpg.run
|
18
16
|
rescue SystemExit => se
|
19
|
-
kpg.error_message.
|
20
|
-
kpg.stderr.string.
|
17
|
+
kpg.error_message.should =~ /Try.*--help/m
|
18
|
+
kpg.stderr.string.should =~ /Try.*--help/m
|
21
19
|
se.status.should == 1
|
22
20
|
end
|
23
21
|
end
|
24
22
|
|
25
|
-
|
23
|
+
it "can set the algorithm" do
|
26
24
|
kpg = Keybox::Application::PasswordGenerator.new(["--alg", "pron"])
|
27
25
|
kpg.set_io(StringIO.new,StringIO.new)
|
28
26
|
kpg.run
|
29
27
|
kpg.options.algorithm.should == :pronounceable
|
30
28
|
end
|
31
29
|
|
32
|
-
|
30
|
+
it "can it the number of passwords created " do
|
33
31
|
kpg = Keybox::Application::PasswordGenerator.new(["--num", "4"])
|
34
32
|
kpg.set_io(StringIO.new,StringIO.new)
|
35
33
|
kpg.run
|
36
|
-
kpg.options.number_to_generate.
|
37
|
-
kpg.stdout.string.split(/\s+/).
|
34
|
+
kpg.options.number_to_generate.should == 4
|
35
|
+
kpg.stdout.string.split(/\s+/).should have(4).items
|
38
36
|
end
|
39
37
|
|
40
|
-
|
38
|
+
it "help has output on stdout and exits 0" do
|
41
39
|
kpg = Keybox::Application::PasswordGenerator.new(["--h"])
|
42
40
|
kpg.set_io(StringIO.new,StringIO.new)
|
43
41
|
begin
|
44
42
|
kpg.run
|
45
43
|
rescue SystemExit => se
|
46
|
-
se.status.
|
47
|
-
kpg.stdout.string.length.
|
44
|
+
se.status.should == 0
|
45
|
+
kpg.stdout.string.length.should > 0
|
48
46
|
end
|
49
|
-
kpg.stdout.string.
|
47
|
+
kpg.stdout.string.should =~ /--help/m
|
50
48
|
end
|
51
49
|
|
52
|
-
|
50
|
+
it "version has output on stdout and exits 0" do
|
53
51
|
kpg = Keybox::Application::PasswordGenerator.new(["--version"])
|
54
52
|
kpg.set_io(StringIO.new,StringIO.new)
|
55
53
|
begin
|
56
54
|
kpg.run
|
57
55
|
rescue SystemExit => se
|
58
|
-
se.status.
|
56
|
+
se.status.should == 0
|
59
57
|
end
|
60
|
-
kpg.stdout.string.
|
58
|
+
kpg.stdout.string.should =~ /version 1/m
|
61
59
|
end
|
62
60
|
|
63
|
-
|
61
|
+
it "minimum length can be set and all generated passwords will have length >= minimum length" do
|
64
62
|
kpg = Keybox::Application::PasswordGenerator.new(["--min", "4"])
|
65
63
|
kpg.set_io(StringIO.new,StringIO.new)
|
66
64
|
kpg.run
|
67
65
|
|
68
|
-
kpg.options.min_length.
|
66
|
+
kpg.options.min_length.should == 4
|
69
67
|
kpg.stdout.string.split("\n").each do |pass|
|
70
|
-
pass.length.
|
68
|
+
pass.length.should >= kpg.options.min_length
|
71
69
|
end
|
72
70
|
end
|
73
71
|
|
74
|
-
|
72
|
+
it "maximum length can be set and all generated passwords will have length <= maximum length" do
|
75
73
|
kpg = Keybox::Application::PasswordGenerator.new(["--max", "4", "--min", "3"])
|
76
74
|
kpg.set_io(StringIO.new,StringIO.new,StringIO.new)
|
77
75
|
kpg.run
|
78
76
|
|
79
|
-
kpg.options.max_length.
|
77
|
+
kpg.options.max_length.should == 4
|
80
78
|
kpg.stdout.string.split("\n").each do |pass|
|
81
|
-
pass.length.
|
79
|
+
pass.length.should <= 4
|
82
80
|
end
|
83
81
|
end
|
84
82
|
|
85
|
-
|
83
|
+
it "setting an invalid required symbol set exits 1 and outputs data on stderr" do
|
86
84
|
kpg = Keybox::Application::PasswordGenerator.new(["--req","bunk"])
|
87
85
|
kpg.set_io(StringIO.new,StringIO.new,StringIO.new)
|
88
86
|
begin
|
89
87
|
kpg.run
|
90
88
|
rescue SystemExit => se
|
91
|
-
kpg.error_message.
|
92
|
-
kpg.stderr.string.
|
89
|
+
kpg.error_message.should =~ /Try.*--help/m
|
90
|
+
kpg.stderr.string.should =~ /Try.*--help/m
|
93
91
|
se.status.should == 1
|
94
92
|
end
|
95
93
|
|
96
94
|
end
|
97
95
|
|
98
|
-
|
96
|
+
it "setting an invalid use symbol set exits 1 and outputs data on stderr" do
|
99
97
|
kpg = Keybox::Application::PasswordGenerator.new(["--use","bunk"])
|
100
98
|
kpg.set_io(StringIO.new,StringIO.new,StringIO.new)
|
101
99
|
begin
|
102
100
|
kpg.run
|
103
101
|
rescue SystemExit => se
|
104
|
-
kpg.error_message.
|
105
|
-
kpg.stderr.string.
|
102
|
+
kpg.error_message.should =~ /Try.*--help/m
|
103
|
+
kpg.stderr.string.should =~ /Try.*--help/m
|
106
104
|
se.status.should == 1
|
107
105
|
end
|
108
106
|
|
109
107
|
end
|
110
108
|
|
111
|
-
|
109
|
+
it "setting an valid use symbol works" do
|
112
110
|
kpg = Keybox::Application::PasswordGenerator.new(["--use","l"])
|
113
111
|
kpg.set_io(StringIO.new,StringIO.new,StringIO.new)
|
114
112
|
kpg.run
|
115
|
-
kpg.options.use_symbols.
|
113
|
+
kpg.options.use_symbols.should be_include(Keybox::SymbolSet::LOWER_ASCII)
|
116
114
|
kpg.stdout.string.split(/\s+/).size.should == 6
|
117
115
|
end
|
118
116
|
|
119
|
-
|
117
|
+
it "setting an valid required symbol works" do
|
120
118
|
kpg = Keybox::Application::PasswordGenerator.new(["--req","l"])
|
121
119
|
kpg.set_io(StringIO.new,StringIO.new,StringIO.new)
|
122
120
|
kpg.run
|
123
|
-
kpg.options.require_symbols.
|
121
|
+
kpg.options.require_symbols.should be_include(Keybox::SymbolSet::LOWER_ASCII)
|
124
122
|
kpg.stdout.string.split(/\s+/).size.should == 6
|
125
123
|
end
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
124
|
end
|
132
125
|
|
data/spec/password_hash_spec.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'keybox'
|
2
|
-
|
3
|
-
|
2
|
+
describe "PasswordHash" do
|
3
|
+
before(:each) do
|
4
4
|
@pwd_hash = Keybox::PasswordHash.new("i love ruby")
|
5
5
|
end
|
6
6
|
|
7
|
-
|
7
|
+
it "creates string for password" do
|
8
8
|
pwd = @pwd_hash.password_for_url("http://www.nytimes.com")
|
9
9
|
pwd.should == "2f85a2e2f"
|
10
10
|
end
|
data/spec/randomizer_spec.rb
CHANGED
@@ -1,116 +1,115 @@
|
|
1
1
|
require 'keybox/randomizer'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
Keybox::RandomDevice.default.
|
3
|
+
describe "a random device class" do
|
4
|
+
it "should have a default source" do
|
5
|
+
Keybox::RandomDevice.default.should == "/dev/urandom"
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
Keybox::RandomDevice.random_bytes.
|
8
|
+
it "should produce strings" do
|
9
|
+
Keybox::RandomDevice.random_bytes.should be_an_instance_of(String)
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
Keybox::RandomDevice.random_bytes(4).size.
|
12
|
+
it "should produce strings of a given length" do
|
13
|
+
Keybox::RandomDevice.random_bytes(4).size.should == 4
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
Proc.new {Keybox::RandomDevice.default = "/tmp/junk" }.
|
16
|
+
it "should raise exception when given an invalid device" do
|
17
|
+
Proc.new {Keybox::RandomDevice.default = "/tmp/junk" }.should raise_error( ArgumentError)
|
18
18
|
end
|
19
19
|
|
20
|
-
|
21
|
-
(Keybox::RandomDevice.default = "/dev/random").
|
20
|
+
it "should be able to assign a new default source" do
|
21
|
+
(Keybox::RandomDevice.default = "/dev/random").should == "/dev/random"
|
22
22
|
Keybox::RandomDevice.default = "/dev/urandom"
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
|
26
|
+
describe "a random device instance" do
|
27
|
+
before(:each) do
|
28
28
|
@random_device = Keybox::RandomDevice.new
|
29
29
|
end
|
30
|
-
|
31
|
-
@random_device.source.
|
30
|
+
it "should have a source" do
|
31
|
+
@random_device.source.should == "/dev/urandom"
|
32
32
|
end
|
33
33
|
|
34
|
-
|
35
|
-
@random_device.random_bytes.
|
34
|
+
it "should produce strings" do
|
35
|
+
@random_device.random_bytes.should be_an_instance_of(String)
|
36
36
|
end
|
37
37
|
|
38
|
-
|
39
|
-
@random_device.random_bytes(20).size.
|
38
|
+
it "should produce strings of a given length" do
|
39
|
+
@random_device.random_bytes(20).size.should == 20
|
40
40
|
end
|
41
41
|
|
42
|
-
|
42
|
+
it "should default to the RandomDevice default when given an invalid device " do
|
43
43
|
rd = Keybox::RandomDevice.new("/tmp/bad-random-device")
|
44
|
-
rd.source.
|
44
|
+
rd.source.should == Keybox::RandomDevice.default
|
45
45
|
end
|
46
46
|
|
47
|
-
|
47
|
+
it "should accept a valid readable device" do
|
48
48
|
rd = Keybox::RandomDevice.new("/dev/random")
|
49
|
-
rd.source.
|
49
|
+
rd.source.should == "/dev/random"
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
|
-
|
54
|
-
|
53
|
+
describe "a random source class " do
|
54
|
+
before(:each) do
|
55
55
|
@random_source_class = mock("JunkRandomSource")
|
56
56
|
@random_source_class.should_receive("random_bytes").at_least(0).times
|
57
57
|
end
|
58
|
-
|
59
|
-
Keybox::RandomSource.source.
|
58
|
+
it "should have a default" do
|
59
|
+
Keybox::RandomSource.source.should_not == nil
|
60
60
|
end
|
61
61
|
|
62
|
-
|
63
|
-
lambda { Keybox::RandomSource.source = String }.
|
62
|
+
it "invalid default class should throw exception " do
|
63
|
+
lambda { Keybox::RandomSource.source = String }.should raise_error(ArgumentError)
|
64
64
|
end
|
65
65
|
|
66
|
-
|
67
|
-
(Keybox::RandomSource.source = @random_source_class).
|
68
|
-
Keybox::RandomSource.source_classes.
|
66
|
+
it "valid class should allow default to be set" do
|
67
|
+
(Keybox::RandomSource.source = @random_source_class).should == @random_source_class
|
68
|
+
Keybox::RandomSource.source_classes.should have(3).entries
|
69
69
|
Keybox::RandomSource.source_classes.delete(@random_source_class)
|
70
|
-
Keybox::RandomSource.source_classes.
|
71
|
-
Keybox::RandomSource.source.
|
70
|
+
Keybox::RandomSource.source_classes.should have(2).entries
|
71
|
+
Keybox::RandomSource.source.should == ::Keybox::RandomDevice
|
72
72
|
end
|
73
73
|
|
74
|
-
|
74
|
+
it "rand with no parameters should return a value between 0 and 1" do
|
75
75
|
r = Keybox::RandomSource.rand
|
76
|
-
r.
|
76
|
+
r.should >= 0.0
|
77
|
+
r.should < 1.0
|
77
78
|
end
|
78
79
|
|
79
|
-
|
80
|
+
it "rand with parameters should return an integer value between 0 and that value" do
|
80
81
|
r = Keybox::RandomSource.rand(42)
|
81
|
-
r.
|
82
|
-
r.
|
82
|
+
r.should be_a_kind_of(Integer)
|
83
|
+
r.should < 42
|
83
84
|
end
|
84
85
|
end
|
85
86
|
|
86
|
-
|
87
|
-
|
87
|
+
describe "a randomzier instance" do
|
88
|
+
before(:each) do
|
88
89
|
@randomizer = Keybox::Randomizer.new
|
89
90
|
@hash = { :stuff => "stuff", :things => "things" }
|
90
91
|
@array = ["foo", "bar", "baz" ]
|
91
92
|
end
|
92
|
-
|
93
|
-
@randomizer.random_source.
|
93
|
+
it "should have a default random source" do
|
94
|
+
@randomizer.random_source.should_not == nil
|
94
95
|
end
|
95
96
|
|
96
|
-
|
97
|
-
lambda { r = Keybox::Randomizer.new(Array) }.
|
97
|
+
it "giving an invalid default random source should raise an exception" do
|
98
|
+
lambda { r = Keybox::Randomizer.new(Array) }.should raise_error(ArgumentError)
|
98
99
|
end
|
99
100
|
|
100
|
-
|
101
|
-
lambda { @randomizer.pick_count_from(@hash) }.
|
101
|
+
it "picking from a non-array should raise an exception" do
|
102
|
+
lambda { @randomizer.pick_count_from(@hash) }.should raise_error(ArgumentError)
|
102
103
|
end
|
103
104
|
|
104
|
-
|
105
|
-
@randomizer.pick_one_from(@array)
|
106
|
-
@array.include?(x)
|
107
|
-
end
|
105
|
+
it "picking one from an array should be okay" do
|
106
|
+
@array.should be_include(@randomizer.pick_one_from(@array))
|
108
107
|
end
|
109
108
|
|
110
|
-
|
111
|
-
@randomizer.pick_count_from(@array,3).
|
109
|
+
it "picking N from an array should result in an array" do
|
110
|
+
@randomizer.pick_count_from(@array,3).should have(3).entries
|
112
111
|
@randomizer.pick_count_from(@array,9).each do |arg|
|
113
|
-
@array.
|
112
|
+
@array.should be_include(arg)
|
114
113
|
end
|
115
114
|
end
|
116
115
|
end
|
@@ -6,8 +6,8 @@ require 'openssl'
|
|
6
6
|
require 'tempfile'
|
7
7
|
require 'yaml'
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
describe 'a storage container' do
|
10
|
+
before(:each) do
|
11
11
|
@passphrase = "i love ruby"
|
12
12
|
@keybox_file = Tempfile.new("keybox").path
|
13
13
|
@testing_file = "/tmp/testing.yml"
|
@@ -17,54 +17,64 @@ context 'a storage container' do
|
|
17
17
|
@container.save
|
18
18
|
end
|
19
19
|
|
20
|
-
|
20
|
+
after(:each) do
|
21
21
|
File.unlink(@testing_file) if File.exists?(@testing_file)
|
22
22
|
File.unlink(@keybox_file) if File.exists?(@keybox_file)
|
23
23
|
end
|
24
24
|
|
25
|
-
|
26
|
-
@container.uuid.
|
25
|
+
it 'should have a uuid' do
|
26
|
+
@container.uuid.to_s.length.should == 36
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
@container.key_digest.
|
29
|
+
it 'should have a valid key ' do
|
30
|
+
@container.key_digest.length.should == 64
|
31
31
|
end
|
32
32
|
|
33
|
-
|
33
|
+
it 'should save correctly to a file' do
|
34
34
|
@container.save(@testing_file)
|
35
|
-
File.size(@testing_file).
|
35
|
+
File.size(@testing_file).should > 0
|
36
36
|
end
|
37
37
|
|
38
|
-
|
38
|
+
it "should load correctly from a file" do
|
39
39
|
@container.save(@testing_file)
|
40
40
|
new_container = Keybox::Storage::Container.new(@passphrase,@testing_file)
|
41
41
|
new_container.should_be_not_modified
|
42
42
|
new_container.uuid.should == @container.uuid
|
43
43
|
end
|
44
44
|
|
45
|
-
|
45
|
+
it "should validate passphrase" do
|
46
46
|
nc = Keybox::Storage::Container.new("i love ruby", @keybox_file)
|
47
47
|
nc.save(@testing_file)
|
48
|
-
nc.key_digest.
|
49
|
-
lambda { Keybox::Storage::Container.new("i hate ruby", @testing_file) }.
|
48
|
+
nc.key_digest.should == @container.key_digest
|
49
|
+
lambda { Keybox::Storage::Container.new("i hate ruby", @testing_file) }.should raise_error(Keybox::ValidationError)
|
50
50
|
|
51
51
|
end
|
52
52
|
|
53
|
-
|
53
|
+
it "url accounts should have the correct password after save" do
|
54
54
|
@container.save(@testing_file)
|
55
55
|
new_container = Keybox::Storage::Container.new(@passphrase, @testing_file)
|
56
56
|
recs = new_container.find_by_url("nytimes")
|
57
|
-
new_container.records.size.
|
58
|
-
recs.size.
|
57
|
+
new_container.records.size.should == 2
|
58
|
+
recs.size.should == 1
|
59
59
|
recs[0].password.should == "2f85a2e2f"
|
60
60
|
end
|
61
61
|
|
62
|
-
|
62
|
+
it "can find matching records" do
|
63
63
|
matches = @container.find(/times/)
|
64
|
-
matches.size.
|
64
|
+
matches.size.should == 1
|
65
65
|
end
|
66
66
|
|
67
|
-
|
67
|
+
it "can find matching records - case insensitive via regex input" do
|
68
|
+
matches = @container.find(/Times/)
|
69
|
+
matches.size.should == 1
|
70
|
+
end
|
71
|
+
|
72
|
+
it "can find matching records - case insensitive via string input" do
|
73
|
+
matches = @container.find("Times")
|
74
|
+
matches.size.should == 1
|
75
|
+
end
|
76
|
+
|
77
|
+
it "changing the password is safe" do
|
68
78
|
@container.save(@testing_file)
|
69
79
|
copy_of_container= Keybox::Storage::Container.new(@passphrase, @testing_file)
|
70
80
|
times_1 = copy_of_container.find_by_url("nytimes").first
|
@@ -73,27 +83,27 @@ context 'a storage container' do
|
|
73
83
|
@container.save(@keybox_file)
|
74
84
|
@container = Keybox::Storage::Container.new("I love ruby too!", @keybox_file)
|
75
85
|
times_2 = @container.find_by_url("nytimes").first
|
76
|
-
times_1.
|
86
|
+
times_1.should == times_2
|
77
87
|
end
|
78
88
|
|
79
|
-
|
80
|
-
@container.modified?.
|
89
|
+
it "should not be modified upon load" do
|
90
|
+
@container.modified?.should == false
|
81
91
|
end
|
82
92
|
|
83
|
-
|
93
|
+
it "a modified db can be detected" do
|
84
94
|
l1 = @container.find("localhost").first
|
85
95
|
l1.username = "new username"
|
86
|
-
@container.modified?.
|
96
|
+
@container.modified?.should == true
|
87
97
|
end
|
88
98
|
|
89
|
-
|
99
|
+
it "deleting an item should modify the container" do
|
90
100
|
ll = @container.find("localhost").first
|
91
101
|
@container.delete(ll)
|
92
|
-
@container.modified?.
|
102
|
+
@container.modified?.should == true
|
93
103
|
end
|
94
104
|
|
95
|
-
|
96
|
-
@container.size.
|
97
|
-
@container.length.
|
105
|
+
it "able to see how many items are in the container" do
|
106
|
+
@container.size.should == 2
|
107
|
+
@container.length.should == 2
|
98
108
|
end
|
99
109
|
end
|