keyrack 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- data/TODO +4 -0
- data/VERSION +1 -1
- data/features/console.feature +43 -3
- data/features/step_definitions/keyrack_steps.rb +11 -0
- data/lib/keyrack/database.rb +23 -6
- data/lib/keyrack/runner.rb +13 -2
- data/lib/keyrack/ui/console.rb +76 -22
- data/test/keyrack/test_database.rb +28 -0
- data/test/keyrack/test_runner.rb +18 -6
- data/test/keyrack/ui/test_console.rb +170 -123
- metadata +6 -4
data/TODO
ADDED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
data/features/console.feature
CHANGED
@@ -11,7 +11,12 @@ Feature: Console runner
|
|
11
11
|
* I wait a few seconds
|
12
12
|
* the output should contain "Choose storage type:"
|
13
13
|
* I type "filesystem"
|
14
|
-
|
14
|
+
|
15
|
+
* the output should contain "g. New group"
|
16
|
+
* I type "g" to add a new group
|
17
|
+
* the output should contain "Group:"
|
18
|
+
* I type "Social"
|
19
|
+
* the output should contain "n. New entry"
|
15
20
|
* I type "n" to add a new entry
|
16
21
|
* the output should contain "Label:"
|
17
22
|
* I type "Twitter"
|
@@ -23,9 +28,28 @@ Feature: Console runner
|
|
23
28
|
* I type "kittens"
|
24
29
|
* the output should contain "Password (again):"
|
25
30
|
* I type "kittens"
|
26
|
-
* the output should contain "1. Twitter"
|
31
|
+
* the output should contain "1. Twitter [dudeguy]"
|
27
32
|
* the output should also contain "s. Save"
|
28
33
|
* I type "s" to save the database
|
34
|
+
* the output should contain "t. Top level menu"
|
35
|
+
* I type "t"
|
36
|
+
* the output should match /1\. .+Social.+/
|
37
|
+
|
38
|
+
* the output should also contain "n. New entry"
|
39
|
+
* I type "n" to add a new entry
|
40
|
+
* the output should contain "Label:"
|
41
|
+
* I type "Company X"
|
42
|
+
* the output should contain "Username:"
|
43
|
+
* I type "buddypal"
|
44
|
+
* the output should contain "Generate password?"
|
45
|
+
* I type "y" for yes
|
46
|
+
* the output should contain "Sound good? [yn]"
|
47
|
+
* I type "y" for yes
|
48
|
+
* the output should contain "2. Company X [buddypal]"
|
49
|
+
* the output should also contain "s. Save"
|
50
|
+
* I type "s" to save the database
|
51
|
+
|
52
|
+
* the output should contain "q. Quit"
|
29
53
|
* I type "q" to quit
|
30
54
|
* I wait a few seconds
|
31
55
|
* I run keyrack interactively again
|
@@ -33,7 +57,23 @@ Feature: Console runner
|
|
33
57
|
* the output should contain "Keyrack password:"
|
34
58
|
* I type "secret"
|
35
59
|
* I wait a few seconds
|
36
|
-
* the output should
|
60
|
+
* the output should match /1\. .+Social.+/
|
61
|
+
* the output should also contain "2. Company X [buddypal]"
|
62
|
+
* I type "1" for Social
|
63
|
+
* the output should contain "1. Twitter [dudeguy]"
|
37
64
|
* I type "1" for Twitter
|
38
65
|
* my clipboard should contain "kittens"
|
66
|
+
|
67
|
+
* the output should contain "d. Delete entry"
|
68
|
+
* I type "d"
|
69
|
+
* the output should contain "1. Twitter [dudeguy]"
|
70
|
+
* I type "1"
|
71
|
+
* the output should contain "Are you sure?"
|
72
|
+
* I type "y"
|
73
|
+
* the output should contain "t. Top level menu"
|
74
|
+
* I type "t"
|
75
|
+
|
76
|
+
* the output should contain "Main Menu"
|
39
77
|
* I type "q" to quit
|
78
|
+
* the output should contain "Really quit?" (since the database is dirty)
|
79
|
+
* I type "y"
|
@@ -25,6 +25,17 @@ Then /the output should contain "([^"]+)"/ do |expected|
|
|
25
25
|
@output.should include(expected)
|
26
26
|
end
|
27
27
|
|
28
|
+
Then %r{the output should match /([^/]+)/} do |expected|
|
29
|
+
# This won't work for escaped backslashes
|
30
|
+
if @slept
|
31
|
+
@slept = false
|
32
|
+
else
|
33
|
+
sleep 1
|
34
|
+
end
|
35
|
+
@output = @out.read_nonblock(255)
|
36
|
+
@output.should match(Regexp.new(expected))
|
37
|
+
end
|
38
|
+
|
28
39
|
Then /the output should also contain "([^"]+)"/ do |expected|
|
29
40
|
@output.should include(expected)
|
30
41
|
end
|
data/lib/keyrack/database.rb
CHANGED
@@ -8,17 +8,28 @@ module Keyrack
|
|
8
8
|
@dirty = false
|
9
9
|
end
|
10
10
|
|
11
|
-
def add(site, username, password)
|
12
|
-
@data[
|
11
|
+
def add(site, username, password, options = {})
|
12
|
+
hash = options[:group] ? @data[options[:group]] ||= {} : @data
|
13
|
+
hash[site] = { :username => username, :password => password }
|
13
14
|
@dirty = true
|
14
15
|
end
|
15
16
|
|
16
|
-
def get(site)
|
17
|
-
@data[site]
|
17
|
+
def get(site, options = {})
|
18
|
+
(options[:group] ? @data[options[:group]] : @data)[site]
|
18
19
|
end
|
19
20
|
|
20
|
-
def sites
|
21
|
-
@data
|
21
|
+
def sites(options = {})
|
22
|
+
hash = options[:group] ? @data[options[:group]] : @data
|
23
|
+
if hash
|
24
|
+
hash.keys.select { |k| hash[k].keys.include?(:username) }.sort
|
25
|
+
else
|
26
|
+
# new groups are empty
|
27
|
+
[]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def groups
|
32
|
+
@data.keys.reject { |k| @data[k].keys.include?(:username) }.sort
|
22
33
|
end
|
23
34
|
|
24
35
|
def dirty?
|
@@ -32,6 +43,12 @@ module Keyrack
|
|
32
43
|
@dirty = false
|
33
44
|
end
|
34
45
|
|
46
|
+
def delete(site, options = {})
|
47
|
+
hash = options[:group] ? @data[options[:group]] : @data
|
48
|
+
hash.delete(site)
|
49
|
+
@dirty = true
|
50
|
+
end
|
51
|
+
|
35
52
|
private
|
36
53
|
def decrypt
|
37
54
|
data = @store.read
|
data/lib/keyrack/runner.rb
CHANGED
@@ -54,15 +54,26 @@ module Keyrack
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def main_loop
|
57
|
+
options = {}
|
57
58
|
loop do
|
58
|
-
|
59
|
+
choice = @ui.menu(options)
|
60
|
+
|
61
|
+
case choice
|
59
62
|
when :new
|
60
63
|
result = @ui.get_new_entry
|
61
|
-
@database.add(result[:site], result[:username], result[:password])
|
64
|
+
@database.add(result[:site], result[:username], result[:password], options)
|
65
|
+
when :delete
|
66
|
+
@ui.delete_entry(options)
|
67
|
+
when :new_group
|
68
|
+
options = @ui.get_new_group
|
62
69
|
when :save
|
63
70
|
@database.save
|
64
71
|
when :quit
|
65
72
|
break
|
73
|
+
when Hash
|
74
|
+
options = choice
|
75
|
+
when :top
|
76
|
+
options = {}
|
66
77
|
end
|
67
78
|
end
|
68
79
|
end
|
data/lib/keyrack/ui/console.rb
CHANGED
@@ -10,40 +10,72 @@ module Keyrack
|
|
10
10
|
@highline.ask("Keyrack password: ") { |q| q.echo = false }
|
11
11
|
end
|
12
12
|
|
13
|
-
def menu
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
@
|
13
|
+
def menu(options = {})
|
14
|
+
choices = {'n' => :new, 'q' => :quit}
|
15
|
+
index = 1
|
16
|
+
|
17
|
+
if !options[:group]
|
18
|
+
# Can't have subgroups (yet?).
|
19
|
+
@highline.say("=== #{@highline.color("Keyrack Main Menu", :yellow)} ===")
|
20
|
+
@database.groups.each do |group|
|
21
|
+
choices[index.to_s] = {:group => group}
|
22
|
+
@highline.say("% 2d. %s" % [index, @highline.color(group, :green)])
|
23
|
+
index += 1
|
24
|
+
end
|
25
|
+
else
|
26
|
+
@highline.say("===== #{@highline.color(options[:group], :green)} =====")
|
27
|
+
end
|
28
|
+
|
29
|
+
sites = @database.sites(options)
|
30
|
+
sites.each do |site|
|
31
|
+
entry = @database.get(site, options)
|
32
|
+
choices[index.to_s] = entry
|
33
|
+
@highline.say("% 2d. %s [%s]" % [index, site, entry[:username]])
|
34
|
+
index += 1
|
35
|
+
end
|
36
|
+
|
37
|
+
@highline.say(" n. New entry")
|
38
|
+
if !sites.empty?
|
39
|
+
choices['d'] = :delete
|
40
|
+
@highline.say(" d. Delete entry")
|
41
|
+
end
|
42
|
+
if !options[:group]
|
43
|
+
choices['g'] = :new_group
|
44
|
+
@highline.say(" g. New group")
|
45
|
+
else
|
46
|
+
choices['t'] = :top
|
47
|
+
@highline.say(" t. Top level menu")
|
21
48
|
end
|
22
|
-
@highline.say(" n. Add new")
|
23
49
|
if @database.dirty?
|
50
|
+
choices['s'] = :save
|
24
51
|
@highline.say(" s. Save")
|
25
|
-
choices << "s"
|
26
52
|
end
|
27
53
|
@highline.say(" q. Quit")
|
28
|
-
|
54
|
+
answer = @highline.ask(" ? ") { |q| q.in = choices.keys }
|
55
|
+
result = choices[answer]
|
29
56
|
case result
|
30
|
-
when
|
31
|
-
:
|
32
|
-
when "s"
|
33
|
-
:save
|
34
|
-
when "q"
|
35
|
-
if @database.dirty? && !@highline.agree("Really quit? You have unsaved changes! [yn] ")
|
57
|
+
when Symbol
|
58
|
+
if result == :quit && @database.dirty? && !@highline.agree("Really quit? You have unsaved changes! [yn] ")
|
36
59
|
nil
|
37
60
|
else
|
38
|
-
|
61
|
+
result
|
62
|
+
end
|
63
|
+
when Hash
|
64
|
+
if result.has_key?(:group)
|
65
|
+
result
|
66
|
+
else
|
67
|
+
Copier(result[:password])
|
68
|
+
@highline.say("The password has been copied to your clipboard.")
|
69
|
+
nil
|
39
70
|
end
|
40
|
-
else
|
41
|
-
Copier(entries[result.to_i - 1][:password])
|
42
|
-
@highline.say("The password has been copied to your clipboard.")
|
43
|
-
nil
|
44
71
|
end
|
45
72
|
end
|
46
73
|
|
74
|
+
def get_new_group
|
75
|
+
group = @highline.ask("Group: ") { |q| q.validate = /^\w[\w\s]*$/ }
|
76
|
+
{:group => group}
|
77
|
+
end
|
78
|
+
|
47
79
|
def get_new_entry
|
48
80
|
result = {}
|
49
81
|
result[:site] = @highline.ask("Label: ")
|
@@ -103,6 +135,28 @@ module Keyrack
|
|
103
135
|
|
104
136
|
result
|
105
137
|
end
|
138
|
+
|
139
|
+
def delete_entry(options = {})
|
140
|
+
choices = {'c' => :cancel}
|
141
|
+
index = 1
|
142
|
+
@highline.say("Choose entry to delete:")
|
143
|
+
@database.sites(options).each do |site|
|
144
|
+
entry = @database.get(site, options)
|
145
|
+
choices[index.to_s] = {:site => site, :username => entry[:username]}
|
146
|
+
@highline.say("% 2d. %s [%s]" % [index, site, entry[:username]])
|
147
|
+
index += 1
|
148
|
+
end
|
149
|
+
@highline.say(" c. Cancel")
|
150
|
+
|
151
|
+
answer = @highline.ask(" ? ") { |q| q.in = choices.keys }
|
152
|
+
result = choices[answer]
|
153
|
+
if result != :cancel
|
154
|
+
entry = @highline.color("#{result[:site]} [#{result[:username]}]", :red)
|
155
|
+
if @highline.agree("You're about to delete #{entry}. Are you sure? [yn] ")
|
156
|
+
@database.delete(result[:site], options)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
106
160
|
end
|
107
161
|
end
|
108
162
|
end
|
@@ -30,7 +30,16 @@ module Keyrack
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def test_sites
|
33
|
+
@database.add('Blargh', 'dudeguy', 'secret', :group => "Junk")
|
33
34
|
assert_equal(%w{Twitter}, @database.sites)
|
35
|
+
assert_equal(%w{Blargh}, @database.sites(:group => "Junk"))
|
36
|
+
assert_equal([], @database.sites(:group => "New group"))
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_groups
|
40
|
+
assert_equal [], @database.groups
|
41
|
+
@database.add('Blargh', 'dudeguy', 'secret', :group => "Junk")
|
42
|
+
assert_equal %w{Junk}, @database.groups
|
34
43
|
end
|
35
44
|
|
36
45
|
def test_dirty
|
@@ -48,5 +57,24 @@ module Keyrack
|
|
48
57
|
@database.save
|
49
58
|
assert_equal 501, @database.sites.length
|
50
59
|
end
|
60
|
+
|
61
|
+
def test_add_with_top_level_group
|
62
|
+
@database.add('Twitter', 'dudeguy', 'secret', :group => "Social")
|
63
|
+
expected = {:username => 'dudeguy', :password => 'secret'}
|
64
|
+
assert_equal expected, @database.get('Twitter', :group => "Social")
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_delete
|
68
|
+
@database.delete('Twitter')
|
69
|
+
assert_equal [], @database.sites
|
70
|
+
assert @database.dirty?
|
71
|
+
end
|
72
|
+
|
73
|
+
def test_delete_group_entry
|
74
|
+
@database.add('Facebook', 'dudeguy', 'secret', :group => "Social")
|
75
|
+
@database.delete('Facebook', :group => 'Social')
|
76
|
+
assert_equal [], @database.sites(:group => 'Social')
|
77
|
+
assert_equal ['Twitter'], @database.sites
|
78
|
+
end
|
51
79
|
end
|
52
80
|
end
|
data/test/keyrack/test_runner.rb
CHANGED
@@ -5,7 +5,7 @@ module Keyrack
|
|
5
5
|
def setup
|
6
6
|
@console = stub('console', {
|
7
7
|
:get_password => 'secret',
|
8
|
-
:database= => nil, :menu =>
|
8
|
+
:database= => nil, :menu => :quit,
|
9
9
|
:get_new_entry => {:site => "Foo", :username => "bar", :password => "baz"}
|
10
10
|
})
|
11
11
|
UI::Console.stubs(:new).returns(@console)
|
@@ -40,10 +40,23 @@ module Keyrack
|
|
40
40
|
|
41
41
|
@console.expects(:menu).returns(:new).in_sequence(seq)
|
42
42
|
@console.expects(:get_new_entry).returns({:site => "Foo", :username => "bar", :password => "baz"}).in_sequence(seq)
|
43
|
-
@database.expects(:add).with("Foo", "bar", "baz")
|
43
|
+
@database.expects(:add).with("Foo", "bar", "baz", {})
|
44
44
|
@console.expects(:menu).returns(nil).in_sequence(seq)
|
45
45
|
@console.expects(:menu).returns(:save).in_sequence(seq)
|
46
46
|
@database.expects(:save).in_sequence(seq)
|
47
|
+
@console.expects(:menu).returns(:delete).in_sequence(seq)
|
48
|
+
@console.expects(:delete_entry).with({}).in_sequence(seq)
|
49
|
+
@console.expects(:menu).returns(:new_group).in_sequence(seq)
|
50
|
+
@console.expects(:get_new_group).returns(:group => 'Blah').in_sequence(seq)
|
51
|
+
@console.expects(:menu).with(:group => 'Blah').returns(:top).in_sequence(seq)
|
52
|
+
@console.expects(:menu).returns(:group => 'Huge').in_sequence(seq)
|
53
|
+
@console.expects(:menu).with(:group => 'Huge').returns(nil).in_sequence(seq)
|
54
|
+
@console.expects(:menu).with(:group => 'Huge').returns(:new).in_sequence(seq)
|
55
|
+
@console.expects(:get_new_entry).returns({:site => "Bar", :username => "bar", :password => "baz"}).in_sequence(seq)
|
56
|
+
@database.expects(:add).with("Bar", "bar", "baz", :group => 'Huge')
|
57
|
+
@console.expects(:menu).with(:group => "Huge").returns(:delete).in_sequence(seq)
|
58
|
+
@console.expects(:delete_entry).with(:group => 'Huge').in_sequence(seq)
|
59
|
+
@console.expects(:menu).with(:group => 'Huge').returns(:top).in_sequence(seq)
|
47
60
|
@console.expects(:menu).returns(:quit).in_sequence(seq)
|
48
61
|
|
49
62
|
runner = Runner.new(["-d", keyrack_dir])
|
@@ -67,10 +80,9 @@ module Keyrack
|
|
67
80
|
rsa.expects(:public_encrypt).with(dump).returns("encrypted dump")
|
68
81
|
|
69
82
|
# Store setup
|
70
|
-
|
71
|
-
@console.expects(:store_setup).returns('type' => 'filesystem', 'path' => store_path).in_sequence(seq)
|
83
|
+
@console.expects(:store_setup).returns('type' => 'filesystem', 'path' => 'database').in_sequence(seq)
|
72
84
|
store = mock('filesystem store')
|
73
|
-
Store::Filesystem.expects(:new).with('path' =>
|
85
|
+
Store::Filesystem.expects(:new).with('path' => File.join(keyrack_dir, 'database')).returns(store).in_sequence(seq)
|
74
86
|
|
75
87
|
Database.expects(:new).with('foobar', 'barfoo', store).returns(@database).in_sequence(seq)
|
76
88
|
@console.expects(:database=).with(@database).in_sequence(seq)
|
@@ -91,7 +103,7 @@ module Keyrack
|
|
91
103
|
assert File.exist?(expected_config_file)
|
92
104
|
expected_config = {
|
93
105
|
'rsa' => expected_rsa_file, 'aes' => expected_aes_file,
|
94
|
-
'store' => { 'type' => 'filesystem', 'path' =>
|
106
|
+
'store' => { 'type' => 'filesystem', 'path' => File.join(keyrack_dir, 'database') }
|
95
107
|
}
|
96
108
|
assert_equal expected_config, YAML.load_file(expected_config_file)
|
97
109
|
end
|
@@ -4,199 +4,246 @@ module Keyrack
|
|
4
4
|
module UI
|
5
5
|
class TestConsole < Test::Unit::TestCase
|
6
6
|
def setup
|
7
|
-
@database = stub('database', :sites => %w{Twitter}, :dirty? => false) do
|
8
|
-
stubs(:get).with('Twitter').returns({
|
7
|
+
@database = stub('database', :sites => %w{Twitter}, :groups => [], :dirty? => false) do
|
8
|
+
stubs(:get).with('Twitter', {}).returns({
|
9
9
|
:username => 'username', :password => 'password'
|
10
10
|
})
|
11
11
|
end
|
12
|
+
@highline = stub('highline')
|
13
|
+
@highline.stubs(:color).with("Keyrack Main Menu", :yellow).returns("yellowKeyrack Main Menu")
|
14
|
+
@highline.stubs(:say)
|
15
|
+
HighLine.expects(:new).returns(@highline)
|
16
|
+
@console = Console.new
|
12
17
|
end
|
13
18
|
|
14
19
|
def test_select_entry_from_menu
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
highline.expects(:say).with("
|
21
|
-
highline.expects(:say).with("
|
22
|
-
highline.expects(:say).with(" q. Quit")
|
20
|
+
@console.database = @database
|
21
|
+
@highline.expects(:say).with("=== yellowKeyrack Main Menu ===")
|
22
|
+
@highline.expects(:say).with(" 1. Twitter [username]")
|
23
|
+
@highline.expects(:say).with(" n. New entry")
|
24
|
+
@highline.expects(:say).with(" d. Delete entry")
|
25
|
+
@highline.expects(:say).with(" g. New group")
|
26
|
+
@highline.expects(:say).with(" q. Quit")
|
23
27
|
|
24
28
|
question = mock('question')
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
assert_nil console.menu
|
29
|
+
@highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q 1 d g}) }).returns('1')
|
30
|
+
@console.expects(:Copier).with('password')
|
31
|
+
@highline.expects(:say).with("The password has been copied to your clipboard.")
|
32
|
+
assert_nil @console.menu
|
30
33
|
end
|
31
34
|
|
32
35
|
def test_select_new_from_menu
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
36
|
+
@console.database = @database
|
37
|
+
|
38
|
+
# === yellowKeyrack Main Menu ===
|
39
|
+
# 1. Twitter [username]
|
40
|
+
# n. New entry
|
41
|
+
# d. Delete entry
|
42
|
+
# g. New group
|
43
|
+
# q. Quit
|
44
|
+
|
45
|
+
@highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q 1 d g}) }).returns('n')
|
46
|
+
assert_equal :new, @console.menu
|
47
|
+
end
|
37
48
|
|
38
|
-
|
39
|
-
|
40
|
-
|
49
|
+
def test_select_delete_from_menu
|
50
|
+
@console.database = @database
|
51
|
+
|
52
|
+
# === yellowKeyrack Main Menu ===
|
53
|
+
# 1. Twitter [username]
|
54
|
+
# n. New entry
|
55
|
+
# d. Delete entry
|
56
|
+
# g. New group
|
57
|
+
# q. Quit
|
41
58
|
|
42
59
|
question = mock('question')
|
43
|
-
question.expects(:in=).with(%w{n q 1})
|
44
|
-
highline.expects(:ask).yields(question).returns('
|
45
|
-
assert_equal :
|
60
|
+
question.expects(:in=).with(%w{n q 1 d g})
|
61
|
+
@highline.expects(:ask).yields(question).returns('d')
|
62
|
+
assert_equal :delete, @console.menu
|
46
63
|
end
|
47
64
|
|
48
65
|
def test_select_quit_from_menu
|
49
|
-
|
50
|
-
HighLine.expects(:new).returns(highline)
|
51
|
-
console = Console.new
|
52
|
-
console.database = @database
|
66
|
+
@console.database = @database
|
53
67
|
|
54
|
-
|
55
|
-
|
56
|
-
|
68
|
+
# === yellowKeyrack Main Menu ===
|
69
|
+
# 1. Twitter [username]
|
70
|
+
# n. New entry
|
71
|
+
# d. Delete entry
|
72
|
+
# g. New group
|
73
|
+
# q. Quit
|
57
74
|
|
58
|
-
|
59
|
-
|
60
|
-
highline.expects(:ask).yields(question).returns('q')
|
61
|
-
assert_equal :quit, console.menu
|
75
|
+
@highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q 1 d g}) }).returns('q')
|
76
|
+
assert_equal :quit, @console.menu
|
62
77
|
end
|
63
78
|
|
64
79
|
def test_select_quit_from_menu_when_database_is_dirty
|
65
|
-
|
66
|
-
HighLine.expects(:new).returns(highline)
|
67
|
-
console = Console.new
|
68
|
-
console.database = @database
|
80
|
+
@console.database = @database
|
69
81
|
@database.stubs(:dirty?).returns(true)
|
70
82
|
|
71
|
-
highline.expects(:
|
72
|
-
highline.expects(:
|
73
|
-
|
74
|
-
highline.expects(:say).with(" q. Quit")
|
75
|
-
|
76
|
-
question = mock('question', :in= => nil)
|
77
|
-
highline.expects(:ask).yields(question).returns('q')
|
78
|
-
highline.expects(:agree).with("Really quit? You have unsaved changes! [yn] ").returns(false)
|
79
|
-
assert_equal nil, console.menu
|
83
|
+
@highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q 1 d g s}) }).returns('q')
|
84
|
+
@highline.expects(:agree).with("Really quit? You have unsaved changes! [yn] ").returns(false)
|
85
|
+
assert_equal nil, @console.menu
|
80
86
|
end
|
81
87
|
|
82
88
|
def test_select_save_from_menu
|
83
|
-
|
84
|
-
HighLine.expects(:new).returns(highline)
|
85
|
-
console = Console.new
|
86
|
-
console.database = @database
|
89
|
+
@console.database = @database
|
87
90
|
@database.stubs(:dirty?).returns(true)
|
88
91
|
|
89
|
-
highline.expects(:say).with("
|
90
|
-
highline.expects(:
|
91
|
-
|
92
|
-
|
92
|
+
@highline.expects(:say).with(" s. Save")
|
93
|
+
@highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q 1 d g s}) }).returns('s')
|
94
|
+
assert_equal :save, @console.menu
|
95
|
+
end
|
93
96
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
97
|
+
def test_select_group_from_menu
|
98
|
+
@console.database = @database
|
99
|
+
@database.stubs(:groups).returns(["Blargh"])
|
100
|
+
|
101
|
+
@highline.expects(:color).with('Blargh', :green).returns('greenBlargh')
|
102
|
+
@highline.expects(:say).with(" 1. greenBlargh")
|
103
|
+
@highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q 1 2 d g}) }).returns('1')
|
104
|
+
assert_equal({:group => 'Blargh'}, @console.menu)
|
98
105
|
end
|
99
106
|
|
100
|
-
def
|
101
|
-
|
102
|
-
|
103
|
-
|
107
|
+
def test_select_entry_from_group_menu
|
108
|
+
@console.database = @database
|
109
|
+
@database.expects(:sites).with(:group => "Foo").returns(["Facebook"])
|
110
|
+
@database.expects(:get).with('Facebook', :group => "Foo").returns({:username => 'username', :password => 'password'})
|
111
|
+
|
112
|
+
@highline.expects(:color).with("Foo", :green).returns("greenFoo")
|
113
|
+
@highline.expects(:say).with("===== greenFoo =====")
|
114
|
+
@highline.expects(:say).with(" 1. Facebook [username]")
|
115
|
+
@highline.expects(:say).with(" n. New entry")
|
116
|
+
@highline.expects(:say).with(" d. Delete entry")
|
117
|
+
@highline.expects(:say).with(" t. Top level menu")
|
118
|
+
@highline.expects(:say).with(" q. Quit")
|
119
|
+
|
120
|
+
@highline.expects(:ask).yields(mock { expects(:in=).with(%w{n q 1 d t}) }).returns('1')
|
121
|
+
@console.expects(:Copier).with('password')
|
122
|
+
@highline.expects(:say).with("The password has been copied to your clipboard.")
|
123
|
+
assert_nil @console.menu(:group => 'Foo')
|
124
|
+
end
|
104
125
|
|
126
|
+
def test_get_password
|
105
127
|
question = mock('question')
|
106
128
|
question.expects(:echo=).with(false)
|
107
|
-
highline.expects(:ask).with("Keyrack password: ").yields(question).returns("foobar")
|
108
|
-
assert_equal "foobar", console.get_password
|
129
|
+
@highline.expects(:ask).with("Keyrack password: ").yields(question).returns("foobar")
|
130
|
+
assert_equal "foobar", @console.get_password
|
109
131
|
end
|
110
132
|
|
111
133
|
def test_get_new_entry_with_manual_password
|
112
|
-
highline = mock('highline')
|
113
|
-
HighLine.expects(:new).returns(highline)
|
114
|
-
console = Console.new
|
115
|
-
|
116
134
|
seq = sequence("new entry")
|
117
|
-
highline.expects(:ask).with("Label: ").returns("Foo").in_sequence(seq)
|
118
|
-
highline.expects(:ask).with("Username: ").returns("bar").in_sequence(seq)
|
119
|
-
highline.expects(:agree).with("Generate password? [yn] ").returns(false).in_sequence(seq)
|
120
|
-
highline.expects(:ask).with("Password: ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
|
121
|
-
highline.expects(:ask).with("Password (again): ").yields(mock { expects(:echo=).with(false) }).returns("bar").in_sequence(seq)
|
122
|
-
highline.expects(:say).with("Passwords didn't match. Try again!").in_sequence(seq)
|
123
|
-
highline.expects(:ask).with("Password: ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
|
124
|
-
highline.expects(:ask).with("Password (again): ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
|
125
|
-
assert_equal({:site => "Foo", :username => "bar", :password => "baz"}, console.get_new_entry)
|
135
|
+
@highline.expects(:ask).with("Label: ").returns("Foo").in_sequence(seq)
|
136
|
+
@highline.expects(:ask).with("Username: ").returns("bar").in_sequence(seq)
|
137
|
+
@highline.expects(:agree).with("Generate password? [yn] ").returns(false).in_sequence(seq)
|
138
|
+
@highline.expects(:ask).with("Password: ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
|
139
|
+
@highline.expects(:ask).with("Password (again): ").yields(mock { expects(:echo=).with(false) }).returns("bar").in_sequence(seq)
|
140
|
+
@highline.expects(:say).with("Passwords didn't match. Try again!").in_sequence(seq)
|
141
|
+
@highline.expects(:ask).with("Password: ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
|
142
|
+
@highline.expects(:ask).with("Password (again): ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
|
143
|
+
assert_equal({:site => "Foo", :username => "bar", :password => "baz"}, @console.get_new_entry)
|
126
144
|
end
|
127
145
|
|
128
146
|
def test_get_new_entry_generated_password
|
129
|
-
highline = mock('highline')
|
130
|
-
HighLine.expects(:new).returns(highline)
|
131
|
-
console = Console.new
|
132
|
-
|
133
147
|
seq = sequence("new entry")
|
134
|
-
highline.expects(:ask).with("Label: ").returns("Foo").in_sequence(seq)
|
135
|
-
highline.expects(:ask).with("Username: ").returns("bar").in_sequence(seq)
|
136
|
-
highline.expects(:agree).with("Generate password? [yn] ").returns(true).in_sequence(seq)
|
148
|
+
@highline.expects(:ask).with("Label: ").returns("Foo").in_sequence(seq)
|
149
|
+
@highline.expects(:ask).with("Username: ").returns("bar").in_sequence(seq)
|
150
|
+
@highline.expects(:agree).with("Generate password? [yn] ").returns(true).in_sequence(seq)
|
137
151
|
Utils.expects(:generate_password).returns('foobar').in_sequence(seq)
|
138
|
-
highline.expects(:color).with('foobar', :blue).returns('bluefoobar').in_sequence(seq)
|
139
|
-
highline.expects(:agree).with("Generated bluefoobar. Sound good? [yn] ").returns(false).in_sequence(seq)
|
152
|
+
@highline.expects(:color).with('foobar', :blue).returns('bluefoobar').in_sequence(seq)
|
153
|
+
@highline.expects(:agree).with("Generated bluefoobar. Sound good? [yn] ").returns(false).in_sequence(seq)
|
140
154
|
Utils.expects(:generate_password).returns('foobar').in_sequence(seq)
|
141
|
-
highline.expects(:color).with('foobar', :blue).returns('bluefoobar').in_sequence(seq)
|
142
|
-
highline.expects(:agree).with("Generated bluefoobar. Sound good? [yn] ").returns(true).in_sequence(seq)
|
143
|
-
assert_equal({:site => "Foo", :username => "bar", :password => "foobar"}, console.get_new_entry)
|
155
|
+
@highline.expects(:color).with('foobar', :blue).returns('bluefoobar').in_sequence(seq)
|
156
|
+
@highline.expects(:agree).with("Generated bluefoobar. Sound good? [yn] ").returns(true).in_sequence(seq)
|
157
|
+
assert_equal({:site => "Foo", :username => "bar", :password => "foobar"}, @console.get_new_entry)
|
144
158
|
end
|
145
159
|
|
146
160
|
def test_display_first_time_notice
|
147
|
-
highline
|
148
|
-
|
149
|
-
console = Console.new
|
150
|
-
|
151
|
-
highline.expects(:say).with("This looks like your first time using Keyrack. I'll need to ask you a few questions first.")
|
152
|
-
console.display_first_time_notice
|
161
|
+
@highline.expects(:say).with("This looks like your first time using Keyrack. I'll need to ask you a few questions first.")
|
162
|
+
@console.display_first_time_notice
|
153
163
|
end
|
154
164
|
|
155
165
|
def test_rsa_setup
|
156
|
-
highline = mock('highline')
|
157
|
-
HighLine.expects(:new).returns(highline)
|
158
|
-
console = Console.new
|
159
|
-
|
160
166
|
seq = sequence("rsa setup")
|
161
|
-
highline.expects(:ask).with("New passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('huge').in_sequence(seq)
|
162
|
-
highline.expects(:ask).with("Confirm passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('small').in_sequence(seq)
|
163
|
-
highline.expects(:say).with("Passphrases didn't match.").in_sequence(seq)
|
164
|
-
highline.expects(:ask).with("New passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('huge').in_sequence(seq)
|
165
|
-
highline.expects(:ask).with("Confirm passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('huge').in_sequence(seq)
|
167
|
+
@highline.expects(:ask).with("New passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('huge').in_sequence(seq)
|
168
|
+
@highline.expects(:ask).with("Confirm passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('small').in_sequence(seq)
|
169
|
+
@highline.expects(:say).with("Passphrases didn't match.").in_sequence(seq)
|
170
|
+
@highline.expects(:ask).with("New passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('huge').in_sequence(seq)
|
171
|
+
@highline.expects(:ask).with("Confirm passphrase: ").yields(mock{expects(:echo=).with(false)}).returns('huge').in_sequence(seq)
|
166
172
|
expected = {'password' => 'huge', 'path' => 'rsa'}
|
167
|
-
assert_equal expected, console.rsa_setup
|
173
|
+
assert_equal expected, @console.rsa_setup
|
168
174
|
end
|
169
175
|
|
170
176
|
def test_store_setup_for_filesystem
|
171
|
-
highline
|
172
|
-
HighLine.expects(:new).returns(highline)
|
173
|
-
console = Console.new
|
174
|
-
|
175
|
-
highline.expects(:choose).yields(mock {
|
177
|
+
@highline.expects(:choose).yields(mock {
|
176
178
|
expects(:header=).with("Choose storage type:")
|
177
179
|
expects(:choices).with("filesystem", "ssh")
|
178
180
|
}).returns("filesystem")
|
179
181
|
|
180
182
|
expected = {'type' => 'filesystem', 'path' => 'database'}
|
181
|
-
assert_equal expected, console.store_setup
|
183
|
+
assert_equal expected, @console.store_setup
|
182
184
|
end
|
183
185
|
|
184
186
|
def test_store_setup_for_ssh
|
185
|
-
highline = mock('highline')
|
186
|
-
HighLine.expects(:new).returns(highline)
|
187
|
-
console = Console.new
|
188
|
-
|
189
187
|
seq = sequence("store setup")
|
190
|
-
highline.expects(:choose).yields(mock {
|
188
|
+
@highline.expects(:choose).yields(mock {
|
191
189
|
expects(:header=).with("Choose storage type:")
|
192
190
|
expects(:choices).with("filesystem", "ssh")
|
193
191
|
}).returns("ssh").in_sequence(seq)
|
194
|
-
highline.expects(:ask).with("Host: ").returns("example.com").in_sequence(seq)
|
195
|
-
highline.expects(:ask).with("User: ").returns("dudeguy").in_sequence(seq)
|
196
|
-
highline.expects(:ask).with("Remote path: ").returns(".keyrack/database").in_sequence(seq)
|
192
|
+
@highline.expects(:ask).with("Host: ").returns("example.com").in_sequence(seq)
|
193
|
+
@highline.expects(:ask).with("User: ").returns("dudeguy").in_sequence(seq)
|
194
|
+
@highline.expects(:ask).with("Remote path: ").returns(".keyrack/database").in_sequence(seq)
|
197
195
|
|
198
196
|
expected = {'type' => 'ssh', 'host' => 'example.com', 'user' => 'dudeguy', 'path' => '.keyrack/database'}
|
199
|
-
assert_equal expected, console.store_setup
|
197
|
+
assert_equal expected, @console.store_setup
|
198
|
+
end
|
199
|
+
|
200
|
+
def test_get_new_group
|
201
|
+
@highline.expects(:ask).with("Group: ").yields(mock {
|
202
|
+
expects(:validate=).with(/^\w[\w\s]*$/)
|
203
|
+
}).returns("Foo")
|
204
|
+
assert_equal({:group => "Foo"}, @console.get_new_group)
|
205
|
+
end
|
206
|
+
|
207
|
+
def test_delete_entry
|
208
|
+
@console.database = @database
|
209
|
+
@database.stubs(:sites).returns(%w{Twitter Facebook})
|
210
|
+
@database.stubs(:get).with('Facebook', {}).returns({
|
211
|
+
:username => 'username', :password => 'password'
|
212
|
+
})
|
213
|
+
|
214
|
+
seq = sequence("deleting")
|
215
|
+
@highline.expects(:say).with("Choose entry to delete:").in_sequence(seq)
|
216
|
+
@highline.expects(:say).with(" 1. Twitter [username]").in_sequence(seq)
|
217
|
+
@highline.expects(:say).with(" 2. Facebook [username]").in_sequence(seq)
|
218
|
+
@highline.expects(:say).with(" c. Cancel").in_sequence(seq)
|
219
|
+
@highline.expects(:ask).yields(mock {
|
220
|
+
expects(:in=).with(%w{c 1 2})
|
221
|
+
}).returns('1').in_sequence(seq)
|
222
|
+
@highline.expects(:color).with("Twitter [username]", :red).returns("redTwitter").in_sequence(seq)
|
223
|
+
@highline.expects(:agree).with("You're about to delete redTwitter. Are you sure? [yn] ").returns(true).in_sequence(seq)
|
224
|
+
@database.expects(:delete).with("Twitter", {}).in_sequence(seq)
|
225
|
+
@console.delete_entry
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_delete_group_entry
|
229
|
+
@console.database = @database
|
230
|
+
@database.stubs(:sites).returns(%w{Quora Foursquare})
|
231
|
+
@database.stubs(:get).with(kind_of(String), {:group => 'Social'}).returns({
|
232
|
+
:username => 'username', :password => 'password'
|
233
|
+
})
|
234
|
+
|
235
|
+
seq = sequence("deleting")
|
236
|
+
@highline.expects(:say).with("Choose entry to delete:").in_sequence(seq)
|
237
|
+
@highline.expects(:say).with(" 1. Quora [username]").in_sequence(seq)
|
238
|
+
@highline.expects(:say).with(" 2. Foursquare [username]").in_sequence(seq)
|
239
|
+
@highline.expects(:say).with(" c. Cancel").in_sequence(seq)
|
240
|
+
@highline.expects(:ask).yields(mock {
|
241
|
+
expects(:in=).with(%w{c 1 2})
|
242
|
+
}).returns('2').in_sequence(seq)
|
243
|
+
@highline.expects(:color).with("Foursquare [username]", :red).returns("redFoursquare").in_sequence(seq)
|
244
|
+
@highline.expects(:agree).with("You're about to delete redFoursquare. Are you sure? [yn] ").returns(true).in_sequence(seq)
|
245
|
+
@database.expects(:delete).with("Foursquare", :group => 'Social').in_sequence(seq)
|
246
|
+
@console.delete_entry(:group => 'Social')
|
200
247
|
end
|
201
248
|
end
|
202
249
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 0.2.
|
8
|
+
- 1
|
9
|
+
version: 0.2.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Jeremy Stephens
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-01-
|
17
|
+
date: 2011-01-05 00:00:00 -06:00
|
18
18
|
default_executable: keyrack
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -134,6 +134,7 @@ extensions: []
|
|
134
134
|
extra_rdoc_files:
|
135
135
|
- LICENSE.txt
|
136
136
|
- README.rdoc
|
137
|
+
- TODO
|
137
138
|
files:
|
138
139
|
- .document
|
139
140
|
- .rvmrc
|
@@ -143,6 +144,7 @@ files:
|
|
143
144
|
- LICENSE.txt
|
144
145
|
- README.rdoc
|
145
146
|
- Rakefile
|
147
|
+
- TODO
|
146
148
|
- VERSION
|
147
149
|
- bin/keyrack
|
148
150
|
- features/console.feature
|
@@ -184,7 +186,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
184
186
|
requirements:
|
185
187
|
- - ">="
|
186
188
|
- !ruby/object:Gem::Version
|
187
|
-
hash: -
|
189
|
+
hash: -45771557779572669
|
188
190
|
segments:
|
189
191
|
- 0
|
190
192
|
version: "0"
|