keybox 1.0.0
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 +14 -0
- data/COPYING +22 -0
- data/README +132 -0
- data/bin/keybox +18 -0
- data/bin/kpg +19 -0
- data/data/chargrams.txt +8432 -0
- data/lib/keybox.rb +29 -0
- data/lib/keybox/application/base.rb +114 -0
- data/lib/keybox/application/password_generator.rb +131 -0
- data/lib/keybox/application/password_safe.rb +410 -0
- data/lib/keybox/cipher.rb +6 -0
- data/lib/keybox/convert.rb +1 -0
- data/lib/keybox/convert/csv.rb +96 -0
- data/lib/keybox/digest.rb +13 -0
- data/lib/keybox/entry.rb +200 -0
- data/lib/keybox/error.rb +5 -0
- data/lib/keybox/password_hash.rb +33 -0
- data/lib/keybox/randomizer.rb +193 -0
- data/lib/keybox/storage.rb +2 -0
- data/lib/keybox/storage/container.rb +307 -0
- data/lib/keybox/storage/record.rb +103 -0
- data/lib/keybox/string_generator.rb +194 -0
- data/lib/keybox/term_io.rb +163 -0
- data/lib/keybox/uuid.rb +86 -0
- data/spec/base_app_spec.rb +56 -0
- data/spec/convert_csv_spec.rb +46 -0
- data/spec/entry_spec.rb +63 -0
- data/spec/keybox_app_spec.rb +268 -0
- data/spec/kpg_app_spec.rb +132 -0
- data/spec/password_hash_spec.rb +11 -0
- data/spec/randomizer_spec.rb +116 -0
- data/spec/storage_container_spec.rb +99 -0
- data/spec/storage_record_spec.rb +63 -0
- data/spec/string_generator_spec.rb +114 -0
- data/spec/uuid_spec.rb +74 -0
- metadata +83 -0
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'keybox'
|
2
|
+
require 'keybox/application/password_generator'
|
3
|
+
|
4
|
+
context "Keybox Password Generator Application" do
|
5
|
+
setup do
|
6
|
+
end
|
7
|
+
|
8
|
+
specify "nil argv should do nothing" do
|
9
|
+
kpg = Keybox::Application::PasswordGenerator.new(nil)
|
10
|
+
kpg.error_message.should_be nil
|
11
|
+
end
|
12
|
+
|
13
|
+
specify "invalid options set the error message, exit 1 and have output on stderr" do
|
14
|
+
kpg = Keybox::Application::PasswordGenerator.new(["--invalid-option"])
|
15
|
+
kpg.stderr = StringIO.new
|
16
|
+
begin
|
17
|
+
kpg.run
|
18
|
+
rescue SystemExit => se
|
19
|
+
kpg.error_message.should_satisfy { |msg| msg =~ /Try.*--help/m }
|
20
|
+
kpg.stderr.string.should_satisfy { |msg| msg =~ /Try.*--help/m }
|
21
|
+
se.status.should == 1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
specify "can set the algorithm" do
|
26
|
+
kpg = Keybox::Application::PasswordGenerator.new(["--alg", "pron"])
|
27
|
+
kpg.stdout = StringIO.new
|
28
|
+
kpg.run
|
29
|
+
kpg.options.algorithm.should == :pronounceable
|
30
|
+
end
|
31
|
+
|
32
|
+
specify "can specify the number of passwords created " do
|
33
|
+
kpg = Keybox::Application::PasswordGenerator.new(["--num", "4"])
|
34
|
+
kpg.stdout = StringIO.new
|
35
|
+
kpg.run
|
36
|
+
kpg.options.number_to_generate.should_eql 4
|
37
|
+
kpg.stdout.string.split(/\s+/).size.should == 4
|
38
|
+
end
|
39
|
+
|
40
|
+
specify "help has output on stdout and exits 0" do
|
41
|
+
kpg = Keybox::Application::PasswordGenerator.new(["--h"])
|
42
|
+
kpg.stdout = StringIO.new
|
43
|
+
begin
|
44
|
+
kpg.run
|
45
|
+
rescue SystemExit => se
|
46
|
+
se.status.should_eql 0
|
47
|
+
kpg.stdout.string.length.should_be > 0
|
48
|
+
end
|
49
|
+
kpg.stdout.string.should_satisfy { |msg| msg =~ /--help/m }
|
50
|
+
end
|
51
|
+
|
52
|
+
specify "version has output on stdout and exits 0" do
|
53
|
+
kpg = Keybox::Application::PasswordGenerator.new(["--version"])
|
54
|
+
kpg.stdout = StringIO.new
|
55
|
+
begin
|
56
|
+
kpg.run
|
57
|
+
rescue SystemExit => se
|
58
|
+
se.status.should_eql 0
|
59
|
+
end
|
60
|
+
kpg.stdout.string.should_satisfy { |msg| msg =~ /version 1.0.0/m }
|
61
|
+
end
|
62
|
+
|
63
|
+
specify "minimum length can be set and all generated passwords will have length >= minimum length" do
|
64
|
+
kpg = Keybox::Application::PasswordGenerator.new(["--min", "4"])
|
65
|
+
kpg.stdout = StringIO.new
|
66
|
+
kpg.run
|
67
|
+
|
68
|
+
kpg.options.min_length.should_eql 4
|
69
|
+
kpg.stdout.string.split("\n").each do |pass|
|
70
|
+
pass.length.should_satisfy { |s| s >= kpg.options.min_length }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
specify "maximum length can be set and all generated passwords will have length <= maximum length" do
|
75
|
+
kpg = Keybox::Application::PasswordGenerator.new(["--max", "4", "--min", "3"])
|
76
|
+
kpg.stdout = StringIO.new
|
77
|
+
kpg.run
|
78
|
+
|
79
|
+
kpg.options.max_length.should_eql 4
|
80
|
+
kpg.stdout.string.split("\n").each do |pass|
|
81
|
+
pass.length.should_satisfy { |s| s <= 4 }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
specify "setting an invalid required symbol set exits 1 and outputs data on stderr" do
|
86
|
+
kpg = Keybox::Application::PasswordGenerator.new(["--req","bunk"])
|
87
|
+
kpg.stderr = StringIO.new
|
88
|
+
begin
|
89
|
+
kpg.run
|
90
|
+
rescue SystemExit => se
|
91
|
+
kpg.error_message.should_satisfy { |msg| msg =~ /Try.*--help/m }
|
92
|
+
kpg.stderr.string.should_satisfy { |msg| msg =~ /Try.*--help/m }
|
93
|
+
se.status.should == 1
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
specify "setting an invalid use symbol set exits 1 and outputs data on stderr" do
|
99
|
+
kpg = Keybox::Application::PasswordGenerator.new(["--use","bunk"])
|
100
|
+
kpg.stderr = StringIO.new
|
101
|
+
begin
|
102
|
+
kpg.run
|
103
|
+
rescue SystemExit => se
|
104
|
+
kpg.error_message.should_satisfy { |msg| msg =~ /Try.*--help/m }
|
105
|
+
kpg.stderr.string.should_satisfy { |msg| msg =~ /Try.*--help/m }
|
106
|
+
se.status.should == 1
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
specify "setting an valid use symbol works" do
|
112
|
+
kpg = Keybox::Application::PasswordGenerator.new(["--use","l"])
|
113
|
+
kpg.stdout = StringIO.new
|
114
|
+
kpg.run
|
115
|
+
kpg.options.use_symbols.should_include Keybox::SymbolSet::LOWER_ASCII
|
116
|
+
kpg.stdout.string.split(/\s+/).size.should == 6
|
117
|
+
end
|
118
|
+
|
119
|
+
specify "setting an valid required symbol works" do
|
120
|
+
kpg = Keybox::Application::PasswordGenerator.new(["--req","l"])
|
121
|
+
kpg.stdout = StringIO.new
|
122
|
+
kpg.run
|
123
|
+
kpg.options.require_symbols.should_include Keybox::SymbolSet::LOWER_ASCII
|
124
|
+
kpg.stdout.string.split(/\s+/).size.should == 6
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
|
129
|
+
|
130
|
+
|
131
|
+
end
|
132
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'keybox'
|
2
|
+
context "PasswordHash" do
|
3
|
+
setup do
|
4
|
+
@pwd_hash = Keybox::PasswordHash.new("i love ruby")
|
5
|
+
end
|
6
|
+
|
7
|
+
specify "creates string for password" do
|
8
|
+
pwd = @pwd_hash.password_for_url("http://www.nytimes.com")
|
9
|
+
pwd.should == "2f85a2e2f"
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'keybox/randomizer'
|
2
|
+
|
3
|
+
context "a random device class" do
|
4
|
+
specify "should have a default source" do
|
5
|
+
Keybox::RandomDevice.default.should_eql "/dev/urandom"
|
6
|
+
end
|
7
|
+
|
8
|
+
specify "should produce strings" do
|
9
|
+
Keybox::RandomDevice.random_bytes.should_be_an_instance_of(String)
|
10
|
+
end
|
11
|
+
|
12
|
+
specify "should produce strings of a given length" do
|
13
|
+
Keybox::RandomDevice.random_bytes(4).size.should_eql 4
|
14
|
+
end
|
15
|
+
|
16
|
+
specify "should raise exception when given an invalid device" do
|
17
|
+
Proc.new {Keybox::RandomDevice.default = "/tmp/junk" }.should_raise ArgumentError
|
18
|
+
end
|
19
|
+
|
20
|
+
specify "should be able to assign a new default source" do
|
21
|
+
(Keybox::RandomDevice.default = "/dev/random").should_eql "/dev/random"
|
22
|
+
Keybox::RandomDevice.default = "/dev/urandom"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "a random device instance" do
|
27
|
+
setup do
|
28
|
+
@random_device = Keybox::RandomDevice.new
|
29
|
+
end
|
30
|
+
specify "should have a source" do
|
31
|
+
@random_device.source.should_eql "/dev/urandom"
|
32
|
+
end
|
33
|
+
|
34
|
+
specify "should produce strings" do
|
35
|
+
@random_device.random_bytes.should_be_an_instance_of(String)
|
36
|
+
end
|
37
|
+
|
38
|
+
specify "should produce strings of a given length" do
|
39
|
+
@random_device.random_bytes(20).size.should_eql 20
|
40
|
+
end
|
41
|
+
|
42
|
+
specify "should default to the RandomDevice default when given an invalid device " do
|
43
|
+
rd = Keybox::RandomDevice.new("/tmp/bad-random-device")
|
44
|
+
rd.source.should_eql Keybox::RandomDevice.default
|
45
|
+
end
|
46
|
+
|
47
|
+
specify "should accept a valid readable device" do
|
48
|
+
rd = Keybox::RandomDevice.new("/dev/random")
|
49
|
+
rd.source.should_eql "/dev/random"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "a random source class " do
|
54
|
+
setup do
|
55
|
+
@random_source_class = mock("JunkRandomSource")
|
56
|
+
@random_source_class.should_receive("random_bytes").at_least(0).times
|
57
|
+
end
|
58
|
+
specify "should have a default" do
|
59
|
+
Keybox::RandomSource.source.should_not_equal nil
|
60
|
+
end
|
61
|
+
|
62
|
+
specify "invalid default class should throw exception " do
|
63
|
+
lambda { Keybox::RandomSource.source = String }.should_raise ArgumentError
|
64
|
+
end
|
65
|
+
|
66
|
+
specify "valid class should allow default to be set" do
|
67
|
+
(Keybox::RandomSource.source = @random_source_class).should_eql @random_source_class
|
68
|
+
Keybox::RandomSource.source_classes.should_have(3).entries
|
69
|
+
Keybox::RandomSource.source_classes.delete(@random_source_class)
|
70
|
+
Keybox::RandomSource.source_classes.should_have(2).entries
|
71
|
+
Keybox::RandomSource.source.should_eql ::Keybox::RandomDevice
|
72
|
+
end
|
73
|
+
|
74
|
+
specify "rand with no parameters should return a value between 0 and 1" do
|
75
|
+
r = Keybox::RandomSource.rand
|
76
|
+
r.should_satisfy { |arg| arg >= 0.0 and arg < 1.0 }
|
77
|
+
end
|
78
|
+
|
79
|
+
specify "rand with parameters should return an integer value between 0 and that value" do
|
80
|
+
r = Keybox::RandomSource.rand(42)
|
81
|
+
r.should_be_a_kind_of(Integer)
|
82
|
+
r.should_be < 42
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "a randomzier instance" do
|
87
|
+
setup do
|
88
|
+
@randomizer = Keybox::Randomizer.new
|
89
|
+
@hash = { :stuff => "stuff", :things => "things" }
|
90
|
+
@array = ["foo", "bar", "baz" ]
|
91
|
+
end
|
92
|
+
specify "should have a default random source" do
|
93
|
+
@randomizer.random_source.should_not_be nil
|
94
|
+
end
|
95
|
+
|
96
|
+
specify "giving an invalid default random source should raise an exception" do
|
97
|
+
lambda { r = Keybox::Randomizer.new(Array) }.should_raise ArgumentError
|
98
|
+
end
|
99
|
+
|
100
|
+
specify "picking from a non-array should raise an exception" do
|
101
|
+
lambda { @randomizer.pick_count_from(@hash) }.should_raise ArgumentError
|
102
|
+
end
|
103
|
+
|
104
|
+
specify "picking one from an array should be okay" do
|
105
|
+
@randomizer.pick_one_from(@array).should_satisfy do |x|
|
106
|
+
@array.include?(x)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
specify "picking N from an array should result in an array" do
|
111
|
+
@randomizer.pick_count_from(@array,3).should_have(3).entries
|
112
|
+
@randomizer.pick_count_from(@array,9).each do |arg|
|
113
|
+
@array.should_include(arg)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'keybox'
|
2
|
+
require 'keybox/storage'
|
3
|
+
require 'keybox/error'
|
4
|
+
require 'keybox/entry'
|
5
|
+
require 'openssl'
|
6
|
+
require 'tempfile'
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
context 'a storage container' do
|
10
|
+
setup do
|
11
|
+
@passphrase = "i love ruby"
|
12
|
+
@keybox_file = Tempfile.new("keybox").path
|
13
|
+
@testing_file = "/tmp/testing.yml"
|
14
|
+
@container = Keybox::Storage::Container.new(@passphrase, @keybox_file)
|
15
|
+
@container << Keybox::HostAccountEntry.new("test account","localhost","guest", "rubyrocks")
|
16
|
+
@container << Keybox::URLAccountEntry.new("the times", "http://www.nytimes.com", "rubyhacker")
|
17
|
+
@container.save
|
18
|
+
end
|
19
|
+
|
20
|
+
teardown do
|
21
|
+
File.unlink(@testing_file) if File.exists?(@testing_file)
|
22
|
+
File.unlink(@keybox_file) if File.exists?(@keybox_file)
|
23
|
+
end
|
24
|
+
|
25
|
+
specify 'should have a uuid' do
|
26
|
+
@container.uuid.should_satisfy { |uuid| uuid.to_s.length == 36 }
|
27
|
+
end
|
28
|
+
|
29
|
+
specify 'should have a valid key ' do
|
30
|
+
@container.key_digest.should_satisfy { |kd| kd.length == 64 }
|
31
|
+
end
|
32
|
+
|
33
|
+
specify 'should save correctly to a file' do
|
34
|
+
@container.save(@testing_file)
|
35
|
+
File.size(@testing_file).should_satisfy { |s| s > 0 }
|
36
|
+
end
|
37
|
+
|
38
|
+
specify "should load correctly from a file" do
|
39
|
+
@container.save(@testing_file)
|
40
|
+
new_container = Keybox::Storage::Container.new(@passphrase,@testing_file)
|
41
|
+
new_container.should_be_not_modified
|
42
|
+
new_container.uuid.should == @container.uuid
|
43
|
+
end
|
44
|
+
|
45
|
+
specify "should validate passphrase" do
|
46
|
+
nc = Keybox::Storage::Container.new("i love ruby", @keybox_file)
|
47
|
+
nc.save(@testing_file)
|
48
|
+
nc.key_digest.should_eql @container.key_digest
|
49
|
+
lambda { Keybox::Storage::Container.new("i hate ruby", @testing_file) }.should_raise Keybox::ValidationError
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
specify "url accounts should have the correct password after save" do
|
54
|
+
@container.save(@testing_file)
|
55
|
+
new_container = Keybox::Storage::Container.new(@passphrase, @testing_file)
|
56
|
+
recs = new_container.find_by_url("nytimes")
|
57
|
+
new_container.records.size.should_eql 2
|
58
|
+
recs.size.should_eql 1
|
59
|
+
recs[0].password.should == "2f85a2e2f"
|
60
|
+
end
|
61
|
+
|
62
|
+
specify "can find matching records" do
|
63
|
+
matches = @container.find(/times/)
|
64
|
+
matches.size.should_be 1
|
65
|
+
end
|
66
|
+
|
67
|
+
specify "changing the password is safe" do
|
68
|
+
@container.save(@testing_file)
|
69
|
+
copy_of_container= Keybox::Storage::Container.new(@passphrase, @testing_file)
|
70
|
+
times_1 = copy_of_container.find_by_url("nytimes").first
|
71
|
+
|
72
|
+
@container.passphrase = "I love ruby too!"
|
73
|
+
@container.save(@keybox_file)
|
74
|
+
@container = Keybox::Storage::Container.new("I love ruby too!", @keybox_file)
|
75
|
+
times_2 = @container.find_by_url("nytimes").first
|
76
|
+
times_1.should_eql times_2
|
77
|
+
end
|
78
|
+
|
79
|
+
specify "should not be modified upon load" do
|
80
|
+
@container.modified?.should_eql false
|
81
|
+
end
|
82
|
+
|
83
|
+
specify "a modified db can be detected" do
|
84
|
+
l1 = @container.find("localhost").first
|
85
|
+
l1.username = "new username"
|
86
|
+
@container.modified?.should_eql true
|
87
|
+
end
|
88
|
+
|
89
|
+
specify "deleting an item should modify the container" do
|
90
|
+
ll = @container.find("localhost").first
|
91
|
+
@container.delete(ll)
|
92
|
+
@container.modified?.should_eql true
|
93
|
+
end
|
94
|
+
|
95
|
+
specify "able to see how many items are in the container" do
|
96
|
+
@container.size.should_eql 2
|
97
|
+
@container.length.should_eql 2
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'keybox/storage'
|
2
|
+
|
3
|
+
context 'a storage record entry' do
|
4
|
+
setup do
|
5
|
+
@data_fields = %w(title username password url additional_data)
|
6
|
+
end
|
7
|
+
specify 'has a creation date set on instantiation' do
|
8
|
+
e = Keybox::Storage::Record.new
|
9
|
+
e.creation_time.should_be_instance_of(Time)
|
10
|
+
end
|
11
|
+
|
12
|
+
specify "assigning to a non-existant field creates the appropriate member " do
|
13
|
+
e = Keybox::Storage::Record.new
|
14
|
+
e.junk = "junk"
|
15
|
+
e.junk.should == "junk"
|
16
|
+
end
|
17
|
+
|
18
|
+
specify 'default values for non-existant fields is nil' do
|
19
|
+
e = Keybox::Storage::Record.new
|
20
|
+
@data_fields.each do |f|
|
21
|
+
e.send(f).should_be nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
specify "assigning to a field makes the modification time > creation time" do
|
26
|
+
e = Keybox::Storage::Record.new
|
27
|
+
sleep 1
|
28
|
+
e.testing = "testing"
|
29
|
+
e.modification_time.should_satisfy { |m| m > e.creation_time }
|
30
|
+
e.last_access_time.should == e.modification_time
|
31
|
+
end
|
32
|
+
|
33
|
+
specify "reading a field after assignment the access time > modification time " do
|
34
|
+
e = Keybox::Storage::Record.new
|
35
|
+
e.testing = "testing"
|
36
|
+
sleep 1
|
37
|
+
e.testing
|
38
|
+
e.last_access_time.should_satisfy { |la| la > e.creation_time }
|
39
|
+
e.last_access_time.should_satisfy { |la| la > e.modification_time }
|
40
|
+
end
|
41
|
+
|
42
|
+
specify "assigning to a modification, creation or acces_time should raise and exception " do
|
43
|
+
e = Keybox::Storage::Record.new
|
44
|
+
lambda {e.modification_time = Time.now}.should_raise NoMethodError
|
45
|
+
end
|
46
|
+
|
47
|
+
specify "assiging multiple items should raise an argument exception" do
|
48
|
+
e = Keybox::Storage::Record.new
|
49
|
+
lambda {e.send(:stuff=,1,2)}.should_raise ArgumentError
|
50
|
+
end
|
51
|
+
|
52
|
+
specify "calling a method with arguments should raise exception" do
|
53
|
+
e = Keybox::Storage::Record.new
|
54
|
+
lambda {e.stuff(1,2)}.should_raise NoMethodError
|
55
|
+
end
|
56
|
+
|
57
|
+
specify "comparison between records is valid" do
|
58
|
+
e = Keybox::Storage::Record.new
|
59
|
+
f = e.dup
|
60
|
+
e.should_eql e.uuid
|
61
|
+
e.should_eql f
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'keybox'
|
2
|
+
context "string generator" do
|
3
|
+
setup do
|
4
|
+
@generator = Keybox::StringGenerator.new
|
5
|
+
end
|
6
|
+
|
7
|
+
specify "should not be used alone" do
|
8
|
+
lambda { @generator.generate }.should_raise Keybox::KeyboxError
|
9
|
+
end
|
10
|
+
|
11
|
+
specify "cannot have a min length greater than a max length" do
|
12
|
+
@generator.min_length = 90
|
13
|
+
lambda { @generator.generate }.should_raise Keybox::ValidationError
|
14
|
+
@generator.min_length = 8
|
15
|
+
end
|
16
|
+
|
17
|
+
specify "cannot have a max length less than a min length" do
|
18
|
+
@generator.max_length = 2
|
19
|
+
lambda { @generator.generate }.should_raise Keybox::ValidationError
|
20
|
+
@generator.max_length = 10
|
21
|
+
end
|
22
|
+
|
23
|
+
specify "initially there are no chunks" do
|
24
|
+
@generator.chunks.should_have(0).entries
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "chargram generator" do
|
29
|
+
setup do
|
30
|
+
@generator = Keybox::CharGramGenerator.new
|
31
|
+
end
|
32
|
+
|
33
|
+
specify "should have a positive size" do
|
34
|
+
@generator.size.should_be > 26
|
35
|
+
end
|
36
|
+
|
37
|
+
specify "should emit a string with length > 0" do
|
38
|
+
@generator.generate_chunk.size.should_be > 0
|
39
|
+
end
|
40
|
+
|
41
|
+
specify "should emit an array " do
|
42
|
+
@generator.generate_chunk.should_be_instance_of String
|
43
|
+
end
|
44
|
+
|
45
|
+
specify "2 succesive emits should have a common first and last character" do
|
46
|
+
one = @generator.generate_chunk
|
47
|
+
two = @generator.generate_chunk
|
48
|
+
one[-1].should == two[0]
|
49
|
+
end
|
50
|
+
|
51
|
+
specify "2 calls to generate_chunk should have a string that is 1 less than the 2 chunks" do
|
52
|
+
one = @generator.generate_chunk
|
53
|
+
two = @generator.generate_chunk
|
54
|
+
@generator.to_s.length.should == (one.length + two.length - 1)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "SymbolSetGenerator" do
|
59
|
+
setup do
|
60
|
+
@generator = Keybox::SymbolSetGenerator.new
|
61
|
+
end
|
62
|
+
|
63
|
+
specify "symbol sets have the right number or characters" do
|
64
|
+
Keybox::SymbolSetGenerator::ALL.size.should == 92
|
65
|
+
end
|
66
|
+
|
67
|
+
specify "generating chunks should produce an array" do
|
68
|
+
12.times do
|
69
|
+
@generator.generate_chunk
|
70
|
+
end
|
71
|
+
@generator.chunks.should_have(12).entries
|
72
|
+
end
|
73
|
+
|
74
|
+
specify "generate should produce a string" do
|
75
|
+
@generator.generate.should_be_instance_of(String)
|
76
|
+
@generator.to_s.size.should_be > 0
|
77
|
+
end
|
78
|
+
|
79
|
+
specify "generating chunks can be cleared" do
|
80
|
+
@generator.generate
|
81
|
+
@generator.clear
|
82
|
+
@generator.chunks.should_have(0).entries
|
83
|
+
end
|
84
|
+
|
85
|
+
specify "min and max lengths are respected" do
|
86
|
+
@generator.max_length = 25
|
87
|
+
@generator.min_length = 25
|
88
|
+
@generator.generate.size.should_be == 25
|
89
|
+
end
|
90
|
+
|
91
|
+
specify "required sets are utilized" do
|
92
|
+
gen = Keybox::SymbolSetGenerator.new([Keybox::SymbolSet::NUMERAL_ASCII, Keybox::SymbolSet::LOWER_ASCII])
|
93
|
+
gen.required_sets << Keybox::SymbolSet::UPPER_ASCII
|
94
|
+
p = gen.generate
|
95
|
+
gen.required_sets.flatten.uniq.should_include(p[0].chr)
|
96
|
+
end
|
97
|
+
specify "required sets are merged with symbol sets" do
|
98
|
+
gen = Keybox::SymbolSetGenerator.new([Keybox::SymbolSet::NUMERAL_ASCII, Keybox::SymbolSet::LOWER_ASCII])
|
99
|
+
gen.required_sets << Keybox::SymbolSet::UPPER_ASCII
|
100
|
+
gen.required_sets.flatten.uniq.each do |c|
|
101
|
+
gen.symbols.should_include(c)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
specify "generated passwords autoclear" do
|
106
|
+
@generator.generate.should_not == @generator.generate
|
107
|
+
end
|
108
|
+
|
109
|
+
specify "setting min and max should not affect " do
|
110
|
+
g = Keybox::SymbolSetGenerator.new(Keybox::SymbolSet::ALL)
|
111
|
+
g.generate.should_be_instance_of(String)
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|