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/CHANGES
CHANGED
@@ -1,4 +1,14 @@
|
|
1
1
|
= keybox Changelog
|
2
|
+
=== Version 1.1.1
|
3
|
+
|
4
|
+
* update all tests to use latest RSpec syntax
|
5
|
+
* Fixed Bug [#8231] storage::container.find() does not work for anything but AccountEntry classes
|
6
|
+
* Fixed Bug [#8330] finding user home directory may be wrong
|
7
|
+
* Fixed Bug [#9827] Password field on add screen can be deleted
|
8
|
+
* Fixed Bug [#10639] search is case sensitive
|
9
|
+
* Fixed Bug [#11684] apostrophe's in additional information cause errors
|
10
|
+
* Updated to using HighLine 1.2.9 (fixes Bug #9827)
|
11
|
+
|
2
12
|
=== Version 1.1.0
|
3
13
|
|
4
14
|
* keybox now uses HighLine for terminal input/output
|
data/lib/keybox.rb
CHANGED
@@ -4,7 +4,7 @@ module Keybox
|
|
4
4
|
APP_DATA_DIR = File.join(APP_ROOT_DIR,"data").freeze
|
5
5
|
APP_VENDOR_DIR = File.join(APP_ROOT_DIR,"vendor").freeze
|
6
6
|
|
7
|
-
VERSION = [1,1,
|
7
|
+
VERSION = [1,1,1].freeze
|
8
8
|
AUTHOR = "Jeremy Hinegardner".freeze
|
9
9
|
AUTHOR_EMAIL= "jeremy@hinegardner.org".freeze
|
10
10
|
HOMEPAGE = "http://keybox.rubyforge.org".freeze
|
@@ -27,6 +27,15 @@ module Keybox
|
|
27
27
|
attr_reader :stdin
|
28
28
|
attr_reader :highline
|
29
29
|
|
30
|
+
class << self
|
31
|
+
# thank you Jamis - from Capistrano
|
32
|
+
def home_directory # :nodoc:
|
33
|
+
ENV["HOME"] ||
|
34
|
+
(ENV["HOMEPATH"] && "#{ENV["HOMEDRIVE"]}#{ENV["HOMEPATH"]}") ||
|
35
|
+
"/"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
30
39
|
def initialize(argv = [])
|
31
40
|
# make sure we have an empty array, we could be
|
32
41
|
# initially passed nil explicitly
|
@@ -124,6 +133,7 @@ module Keybox
|
|
124
133
|
error_version_help
|
125
134
|
@highline.say "Keybox Base Application. Doing nothing but output this line."
|
126
135
|
end
|
136
|
+
|
127
137
|
end
|
128
138
|
end
|
129
139
|
end
|
@@ -16,7 +16,7 @@ module Keybox
|
|
16
16
|
attr_accessor :actions
|
17
17
|
attr_reader :db
|
18
18
|
|
19
|
-
DEFAULT_DIRECTORY = File.join(
|
19
|
+
DEFAULT_DIRECTORY = File.join(home_directory,".keybox")
|
20
20
|
DEFAULT_DB = File.join(DEFAULT_DIRECTORY,"database.yaml")
|
21
21
|
DEFAULT_CONFIG = File.join(DEFAULT_DIRECTORY,"config.yaml")
|
22
22
|
DEFAULT_COLOR_SCHEME = :dark_bg
|
@@ -352,7 +352,7 @@ module Keybox
|
|
352
352
|
columns << t.ljust(lengths[f])
|
353
353
|
end
|
354
354
|
cdata = columns.join(" " * 4)
|
355
|
-
@highline.say("<%= color('#{line_number}',:line_number) %> <%= color(
|
355
|
+
@highline.say("<%= color('#{line_number}',:line_number) %> <%= color(%Q{#{cdata}},'#{color}') %>")
|
356
356
|
end
|
357
357
|
else
|
358
358
|
hsay "No matching records were found.", :information
|
@@ -373,18 +373,18 @@ module Keybox
|
|
373
373
|
next if value.length == 0
|
374
374
|
|
375
375
|
name_out = name.rjust(max_name_length)
|
376
|
-
@highline.say("<%= color(
|
376
|
+
@highline.say("<%= color(%Q{#{name_out}}, :name) %> <%= color(':',:separator) %> ")
|
377
377
|
|
378
378
|
if match.private_field?(name) then
|
379
379
|
@highline.ask(
|
380
|
-
"<%= color(
|
380
|
+
"<%= color(%Q{#{value}},:private) %> <%= color('(press any key).', :prompt) %> "
|
381
381
|
) do |q|
|
382
382
|
q.overwrite = true
|
383
383
|
q.echo = false
|
384
384
|
q.character = true
|
385
385
|
end
|
386
386
|
|
387
|
-
@highline.say("<%= color(
|
387
|
+
@highline.say("<%= color(%Q{#{name_out}}, :name) %> <%= color(':',:separator) %> <%= color('#{'*' * 20}', :private) %>")
|
388
388
|
else
|
389
389
|
hsay value, :value
|
390
390
|
end
|
data/lib/keybox/highline_util.rb
CHANGED
@@ -47,9 +47,10 @@ module Keybox
|
|
47
47
|
|
48
48
|
#
|
49
49
|
# Prompt for input, returning what was typed. Options can be
|
50
|
-
# passed
|
51
|
-
#
|
52
|
-
#
|
50
|
+
# passed in.
|
51
|
+
#
|
52
|
+
# If echo is false, then '*' is printed out for each character
|
53
|
+
# typed in. If it is any other character then that is output instead.
|
53
54
|
#
|
54
55
|
# If validate is set to true, then it will prompt twice and make
|
55
56
|
# sure that the two values match
|
@@ -65,15 +66,11 @@ module Keybox
|
|
65
66
|
validate = options[:validate] || false
|
66
67
|
|
67
68
|
until validated do
|
68
|
-
line = @highline.ask("<%= color(
|
69
|
-
# ensure we are at the beginning of the line
|
70
|
-
@stdout.print "\r"
|
69
|
+
line = @highline.ask("<%= color(%Q{#{original_prompt.rjust(width)}},:prompt) %> : ") { |q| q.echo = echo }
|
71
70
|
|
72
71
|
# if we are validating then prompt again to validate
|
73
72
|
if validate then
|
74
|
-
v = @highline.ask("<%= color(
|
75
|
-
# ensure we are at the beginning of the line
|
76
|
-
@stdout.print "\r"
|
73
|
+
v = @highline.ask("<%= color(%Q{#{validation_prompt.rjust(width)}}, :prompt) %> : ") { |q| q.echo = echo }
|
77
74
|
|
78
75
|
# line on some terminals
|
79
76
|
if v != line then
|
@@ -13,14 +13,14 @@ module Keybox
|
|
13
13
|
# The container of the Keybox records. The Container itself is
|
14
14
|
# a Keybox::Storage::Record with a few extra methods.
|
15
15
|
#
|
16
|
-
# A instance of a Container is created with a
|
16
|
+
# A instance of a Container is created with a passphrase and a
|
17
17
|
# path to a file. The passphrase can be anything that has a
|
18
18
|
# to_s method.
|
19
19
|
#
|
20
20
|
# container = Keybox::Storage::Container.new("i love ruby", "/tmp/database.yml")
|
21
21
|
#
|
22
22
|
# This will load from the given file with the given passphrase
|
23
|
-
# if the file exists, or it will
|
23
|
+
# if the file exists, or it will initialize the container to
|
24
24
|
# accept records.
|
25
25
|
#
|
26
26
|
# The records are held decrypted in memory, so keep that in mind
|
@@ -30,7 +30,7 @@ module Keybox
|
|
30
30
|
#
|
31
31
|
# record = Keybox::Storage::Record.new
|
32
32
|
# record.field1 = "data"
|
33
|
-
# record.
|
33
|
+
# record.field2 = "some more data"
|
34
34
|
#
|
35
35
|
# container << record
|
36
36
|
#
|
@@ -215,10 +215,15 @@ module Keybox
|
|
215
215
|
# regexp will only be matched against those fields
|
216
216
|
#
|
217
217
|
def find(search_string,restricted_to = nil)
|
218
|
-
|
218
|
+
case search_string
|
219
|
+
when Regexp
|
220
|
+
regex = Regexp.new(search_string.source,search_string.options | Regexp::IGNORECASE)
|
221
|
+
else
|
222
|
+
regex = Regexp.new(search_string.to_s,Regexp::IGNORECASE)
|
223
|
+
end
|
219
224
|
matches = []
|
220
225
|
@records.each do |record|
|
221
|
-
restricted_to = restricted_to || ( record.
|
226
|
+
restricted_to = restricted_to || ( record.data_member_names - %w(password) )
|
222
227
|
record.data_members.each_pair do |k,v|
|
223
228
|
if regex.match(v) and restricted_to.include?(k.to_s) then
|
224
229
|
matches << record
|
@@ -49,6 +49,12 @@ module Keybox
|
|
49
49
|
@modified
|
50
50
|
end
|
51
51
|
|
52
|
+
# an array of the data member names
|
53
|
+
def data_member_names
|
54
|
+
@data_members.keys.collect { |n| n.to_s }
|
55
|
+
end
|
56
|
+
|
57
|
+
|
52
58
|
# this is here so that after this class has been serialized
|
53
59
|
# to a file the container can mark it as clean. The class
|
54
60
|
# should take care of marking itself dirty.
|
data/spec/base_app_spec.rb
CHANGED
@@ -1,55 +1,53 @@
|
|
1
1
|
require 'keybox'
|
2
2
|
require 'keybox/application/base'
|
3
3
|
|
4
|
-
|
4
|
+
describe "Keybox Base Application" do
|
5
5
|
|
6
|
-
|
6
|
+
it "nil argv should do nothing" do
|
7
7
|
kba = Keybox::Application::Base.new(nil)
|
8
|
-
kba.error_message.
|
8
|
+
kba.error_message.should == nil
|
9
9
|
end
|
10
10
|
|
11
|
-
|
11
|
+
it "executing with no args should have output on stdout" do
|
12
12
|
kba = Keybox::Application::Base.new(nil)
|
13
13
|
kba.set_io(StringIO.new,StringIO.new,StringIO.new)
|
14
14
|
kba.run
|
15
|
-
kba.stdout.string.size.
|
15
|
+
kba.stdout.string.size.should > 0
|
16
16
|
end
|
17
17
|
|
18
|
-
|
19
|
-
specify "invalid options set the error message, exit 1 and have output on stderr" do
|
18
|
+
it "invalid options set the error message, exit 1 and have output on stderr" do
|
20
19
|
kba = Keybox::Application::Base.new(["--invalid-option"])
|
21
20
|
kba.set_io(StringIO.new,StringIO.new,StringIO.new)
|
22
21
|
begin
|
23
22
|
kba.run
|
24
23
|
rescue SystemExit => se
|
25
|
-
kba.error_message.
|
26
|
-
kba.stderr.string.
|
27
|
-
kba.stdout.string.size.
|
24
|
+
kba.error_message.should =~ /Try.*--help/m
|
25
|
+
kba.stderr.string.should =~ /Try.*--help/m
|
26
|
+
kba.stdout.string.size.should == 0
|
28
27
|
se.status.should == 1
|
29
28
|
end
|
30
29
|
end
|
31
30
|
|
32
|
-
|
31
|
+
it "help has output on stdout and exits 0" do
|
33
32
|
kba = Keybox::Application::Base.new(["--h"])
|
34
33
|
kba.set_io(StringIO.new,StringIO.new,StringIO.new)
|
35
34
|
begin
|
36
35
|
kba.run
|
37
36
|
rescue SystemExit => se
|
38
|
-
se.status.
|
39
|
-
kba.stdout.string.length.
|
37
|
+
se.status.should == 0
|
38
|
+
kba.stdout.string.length.should > 0
|
40
39
|
end
|
41
40
|
end
|
42
41
|
|
43
|
-
|
42
|
+
it "version has output on stdout and exits 0" do
|
44
43
|
kba = Keybox::Application::Base.new(["--ver"])
|
45
44
|
kba.set_io(StringIO.new,StringIO.new,StringIO.new)
|
46
45
|
begin
|
47
46
|
kba.run
|
48
47
|
rescue SystemExit => se
|
49
|
-
se.status.
|
50
|
-
kba.stdout.string.length.
|
48
|
+
se.status.should == 0
|
49
|
+
kba.stdout.string.length.should > 0
|
51
50
|
end
|
52
51
|
end
|
53
|
-
|
54
52
|
end
|
55
53
|
|
data/spec/convert_csv_spec.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
require 'tempfile'
|
2
2
|
require 'keybox'
|
3
3
|
require 'keybox/convert/csv'
|
4
|
-
|
5
|
-
|
4
|
+
describe "CSV Convert class" do
|
5
|
+
before(:each) do
|
6
6
|
@import_csv = Tempfile.new("keybox_import.csv")
|
7
7
|
@import_csv.puts "title,hostname,username,password,additional_info"
|
8
8
|
@import_csv.puts "example host,host.example.com,guest,mysecretpassword,use this account only for honeybots"
|
9
9
|
@import_csv.puts "example site,http://www.example.com,guest,mywebpassword,web forum login"
|
10
|
+
@import_csv.puts "example site,http://www.example.com,guest,mywebpassword,web forum login's information"
|
10
11
|
@import_csv.close
|
11
12
|
|
12
13
|
@bad_import_csv = Tempfile.new("keybox_bad_header.csv")
|
@@ -19,28 +20,29 @@ context "CSV Convert class" do
|
|
19
20
|
|
20
21
|
end
|
21
22
|
|
22
|
-
|
23
|
+
after(:each) do
|
23
24
|
@import_csv.unlink
|
24
25
|
@bad_import_csv.unlink
|
25
26
|
@export_csv.unlink
|
26
27
|
end
|
27
28
|
|
28
|
-
|
29
|
+
it "able to load records from a file" do
|
29
30
|
entries = Keybox::Convert::CSV.from_file(@import_csv.path)
|
30
|
-
entries.size.
|
31
|
-
entries[0].hostname.
|
32
|
-
entries[1].password.
|
31
|
+
entries.size.should == 3
|
32
|
+
entries[0].hostname.should == "host.example.com"
|
33
|
+
entries[1].password.should == "mywebpassword"
|
34
|
+
entries[2].additional_info.should == "web forum login's information"
|
33
35
|
end
|
34
36
|
|
35
|
-
|
36
|
-
lambda { Keybox::Convert::CSV.from_file(@bad_import_csv.path) }.
|
37
|
+
it "throws error if the header is bad" do
|
38
|
+
lambda { Keybox::Convert::CSV.from_file(@bad_import_csv.path) }.should raise_error(Keybox::ValidationError)
|
37
39
|
end
|
38
40
|
|
39
|
-
|
41
|
+
it "able to write to a csv file" do
|
40
42
|
entries = Keybox::Convert::CSV.from_file(@import_csv.path)
|
41
43
|
Keybox::Convert::CSV.to_file(entries,@export_csv.path)
|
42
44
|
@export_csv.open
|
43
45
|
data = @export_csv.read
|
44
|
-
data.size.
|
46
|
+
data.size.should > 0
|
45
47
|
end
|
46
48
|
end
|
data/spec/entry_spec.rb
CHANGED
@@ -1,62 +1,62 @@
|
|
1
1
|
require 'keybox'
|
2
|
-
|
3
|
-
|
2
|
+
describe "Account Entry" do
|
3
|
+
it "fields get set correctly" do
|
4
4
|
k = Keybox::AccountEntry.new("a test title", "user")
|
5
|
-
k.username.
|
6
|
-
k.title.
|
5
|
+
k.username.should == "user"
|
6
|
+
k.title.should == "a test title"
|
7
7
|
end
|
8
8
|
|
9
|
-
|
9
|
+
it "fields can be accessed" do
|
10
10
|
k = Keybox::AccountEntry.new("a test title", "user")
|
11
|
-
k.fields.
|
12
|
-
k.fields.
|
13
|
-
k.fields.
|
11
|
+
k.fields.should be_include("title")
|
12
|
+
k.fields.should be_include("username")
|
13
|
+
k.fields.should be_include("additional_info")
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
it "fields can be private or visible" do
|
17
17
|
k = Keybox::AccountEntry.new("a test title", "user")
|
18
|
-
k.private_fields.size.
|
19
|
-
k.visible_field?("title").
|
18
|
+
k.private_fields.size.should == 0
|
19
|
+
k.visible_field?("title").should == true
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
describe "Host Account" do
|
24
|
+
it "fields get set correctly" do
|
25
25
|
ha = Keybox::HostAccountEntry.new("a title", "host", "user", "password")
|
26
|
-
ha.title.
|
27
|
-
ha.username.
|
28
|
-
ha.hostname.
|
29
|
-
ha.password.
|
26
|
+
ha.title.should == "a title"
|
27
|
+
ha.username.should == "user"
|
28
|
+
ha.hostname.should == "host"
|
29
|
+
ha.password.should == "password"
|
30
30
|
end
|
31
31
|
|
32
|
-
|
32
|
+
it "password is displayable, private and non-visible" do
|
33
33
|
ha = Keybox::HostAccountEntry.new("a title", "host", "user", "password")
|
34
|
-
ha.display_fields.
|
35
|
-
ha.private_fields.
|
36
|
-
ha.visible_fields.
|
34
|
+
ha.display_fields.should be_include("password")
|
35
|
+
ha.private_fields.should be_include("password")
|
36
|
+
ha.visible_fields.should_not be_include("password")
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
|
41
|
-
|
40
|
+
describe "URL Account" do
|
41
|
+
it "fields get set correctly" do
|
42
42
|
urla = Keybox::URLAccountEntry.new("url title", "http://www.example.com", "someuser")
|
43
|
-
urla.title.
|
44
|
-
urla.url.
|
45
|
-
urla.username.
|
43
|
+
urla.title.should == "url title"
|
44
|
+
urla.url.should == "http://www.example.com"
|
45
|
+
urla.username.should == "someuser"
|
46
46
|
end
|
47
47
|
|
48
|
-
|
48
|
+
it "password hash is used" do
|
49
49
|
container = Keybox::Storage::Container.new("i love ruby", "/tmp/junk.yml")
|
50
50
|
urla = Keybox::URLAccountEntry.new("url title", "http://www.example.com", "someuser")
|
51
51
|
container << urla
|
52
|
-
urla.password.
|
52
|
+
urla.password.should == "589c0d91d"
|
53
53
|
end
|
54
54
|
|
55
|
-
|
55
|
+
it "there is no password storage field, but there a private password field" do
|
56
56
|
urla = Keybox::URLAccountEntry.new("url title", "http://www.example.com", "someuser")
|
57
|
-
urla.fields.
|
58
|
-
urla.private_fields.
|
59
|
-
urla.private_field?("password").
|
57
|
+
urla.fields.should_not be_include("password")
|
58
|
+
urla.private_fields.should be_include("password")
|
59
|
+
urla.private_field?("password").should == true
|
60
60
|
end
|
61
61
|
|
62
62
|
end
|
data/spec/keybox_app_spec.rb
CHANGED
@@ -2,8 +2,8 @@ require 'tempfile'
|
|
2
2
|
require 'keybox'
|
3
3
|
require 'keybox/application/password_safe'
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
describe "Keybox Password Safe Application" do
|
6
|
+
before(:each) do
|
7
7
|
|
8
8
|
@passphrase = "i love ruby"
|
9
9
|
@testing_db = Tempfile.new("kps_db.yml")
|
@@ -12,13 +12,16 @@ context "Keybox Password Safe Application" do
|
|
12
12
|
container = Keybox::Storage::Container.new(@passphrase, @testing_db.path)
|
13
13
|
container << Keybox::HostAccountEntry.new("test account","localhost","guest", "rubyrocks")
|
14
14
|
container << Keybox::URLAccountEntry.new("example site", "http://www.example.com", "rubyhacker")
|
15
|
+
apos = Keybox::HostAccountEntry.new("a title","hostname","login", "password")
|
16
|
+
apos.additional_info = "Someone's additional information"
|
17
|
+
container << apos
|
15
18
|
container.save
|
16
|
-
container.save("/tmp/jjh-db.yml")
|
17
19
|
|
18
20
|
@import_csv = Tempfile.new("keybox_import.csv")
|
19
21
|
@import_csv.puts "title,hostname,username,password,additional_info"
|
20
22
|
@import_csv.puts "example host,host.example.com,guest,mysecretpassword,use this account only for honeybots"
|
21
23
|
@import_csv.puts "example site,http://www.example.com,guest,mywebpassword,web forum login"
|
24
|
+
@import_csv.puts "example site,http://www.example.com,guest,mywebpassword,web forum's login"
|
22
25
|
@import_csv.close
|
23
26
|
|
24
27
|
@bad_import_csv = Tempfile.new("keybox_bad_header.csv")
|
@@ -31,7 +34,7 @@ context "Keybox Password Safe Application" do
|
|
31
34
|
|
32
35
|
end
|
33
36
|
|
34
|
-
|
37
|
+
after(:each) do
|
35
38
|
@testing_db.unlink
|
36
39
|
@testing_cfg.unlink
|
37
40
|
@import_csv.unlink
|
@@ -40,50 +43,50 @@ context "Keybox Password Safe Application" do
|
|
40
43
|
|
41
44
|
end
|
42
45
|
|
43
|
-
|
46
|
+
it "nil argv should do nothing" do
|
44
47
|
kps = Keybox::Application::PasswordSafe.new
|
45
|
-
kps.error_message.
|
48
|
+
kps.error_message.should == nil
|
46
49
|
end
|
47
50
|
|
48
|
-
|
51
|
+
it "executing with no args should have output on stdout" do
|
49
52
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path])
|
50
53
|
kps.set_io(StringIO.new(@passphrase),StringIO.new,StringIO.new)
|
51
54
|
kps.run
|
52
|
-
kps.stdout.string.size.
|
55
|
+
kps.stdout.string.size.should > 0
|
53
56
|
end
|
54
57
|
|
55
|
-
|
58
|
+
it "general options get set correctly" do
|
56
59
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path, "--debug", "--no-use-hash-for-url"])
|
57
60
|
kps.merge_options
|
58
|
-
kps.options.db_file.
|
59
|
-
kps.options.config_file.
|
60
|
-
kps.options.debug.
|
61
|
-
kps.options.use_password_hash_for_url.
|
61
|
+
kps.options.db_file.should == @testing_db.path
|
62
|
+
kps.options.config_file.should == @testing_cfg.path
|
63
|
+
kps.options.debug.should == true
|
64
|
+
kps.options.use_password_hash_for_url.should == false
|
62
65
|
end
|
63
66
|
|
64
|
-
|
67
|
+
it "more than one command options is an error" do
|
65
68
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path, "--add", "account", "--edit", "account"])
|
66
69
|
kps.set_io(StringIO.new,StringIO.new,StringIO.new)
|
67
70
|
begin
|
68
71
|
kps.run
|
69
72
|
rescue SystemExit => se
|
70
|
-
kps.error_message.
|
71
|
-
kps.stderr.string.
|
72
|
-
se.status.
|
73
|
+
kps.error_message.should =~ /Only one of/m
|
74
|
+
kps.stderr.string.should =~ /Only one of/m
|
75
|
+
se.status.should == 1
|
73
76
|
end
|
74
77
|
end
|
75
78
|
|
76
|
-
|
79
|
+
it "space separated words are okay for names" do
|
77
80
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path, "--add", "An Example"])
|
78
81
|
prompted_values = [@passphrase, "An example"] + %w(example.com someuser apassword apassword noinfo yes)
|
79
82
|
stdin = StringIO.new(prompted_values.join("\n"))
|
80
83
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
81
84
|
kps.run
|
82
|
-
kps.db.records.size.
|
85
|
+
kps.db.records.size.should == 4
|
83
86
|
end
|
84
87
|
|
85
88
|
|
86
|
-
|
89
|
+
it "invalid options set the error message, exit 1 and have output on stderr" do
|
87
90
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path,
|
88
91
|
"-c", @testing_cfg.path,
|
89
92
|
"--invalid-option"])
|
@@ -91,83 +94,83 @@ context "Keybox Password Safe Application" do
|
|
91
94
|
begin
|
92
95
|
kps.run
|
93
96
|
rescue SystemExit => se
|
94
|
-
kps.error_message.
|
95
|
-
kps.stderr.string.
|
96
|
-
kps.stdout.string.size.
|
97
|
+
kps.error_message.should =~ /Try.*--help/m
|
98
|
+
kps.stderr.string.should =~ /Try.*--help/m
|
99
|
+
kps.stdout.string.size.should == 0
|
97
100
|
se.status.should == 1
|
98
101
|
end
|
99
102
|
end
|
100
103
|
|
101
|
-
|
104
|
+
it "help has output on stdout and exits 0" do
|
102
105
|
kps = Keybox::Application::PasswordSafe.new(["--h"])
|
103
106
|
kps.set_io(StringIO.new,StringIO.new,StringIO.new)
|
104
107
|
begin
|
105
108
|
kps.run
|
106
109
|
rescue SystemExit => se
|
107
|
-
se.status.
|
108
|
-
kps.stdout.string.length.
|
110
|
+
se.status.should == 0
|
111
|
+
kps.stdout.string.length.should > 0
|
109
112
|
end
|
110
113
|
end
|
111
114
|
|
112
|
-
|
115
|
+
it "version has output on stdout and exits 0" do
|
113
116
|
kps = Keybox::Application::PasswordSafe.new(["--ver"])
|
114
117
|
kps.set_io(StringIO.new,StringIO.new,StringIO.new)
|
115
118
|
begin
|
116
119
|
kps.run
|
117
120
|
rescue SystemExit => se
|
118
|
-
se.status.
|
119
|
-
kps.stdout.string.length.
|
121
|
+
se.status.should == 0
|
122
|
+
kps.stdout.string.length.should > 0
|
120
123
|
end
|
121
124
|
end
|
122
125
|
|
123
|
-
|
126
|
+
it "prompted for password twice to create database initially" do
|
124
127
|
File.unlink(@testing_db.path)
|
125
128
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path])
|
126
129
|
stdin = StringIO.new([@passphrase,@passphrase].join("\n"))
|
127
130
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
128
131
|
kps.run
|
129
|
-
kps.db.records.size.
|
130
|
-
kps.stdout.string.
|
131
|
-
kps.stdout.string.
|
132
|
+
kps.db.records.size.should == 0
|
133
|
+
kps.stdout.string.should =~ /Creating initial database./m
|
134
|
+
kps.stdout.string.should =~ /Initial Password for/m
|
132
135
|
end
|
133
136
|
|
134
|
-
|
137
|
+
it "file can be opened with password" do
|
135
138
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path])
|
136
139
|
stdin = StringIO.new(@passphrase + "\n")
|
137
140
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
138
141
|
kps.run
|
139
|
-
kps.db.records.size.
|
142
|
+
kps.db.records.size.should == 3
|
140
143
|
end
|
141
144
|
|
142
|
-
|
145
|
+
it "adding an entry to the database works" do
|
143
146
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path, "--add", "example.com"])
|
144
147
|
prompted_values = [@passphrase] + %w(example.com example.com someuser apassword apassword noinfo yes)
|
145
148
|
stdin = StringIO.new(prompted_values.join("\n"))
|
146
149
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
147
150
|
kps.run
|
148
|
-
kps.db.records.size.
|
151
|
+
kps.db.records.size.should == 4
|
149
152
|
end
|
150
153
|
|
151
|
-
|
154
|
+
it "editing an entry in the database works" do
|
152
155
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path, "--edit", "localhost"])
|
153
156
|
prompted_values = [@passphrase] + %w(yes example.com example.com someother anewpassword anewpassword someinfo yes)
|
154
157
|
stdin = StringIO.new(prompted_values.join("\n"))
|
155
158
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
156
159
|
kps.run
|
157
|
-
kps.db.records.size.
|
158
|
-
kps.db.find("someother")[0].additional_info.
|
160
|
+
kps.db.records.size.should == 3
|
161
|
+
kps.db.find("someother")[0].additional_info.should == "someinfo"
|
159
162
|
end
|
160
163
|
|
161
|
-
|
164
|
+
it "add a url entry to the database" do
|
162
165
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path, "--use-hash-for-url", "--add", "http://www.example.com"])
|
163
166
|
prompted_values = [@passphrase] + %w(www.example.com http://www.example.com someuser noinfo yes)
|
164
167
|
stdin = StringIO.new(prompted_values.join("\n"))
|
165
168
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
166
169
|
kps.run
|
167
|
-
kps.db.records.size.
|
170
|
+
kps.db.records.size.should == 4
|
168
171
|
end
|
169
172
|
|
170
|
-
|
173
|
+
it "double prompting on failed password for entry to the database works" do
|
171
174
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path,
|
172
175
|
"-c", @testing_cfg.path,
|
173
176
|
"--add", "example.com"])
|
@@ -175,125 +178,125 @@ context "Keybox Password Safe Application" do
|
|
175
178
|
stdin = StringIO.new(prompted_values.join("\n"))
|
176
179
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
177
180
|
kps.run
|
178
|
-
kps.db.records.size.
|
181
|
+
kps.db.records.size.should == 4
|
179
182
|
end
|
180
183
|
|
181
|
-
|
184
|
+
it "able to delete an entry" do
|
182
185
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path, "--delete", "example"])
|
183
186
|
prompted_values = [@passphrase] + %w(Yes)
|
184
187
|
stdin = StringIO.new(prompted_values.join("\n"))
|
185
188
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
186
189
|
kps.run
|
187
|
-
kps.db.records.size.
|
188
|
-
kps.stdout.string.
|
190
|
+
kps.db.records.size.should == 2
|
191
|
+
kps.stdout.string.should =~ /example' deleted/
|
189
192
|
end
|
190
193
|
|
191
|
-
|
194
|
+
it "able to cancel deletion" do
|
192
195
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path, "--delete", "example"])
|
193
196
|
prompted_values = [@passphrase] + %w(No)
|
194
197
|
stdin = StringIO.new(prompted_values.join("\n"))
|
195
198
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
196
199
|
kps.run
|
197
|
-
kps.db.records.size.
|
198
|
-
kps.stdout.string.
|
200
|
+
kps.db.records.size.should == 3
|
201
|
+
kps.stdout.string.should =~ /example' deleted/
|
199
202
|
end
|
200
203
|
|
201
|
-
|
204
|
+
it "list all the entries" do
|
202
205
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path, "--list"])
|
203
206
|
stdin = StringIO.new(@passphrase)
|
204
207
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
205
208
|
kps.run
|
206
|
-
kps.stdout.string.
|
209
|
+
kps.stdout.string.should =~ /2./m
|
207
210
|
end
|
208
211
|
|
209
|
-
|
212
|
+
it "listing no entries found" do
|
210
213
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path, "--list", "nothing"])
|
211
214
|
stdin = StringIO.new(@passphrase)
|
212
215
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
213
216
|
kps.run
|
214
|
-
kps.stdout.string.
|
217
|
+
kps.stdout.string.should =~ /No matching records were found./
|
215
218
|
end
|
216
219
|
|
217
|
-
|
220
|
+
it "showing no entries found" do
|
218
221
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path, "--show", "nothing"])
|
219
222
|
stdin = StringIO.new(@passphrase)
|
220
223
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
221
224
|
kps.run
|
222
|
-
kps.stdout.string.
|
225
|
+
kps.stdout.string.should =~ /No matching records were found./
|
223
226
|
end
|
224
227
|
|
225
228
|
|
226
|
-
|
229
|
+
it "show all the entries" do
|
227
230
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path, "--show"])
|
228
|
-
stdin = StringIO.new([@passphrase, "", ""].join("\n"))
|
231
|
+
stdin = StringIO.new([@passphrase, "", "", ""].join("\n"))
|
229
232
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
230
233
|
kps.run
|
231
|
-
kps.stdout.string.
|
234
|
+
kps.stdout.string.should =~ /2./m
|
232
235
|
end
|
233
236
|
|
234
|
-
|
237
|
+
it "changing master password works" do
|
235
238
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path, "--master-password"])
|
236
239
|
stdin = StringIO.new([@passphrase, "I really love ruby.", "I really love ruby."].join("\n"))
|
237
240
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
238
241
|
kps.run
|
239
|
-
kps.stdout.string.
|
242
|
+
kps.stdout.string.should =~ /New master password set/m
|
240
243
|
end
|
241
244
|
|
242
|
-
|
245
|
+
it "master password must be non-zero" do
|
243
246
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path, "--master-password"])
|
244
247
|
stdin = StringIO.new([@passphrase, "", ""].join("\n"))
|
245
248
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
246
249
|
begin
|
247
250
|
kps.run
|
248
251
|
rescue SystemExit => se
|
249
|
-
kps.stdout.string.
|
250
|
-
se.status.
|
252
|
+
kps.stdout.string.should =~ /Passphrase is not strong enough./m
|
253
|
+
se.status.should == 1
|
251
254
|
end
|
252
255
|
end
|
253
256
|
|
254
|
-
|
257
|
+
it "importing from a valid csv file" do
|
255
258
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path,"-i", @import_csv.path])
|
256
259
|
stdin = StringIO.new([@passphrase, @passphrase].join("\n"))
|
257
260
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
258
261
|
kps.run
|
259
|
-
kps.stdout.string.
|
262
|
+
kps.stdout.string.should =~ /Imported \d* records from/m
|
260
263
|
end
|
261
264
|
|
262
|
-
|
265
|
+
it "Error message give on invalid imported csv" do
|
263
266
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path,"-i", @bad_import_csv.path])
|
264
267
|
stdin = StringIO.new([@passphrase, @passphrase].join("\n"))
|
265
268
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
266
269
|
begin
|
267
270
|
kps.run
|
268
271
|
rescue SystemExit => se
|
269
|
-
kps.stdout.string.
|
270
|
-
se.status.
|
272
|
+
kps.stdout.string.should =~ /Error: There must be a header on the CSV /m
|
273
|
+
se.status.should == 1
|
271
274
|
end
|
272
275
|
end
|
273
276
|
|
274
|
-
|
277
|
+
it "able to export to a csv" do
|
275
278
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path,"-x", @export_csv.path])
|
276
279
|
stdin = StringIO.new([@passphrase, @passphrase].join("\n"))
|
277
280
|
kps.set_io(stdin,StringIO.new,StringIO.new)
|
278
281
|
kps.run
|
279
|
-
kps.stdout.string.
|
282
|
+
kps.stdout.string.should =~ /Exported \d* records to/m
|
280
283
|
end
|
281
284
|
|
282
|
-
|
285
|
+
it "able to turn off color schemes" do
|
283
286
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path,"--color","none"])
|
284
287
|
kps.set_io(StringIO.new(@passphrase),StringIO.new,StringIO.new)
|
285
288
|
kps.run
|
286
|
-
kps.options.color_scheme.
|
289
|
+
kps.options.color_scheme.should == :none
|
287
290
|
end
|
288
291
|
|
289
|
-
|
292
|
+
it "an invalid color scheme results in a no color scheme" do
|
290
293
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path,"--color","dne"])
|
291
294
|
kps.set_io(StringIO.new(@passphrase),StringIO.new,StringIO.new)
|
292
295
|
kps.run
|
293
|
-
kps.options.color_scheme.
|
296
|
+
kps.options.color_scheme.should == :none
|
294
297
|
end
|
295
298
|
|
296
|
-
|
299
|
+
it "an incomplete color scheme results in an error message and then 'none' color scheme" do
|
297
300
|
bad_color_scheme = { :bad => [:bold, :white, :on_magenta] }
|
298
301
|
File.open("/tmp/test.color_scheme.yaml", "w+") { |f| f.write(bad_color_scheme.to_yaml) }
|
299
302
|
kps = Keybox::Application::PasswordSafe.new(["-f", @testing_db.path, "-c", @testing_cfg.path,"--color","test"])
|
@@ -301,7 +304,11 @@ context "Keybox Password Safe Application" do
|
|
301
304
|
kps.run
|
302
305
|
|
303
306
|
File.unlink("/tmp/test.color_scheme.yaml")
|
304
|
-
kps.stdout.string.
|
305
|
-
kps.options.color_scheme.
|
307
|
+
kps.stdout.string.should =~ /It is missing the following items/m
|
308
|
+
kps.options.color_scheme.should == :none
|
309
|
+
end
|
310
|
+
|
311
|
+
it "should have a valid home directory" do
|
312
|
+
File.dirname(Keybox::Application::PasswordSafe::DEFAULT_DIRECTORY).size.should > 0
|
306
313
|
end
|
307
314
|
end
|