keyrack 0.1.1 → 0.1.2

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.
@@ -0,0 +1,2 @@
1
+ neww -n 'autotest' 'autotest'
2
+ neww -n 'vim' 'vim'
@@ -17,24 +17,27 @@ The configuration file is a YAML file that requires the following data:
17
17
 
18
18
  === Store types
19
19
 
20
- * *filesystem*
21
- * Required options:
22
- * *path*: path to the keyrack database
23
- * +ssh+
24
- * Required options:
25
- * *host*: host name
26
- * *user*: user name
27
- * *path*: path to the keyrack database on remote host
20
+ ==== filesystem
21
+ * Required options:
22
+ * *path*: path to the keyrack database
23
+
24
+ ==== ssh
25
+ * Required options:
26
+ * *host*: host name
27
+ * *user*: user name
28
+ * *path*: path to the keyrack database on remote host
28
29
 
29
30
  === Examples
30
31
 
31
- Filesystem example
32
+ ==== Filesystem example
33
+
32
34
  store:
33
35
  type: filesystem
34
36
  path: ~/.keyrack/database
35
37
  key: ~/.keyrack/id_rsa
36
38
 
37
- SSH example
39
+ ==== SSH example
40
+
38
41
  store:
39
42
  type: ssh
40
43
  host: example.com
@@ -46,8 +49,23 @@ SSH example
46
49
 
47
50
  keyrack [-c path-to-config]
48
51
 
49
- By default, keyrack will look for <b>~/.keyrack/config</b>. The database file
50
- (merely a RSA-encrypted YAML file) will be created on save if it doesn't exist.
52
+ By default, Keyrack will look for <b>~/.keyrack/config</b>. The database file
53
+ (merely a RSA-encrypted Ruby hash) will be created on save if it doesn't exist.
54
+ It's a good idea to generate a seperate RSA key for use with Keyrack, especially
55
+ if you are using the SSH store and are connecting from multiple locations. To
56
+ generate a key, try: <code>ssh-keygen -C keyrack -f ~/.keyrack/id_rsa</code>
57
+
58
+ Starting keyrack will display a simple menu in your terminal, like this:
59
+
60
+ 1. Twitter [foobar]
61
+ 2. Facebook [foobar@example.com]
62
+ 3. Twitter [otherfoobar]
63
+ n. Add new
64
+ s. Save
65
+ q. Quit
66
+
67
+ Selecting <b>1</b> in this case will copy the Twitter password for the foobar user
68
+ to your clipboard.
51
69
 
52
70
  == Contributing to keyrack
53
71
 
data/Rakefile CHANGED
@@ -23,14 +23,14 @@ Jeweler::Tasks.new do |gem|
23
23
  # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
24
24
  # gem.add_runtime_dependency 'jabber4r', '> 0.1'
25
25
  # gem.add_development_dependency 'rspec', '> 1.2.3'
26
- gem.add_runtime_dependency 'net-scp'
27
- gem.add_runtime_dependency 'highline'
28
- gem.add_runtime_dependency 'clipboard'
29
- gem.add_development_dependency 'rspec', '> 1.2.3'
30
- gem.add_development_dependency "bundler", "~> 1.0.0"
31
- gem.add_development_dependency "jeweler", "~> 1.5.1"
32
- gem.add_development_dependency "rcov", ">= 0"
33
- gem.add_development_dependency "mocha"
26
+ # gem.add_runtime_dependency 'net-scp'
27
+ # gem.add_runtime_dependency 'highline'
28
+ # gem.add_runtime_dependency 'clipboard'
29
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
30
+ # gem.add_development_dependency "bundler", "~> 1.0.0"
31
+ # gem.add_development_dependency "jeweler", "~> 1.5.1"
32
+ # gem.add_development_dependency "rcov", ">= 0"
33
+ # gem.add_development_dependency "mocha"
34
34
  end
35
35
  Jeweler::RubygemsDotOrgTasks.new
36
36
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.2
@@ -0,0 +1,97 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{keyrack}
8
+ s.version = "0.1.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Jeremy Stephens"]
12
+ s.date = %q{2010-12-12}
13
+ s.default_executable = %q{keyrack}
14
+ s.description = %q{Simple password manager with local/remote database storage and RSA encryption.}
15
+ s.email = %q{viking@pillageandplunder.net}
16
+ s.executables = ["keyrack"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE.txt",
19
+ "README.rdoc"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".rvmrc",
24
+ "Gemfile",
25
+ "Gemfile.lock",
26
+ "LICENSE.txt",
27
+ "README.rdoc",
28
+ "Rakefile",
29
+ "VERSION",
30
+ "bin/keyrack",
31
+ "lib/keyrack.rb",
32
+ "lib/keyrack/database.rb",
33
+ "lib/keyrack/runner.rb",
34
+ "lib/keyrack/store.rb",
35
+ "lib/keyrack/store/filesystem.rb",
36
+ "lib/keyrack/store/ssh.rb",
37
+ "lib/keyrack/ui.rb",
38
+ "lib/keyrack/ui/console.rb",
39
+ "test/fixtures/config.yml",
40
+ "test/fixtures/foo.txt",
41
+ "test/fixtures/id_rsa",
42
+ "test/fixtures/id_rsa.pub",
43
+ "test/helper.rb",
44
+ "test/keyrack/store/test_filesystem.rb",
45
+ "test/keyrack/store/test_ssh.rb",
46
+ "test/keyrack/test_database.rb",
47
+ "test/keyrack/test_runner.rb",
48
+ "test/keyrack/test_store.rb",
49
+ "test/keyrack/ui/test_console.rb"
50
+ ]
51
+ s.homepage = %q{http://github.com/viking/keyrack}
52
+ s.licenses = ["MIT"]
53
+ s.require_paths = ["lib"]
54
+ s.rubygems_version = %q{1.3.7}
55
+ s.summary = %q{Simple password manager}
56
+ s.test_files = [
57
+ "test/helper.rb",
58
+ "test/keyrack/store/test_filesystem.rb",
59
+ "test/keyrack/store/test_ssh.rb",
60
+ "test/keyrack/test_database.rb",
61
+ "test/keyrack/test_runner.rb",
62
+ "test/keyrack/test_store.rb",
63
+ "test/keyrack/ui/test_console.rb"
64
+ ]
65
+
66
+ if s.respond_to? :specification_version then
67
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
68
+ s.specification_version = 3
69
+
70
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
71
+ s.add_runtime_dependency(%q<net-scp>, [">= 0"])
72
+ s.add_runtime_dependency(%q<highline>, [">= 0"])
73
+ s.add_runtime_dependency(%q<clipboard>, [">= 0"])
74
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
75
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
76
+ s.add_development_dependency(%q<rcov>, [">= 0"])
77
+ s.add_development_dependency(%q<mocha>, [">= 0"])
78
+ else
79
+ s.add_dependency(%q<net-scp>, [">= 0"])
80
+ s.add_dependency(%q<highline>, [">= 0"])
81
+ s.add_dependency(%q<clipboard>, [">= 0"])
82
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
83
+ s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
84
+ s.add_dependency(%q<rcov>, [">= 0"])
85
+ s.add_dependency(%q<mocha>, [">= 0"])
86
+ end
87
+ else
88
+ s.add_dependency(%q<net-scp>, [">= 0"])
89
+ s.add_dependency(%q<highline>, [">= 0"])
90
+ s.add_dependency(%q<clipboard>, [">= 0"])
91
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
92
+ s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
93
+ s.add_dependency(%q<rcov>, [">= 0"])
94
+ s.add_dependency(%q<mocha>, [">= 0"])
95
+ end
96
+ end
97
+
@@ -8,6 +8,7 @@ require 'clipboard'
8
8
  module Keyrack
9
9
  end
10
10
 
11
+ require File.dirname(__FILE__) + '/keyrack/utils'
11
12
  require File.dirname(__FILE__) + '/keyrack/database'
12
13
  require File.dirname(__FILE__) + '/keyrack/store'
13
14
  require File.dirname(__FILE__) + '/keyrack/ui'
@@ -6,10 +6,12 @@ module Keyrack
6
6
  key_path = File.expand_path(config['key'])
7
7
  @key = OpenSSL::PKey::RSA.new(File.read(key_path), config['password'])
8
8
  @data = decrypt
9
+ @dirty = false
9
10
  end
10
11
 
11
12
  def add(site, username, password)
12
13
  @data[site] = { :username => username, :password => password }
14
+ @dirty = true
13
15
  end
14
16
 
15
17
  def get(site)
@@ -20,8 +22,13 @@ module Keyrack
20
22
  @data.keys
21
23
  end
22
24
 
25
+ def dirty?
26
+ @dirty
27
+ end
28
+
23
29
  def save
24
30
  @store.write(@key.public_encrypt(Marshal.dump(@data)))
31
+ @dirty = false
25
32
  end
26
33
 
27
34
  private
@@ -12,7 +12,7 @@ module Keyrack
12
12
 
13
13
  def menu
14
14
  entries = []
15
- choices = %w{n s q}
15
+ choices = %w{n q}
16
16
  @database.sites.each_with_index do |site, i|
17
17
  entry = @database.get(site)
18
18
  entries << entry
@@ -20,7 +20,10 @@ module Keyrack
20
20
  @highline.say("% 2d. %s [%s]" % [i+1, site, entry[:username]])
21
21
  end
22
22
  @highline.say(" n. Add new")
23
- @highline.say(" s. Save")
23
+ if @database.dirty?
24
+ @highline.say(" s. Save")
25
+ choices << "s"
26
+ end
24
27
  @highline.say(" q. Quit")
25
28
  result = @highline.ask(" ? ") { |q| q.in = choices }
26
29
  case result
@@ -29,7 +32,11 @@ module Keyrack
29
32
  when "s"
30
33
  :save
31
34
  when "q"
32
- :quit
35
+ if @database.dirty? && !@highline.agree("Really quit? You have unsaved changes! [yn] ")
36
+ nil
37
+ else
38
+ :quit
39
+ end
33
40
  else
34
41
  Clipboard.copy(entries[result.to_i - 1][:password])
35
42
  @highline.say("The password has been copied to your clipboard.")
@@ -39,9 +46,27 @@ module Keyrack
39
46
 
40
47
  def get_new_entry
41
48
  result = {}
42
- result[:site] = @highline.ask("Site: ")
49
+ result[:site] = @highline.ask("Label: ")
43
50
  result[:username] = @highline.ask("Username: ")
44
- result[:password] = @highline.ask("Password: ")
51
+ if @highline.agree("Generate password? [yn] ")
52
+ loop do
53
+ password = Utils.generate_password
54
+ if @highline.agree("Generated #{@highline.color(password, :blue)}. Sound good? [yn] ")
55
+ result[:password] = password
56
+ break
57
+ end
58
+ end
59
+ else
60
+ loop do
61
+ password = @highline.ask("Password: ") { |q| q.echo = false }
62
+ confirmation = @highline.ask("Password (again): ") { |q| q.echo = false }
63
+ if password == confirmation
64
+ result[:password] = password
65
+ break
66
+ end
67
+ @highline.say("Passwords didn't match. Try again!")
68
+ end
69
+ end
45
70
  result
46
71
  end
47
72
  end
@@ -0,0 +1,11 @@
1
+ module Keyrack
2
+ module Utils
3
+ def self.generate_password
4
+ result = " "
5
+ result.length.times do |i|
6
+ result[i] = (33 + rand(94)).chr
7
+ end
8
+ result
9
+ end
10
+ end
11
+ end
@@ -34,5 +34,11 @@ module Keyrack
34
34
  def test_sites
35
35
  assert_equal(%w{Twitter}, @database.sites)
36
36
  end
37
+
38
+ def test_dirty
39
+ assert !@database.dirty?
40
+ @database.add('Foo', 'bar', 'baz')
41
+ assert @database.dirty?
42
+ end
37
43
  end
38
44
  end
@@ -0,0 +1,10 @@
1
+ require 'helper'
2
+
3
+ module Keyrack
4
+ class TestUtils < Test::Unit::TestCase
5
+ def test_generate_password
6
+ result = Utils.generate_password
7
+ assert_match result, /^[!-~]{8}$/
8
+ end
9
+ end
10
+ end
@@ -22,11 +22,10 @@ module Keyrack
22
22
 
23
23
  highline.expects(:say).with(" 1. Twitter [username]")
24
24
  highline.expects(:say).with(" n. Add new")
25
- highline.expects(:say).with(" s. Save")
26
25
  highline.expects(:say).with(" q. Quit")
27
26
 
28
27
  question = mock('question')
29
- question.expects(:in=).with(%w{n s q 1})
28
+ question.expects(:in=).with(%w{n q 1})
30
29
  highline.expects(:ask).yields(question).returns('1')
31
30
  Clipboard.expects(:copy).with('password')
32
31
  highline.expects(:say).with("The password has been copied to your clipboard.")
@@ -41,11 +40,10 @@ module Keyrack
41
40
 
42
41
  highline.expects(:say).with(" 1. Twitter [username]")
43
42
  highline.expects(:say).with(" n. Add new")
44
- highline.expects(:say).with(" s. Save")
45
43
  highline.expects(:say).with(" q. Quit")
46
44
 
47
45
  question = mock('question')
48
- question.expects(:in=).with(%w{n s q 1})
46
+ question.expects(:in=).with(%w{n q 1})
49
47
  highline.expects(:ask).yields(question).returns('n')
50
48
  assert_equal :new, console.menu
51
49
  end
@@ -58,20 +56,38 @@ module Keyrack
58
56
 
59
57
  highline.expects(:say).with(" 1. Twitter [username]")
60
58
  highline.expects(:say).with(" n. Add new")
61
- highline.expects(:say).with(" s. Save")
62
59
  highline.expects(:say).with(" q. Quit")
63
60
 
64
61
  question = mock('question')
65
- question.expects(:in=).with(%w{n s q 1})
62
+ question.expects(:in=).with(%w{n q 1})
66
63
  highline.expects(:ask).yields(question).returns('q')
67
64
  assert_equal :quit, console.menu
68
65
  end
69
66
 
67
+ def test_select_quit_from_menu_when_database_is_dirty
68
+ highline = mock('highline')
69
+ HighLine.expects(:new).returns(highline)
70
+ console = Console.new
71
+ console.database = @database
72
+ @database.stubs(:dirty?).returns(true)
73
+
74
+ highline.expects(:say).with(" 1. Twitter [username]")
75
+ highline.expects(:say).with(" n. Add new")
76
+ highline.expects(:say).with(" s. Save")
77
+ highline.expects(:say).with(" q. Quit")
78
+
79
+ question = mock('question', :in= => nil)
80
+ highline.expects(:ask).yields(question).returns('q')
81
+ highline.expects(:agree).with("Really quit? You have unsaved changes! [yn] ").returns(false)
82
+ assert_equal nil, console.menu
83
+ end
84
+
70
85
  def test_select_save_from_menu
71
86
  highline = mock('highline')
72
87
  HighLine.expects(:new).returns(highline)
73
88
  console = Console.new
74
89
  console.database = @database
90
+ @database.stubs(:dirty?).returns(true)
75
91
 
76
92
  highline.expects(:say).with(" 1. Twitter [username]")
77
93
  highline.expects(:say).with(" n. Add new")
@@ -79,7 +95,7 @@ module Keyrack
79
95
  highline.expects(:say).with(" q. Quit")
80
96
 
81
97
  question = mock('question')
82
- question.expects(:in=).with(%w{n s q 1})
98
+ question.expects(:in=).with(%w{n q 1 s})
83
99
  highline.expects(:ask).yields(question).returns('s')
84
100
  assert_equal :save, console.menu
85
101
  end
@@ -95,16 +111,40 @@ module Keyrack
95
111
  assert_equal "foobar", console.get_password
96
112
  end
97
113
 
98
- def test_get_new_entry
114
+ def test_get_new_entry_with_manual_password
99
115
  highline = mock('highline')
100
116
  HighLine.expects(:new).returns(highline)
101
117
  console = Console.new
102
118
 
103
- highline.expects(:ask).with("Site: ").returns("Foo")
104
- highline.expects(:ask).with("Username: ").returns("bar")
105
- highline.expects(:ask).with("Password: ").returns("baz")
119
+ seq = sequence("new entry")
120
+ highline.expects(:ask).with("Label: ").returns("Foo").in_sequence(seq)
121
+ highline.expects(:ask).with("Username: ").returns("bar").in_sequence(seq)
122
+ highline.expects(:agree).with("Generate password? [yn] ").returns(false).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("bar").in_sequence(seq)
125
+ highline.expects(:say).with("Passwords didn't match. Try again!").in_sequence(seq)
126
+ highline.expects(:ask).with("Password: ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
127
+ highline.expects(:ask).with("Password (again): ").yields(mock { expects(:echo=).with(false) }).returns("baz").in_sequence(seq)
106
128
  assert_equal({:site => "Foo", :username => "bar", :password => "baz"}, console.get_new_entry)
107
129
  end
130
+
131
+ def test_get_new_entry_generated_password
132
+ highline = mock('highline')
133
+ HighLine.expects(:new).returns(highline)
134
+ console = Console.new
135
+
136
+ seq = sequence("new entry")
137
+ highline.expects(:ask).with("Label: ").returns("Foo").in_sequence(seq)
138
+ highline.expects(:ask).with("Username: ").returns("bar").in_sequence(seq)
139
+ highline.expects(:agree).with("Generate password? [yn] ").returns(true).in_sequence(seq)
140
+ 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(false).in_sequence(seq)
143
+ Utils.expects(:generate_password).returns('foobar').in_sequence(seq)
144
+ highline.expects(:color).with('foobar', :blue).returns('bluefoobar').in_sequence(seq)
145
+ highline.expects(:agree).with("Generated bluefoobar. Sound good? [yn] ").returns(true).in_sequence(seq)
146
+ assert_equal({:site => "Foo", :username => "bar", :password => "foobar"}, console.get_new_entry)
147
+ end
108
148
  end
109
149
  end
110
150
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 1
9
- version: 0.1.1
8
+ - 2
9
+ version: 0.1.2
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: 2010-12-12 00:00:00 -06:00
17
+ date: 2010-12-13 00:00:00 -06:00
18
18
  default_executable: keyrack
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -112,116 +112,6 @@ dependencies:
112
112
  type: :development
113
113
  prerelease: false
114
114
  version_requirements: *id007
115
- - !ruby/object:Gem::Dependency
116
- name: net-scp
117
- requirement: &id008 !ruby/object:Gem::Requirement
118
- none: false
119
- requirements:
120
- - - ">="
121
- - !ruby/object:Gem::Version
122
- segments:
123
- - 0
124
- version: "0"
125
- type: :runtime
126
- prerelease: false
127
- version_requirements: *id008
128
- - !ruby/object:Gem::Dependency
129
- name: highline
130
- requirement: &id009 !ruby/object:Gem::Requirement
131
- none: false
132
- requirements:
133
- - - ">="
134
- - !ruby/object:Gem::Version
135
- segments:
136
- - 0
137
- version: "0"
138
- type: :runtime
139
- prerelease: false
140
- version_requirements: *id009
141
- - !ruby/object:Gem::Dependency
142
- name: clipboard
143
- requirement: &id010 !ruby/object:Gem::Requirement
144
- none: false
145
- requirements:
146
- - - ">="
147
- - !ruby/object:Gem::Version
148
- segments:
149
- - 0
150
- version: "0"
151
- type: :runtime
152
- prerelease: false
153
- version_requirements: *id010
154
- - !ruby/object:Gem::Dependency
155
- name: rspec
156
- requirement: &id011 !ruby/object:Gem::Requirement
157
- none: false
158
- requirements:
159
- - - ">"
160
- - !ruby/object:Gem::Version
161
- segments:
162
- - 1
163
- - 2
164
- - 3
165
- version: 1.2.3
166
- type: :development
167
- prerelease: false
168
- version_requirements: *id011
169
- - !ruby/object:Gem::Dependency
170
- name: bundler
171
- requirement: &id012 !ruby/object:Gem::Requirement
172
- none: false
173
- requirements:
174
- - - ~>
175
- - !ruby/object:Gem::Version
176
- segments:
177
- - 1
178
- - 0
179
- - 0
180
- version: 1.0.0
181
- type: :development
182
- prerelease: false
183
- version_requirements: *id012
184
- - !ruby/object:Gem::Dependency
185
- name: jeweler
186
- requirement: &id013 !ruby/object:Gem::Requirement
187
- none: false
188
- requirements:
189
- - - ~>
190
- - !ruby/object:Gem::Version
191
- segments:
192
- - 1
193
- - 5
194
- - 1
195
- version: 1.5.1
196
- type: :development
197
- prerelease: false
198
- version_requirements: *id013
199
- - !ruby/object:Gem::Dependency
200
- name: rcov
201
- requirement: &id014 !ruby/object:Gem::Requirement
202
- none: false
203
- requirements:
204
- - - ">="
205
- - !ruby/object:Gem::Version
206
- segments:
207
- - 0
208
- version: "0"
209
- type: :development
210
- prerelease: false
211
- version_requirements: *id014
212
- - !ruby/object:Gem::Dependency
213
- name: mocha
214
- requirement: &id015 !ruby/object:Gem::Requirement
215
- none: false
216
- requirements:
217
- - - ">="
218
- - !ruby/object:Gem::Version
219
- segments:
220
- - 0
221
- version: "0"
222
- type: :development
223
- prerelease: false
224
- version_requirements: *id015
225
115
  description: Simple password manager with local/remote database storage and RSA encryption.
226
116
  email: viking@pillageandplunder.net
227
117
  executables:
@@ -234,6 +124,7 @@ extra_rdoc_files:
234
124
  files:
235
125
  - .document
236
126
  - .rvmrc
127
+ - .tmux.conf
237
128
  - Gemfile
238
129
  - Gemfile.lock
239
130
  - LICENSE.txt
@@ -241,6 +132,7 @@ files:
241
132
  - Rakefile
242
133
  - VERSION
243
134
  - bin/keyrack
135
+ - keyrack.gemspec
244
136
  - lib/keyrack.rb
245
137
  - lib/keyrack/database.rb
246
138
  - lib/keyrack/runner.rb
@@ -249,6 +141,7 @@ files:
249
141
  - lib/keyrack/store/ssh.rb
250
142
  - lib/keyrack/ui.rb
251
143
  - lib/keyrack/ui/console.rb
144
+ - lib/keyrack/utils.rb
252
145
  - test/fixtures/config.yml
253
146
  - test/fixtures/foo.txt
254
147
  - test/fixtures/id_rsa
@@ -259,6 +152,7 @@ files:
259
152
  - test/keyrack/test_database.rb
260
153
  - test/keyrack/test_runner.rb
261
154
  - test/keyrack/test_store.rb
155
+ - test/keyrack/test_utils.rb
262
156
  - test/keyrack/ui/test_console.rb
263
157
  has_rdoc: true
264
158
  homepage: http://github.com/viking/keyrack
@@ -274,7 +168,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
274
168
  requirements:
275
169
  - - ">="
276
170
  - !ruby/object:Gem::Version
277
- hash: -3950856831119826099
171
+ hash: 528577741293551689
278
172
  segments:
279
173
  - 0
280
174
  version: "0"
@@ -300,4 +194,5 @@ test_files:
300
194
  - test/keyrack/test_database.rb
301
195
  - test/keyrack/test_runner.rb
302
196
  - test/keyrack/test_store.rb
197
+ - test/keyrack/test_utils.rb
303
198
  - test/keyrack/ui/test_console.rb