pwl 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,3 @@
1
- require 'jbuilder'
2
-
3
1
  module Pwl
4
2
  module Presenter
5
3
  class Json
@@ -8,15 +6,13 @@ module Pwl
8
6
  end
9
7
 
10
8
  def to_s
11
- Jbuilder.encode do |json|
12
- json.(@locker, :created, :last_accessed, :last_modified)
13
-
14
- json.entries @locker.all do |json, entry|
15
- json.key entry.first
16
- json.value entry.last
17
- end
9
+ result = {}
10
+ %w[created last_accessed last_modified].each do |attr|
11
+ result.store(attr.to_sym, @locker.send(attr))
18
12
  end
13
+ result[:entries] = @locker.all.collect{|e| {:uuid => e.uuid, :name => e.name, :password => e.password}}
14
+ result.to_json
19
15
  end
20
16
  end
21
17
  end
22
- end
18
+ end
@@ -13,11 +13,15 @@ module Pwl
13
13
  result[:last_accessed] = @locker.last_accessed.to_s
14
14
  result[:last_modified] = @locker.last_modified.to_s
15
15
  result[:entries] = []
16
- @locker.all.each{|entry|
17
- result[:entries] << {:key => entry.first, :value => entry.last}
18
- }
16
+ @locker.all.each do |entry|
17
+ result[:entries] << {
18
+ :uuid => entry.uuid,
19
+ :key => entry.name,
20
+ :value => entry.password
21
+ }
22
+ end
19
23
  result.to_yaml
20
24
  end
21
25
  end
22
26
  end
23
- end
27
+ end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "pwl"
8
- s.version = "0.0.2"
8
+ s.version = "0.0.3"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Nicholas E. Rabenau"]
12
- s.date = "2012-05-02"
12
+ s.date = "2012-09-05"
13
13
  s.description = "pwl is a secure password locker for the commandline"
14
14
  s.email = "nerab@gmx.net"
15
15
  s.executables = ["pwl", "pwl"]
@@ -28,11 +28,22 @@ Gem::Specification.new do |s|
28
28
  "VERSION",
29
29
  "bin/pwl",
30
30
  "lib/pwl.rb",
31
+ "lib/pwl/commands/add.rb",
32
+ "lib/pwl/commands/base.rb",
33
+ "lib/pwl/commands/delete.rb",
34
+ "lib/pwl/commands/export.rb",
35
+ "lib/pwl/commands/get.rb",
36
+ "lib/pwl/commands/init.rb",
37
+ "lib/pwl/commands/list.rb",
38
+ "lib/pwl/commands/passwd.rb",
39
+ "lib/pwl/commands/stats.rb",
31
40
  "lib/pwl/dialog.rb",
32
41
  "lib/pwl/dialog/base.rb",
33
42
  "lib/pwl/dialog/cocoa.rb",
34
43
  "lib/pwl/dialog/console.rb",
35
44
  "lib/pwl/dialog/gnome.rb",
45
+ "lib/pwl/entry.rb",
46
+ "lib/pwl/entry_mapper.rb",
36
47
  "lib/pwl/locker.rb",
37
48
  "lib/pwl/message.rb",
38
49
  "lib/pwl/password_policy.rb",
@@ -59,6 +70,8 @@ Gem::Specification.new do |s|
59
70
  "test/fixtures/test_empty.json",
60
71
  "test/fixtures/test_empty.yaml",
61
72
  "test/helper.rb",
73
+ "test/unit/test_entry.rb",
74
+ "test/unit/test_entry_mapper.rb",
62
75
  "test/unit/test_error.rb",
63
76
  "test/unit/test_message.rb",
64
77
  "test/unit/test_store_construction.rb",
@@ -80,16 +93,20 @@ Gem::Specification.new do |s|
80
93
  s.add_runtime_dependency(%q<encryptor>, ["~> 1.1"])
81
94
  s.add_runtime_dependency(%q<commander>, ["~> 4.1"])
82
95
  s.add_runtime_dependency(%q<activesupport>, ["~> 3.2"])
83
- s.add_runtime_dependency(%q<jbuilder>, ["~> 0.4"])
96
+ s.add_runtime_dependency(%q<activemodel>, ["~> 3.2"])
97
+ s.add_runtime_dependency(%q<uuid>, ["~> 2.3"])
84
98
  s.add_development_dependency(%q<rdoc>, ["~> 3.1"])
99
+ s.add_development_dependency(%q<pry>, [">= 0"])
85
100
  s.add_development_dependency(%q<bundler>, ["~> 1.1"])
86
101
  s.add_development_dependency(%q<jeweler>, ["~> 1.8"])
87
102
  else
88
103
  s.add_dependency(%q<encryptor>, ["~> 1.1"])
89
104
  s.add_dependency(%q<commander>, ["~> 4.1"])
90
105
  s.add_dependency(%q<activesupport>, ["~> 3.2"])
91
- s.add_dependency(%q<jbuilder>, ["~> 0.4"])
106
+ s.add_dependency(%q<activemodel>, ["~> 3.2"])
107
+ s.add_dependency(%q<uuid>, ["~> 2.3"])
92
108
  s.add_dependency(%q<rdoc>, ["~> 3.1"])
109
+ s.add_dependency(%q<pry>, [">= 0"])
93
110
  s.add_dependency(%q<bundler>, ["~> 1.1"])
94
111
  s.add_dependency(%q<jeweler>, ["~> 1.8"])
95
112
  end
@@ -97,8 +114,10 @@ Gem::Specification.new do |s|
97
114
  s.add_dependency(%q<encryptor>, ["~> 1.1"])
98
115
  s.add_dependency(%q<commander>, ["~> 4.1"])
99
116
  s.add_dependency(%q<activesupport>, ["~> 3.2"])
100
- s.add_dependency(%q<jbuilder>, ["~> 0.4"])
117
+ s.add_dependency(%q<activemodel>, ["~> 3.2"])
118
+ s.add_dependency(%q<uuid>, ["~> 2.3"])
101
119
  s.add_dependency(%q<rdoc>, ["~> 3.1"])
120
+ s.add_dependency(%q<pry>, [">= 0"])
102
121
  s.add_dependency(%q<bundler>, ["~> 1.1"])
103
122
  s.add_dependency(%q<jeweler>, ["~> 1.8"])
104
123
  end
@@ -49,13 +49,13 @@
49
49
  </tr>
50
50
  </tfoot>
51
51
  <tbody>
52
- <% locker.all.each{|key, value|%>
53
- <tr>
54
- <td><%= key %></td>
55
- <td><%= value %></td>
52
+ <% locker.all.each{|entry|%>
53
+ <tr id="<%= entry.uuid %>">
54
+ <td><%= entry.name %></td>
55
+ <td><%= entry.password %></td>
56
56
  </tr>
57
57
  <% } %>
58
58
  </tbody>
59
59
  </table>
60
60
  </body>
61
- </html>
61
+ </html>
@@ -13,10 +13,10 @@ class TestExport < Test::Pwl::AppTestCase
13
13
  test_vector.each{|k,v|
14
14
  assert_successful('', "add '#{k}' '#{v}'")
15
15
  }
16
-
16
+
17
17
  now = DateTime.now.strftime('%F %R')
18
18
  fixture = fixture("test_all.html").gsub('CREATED_STAMP', now).gsub('MODIFIED_STAMP', now).gsub('DATABASE_FILE', locker_file)
19
-
19
+
20
20
  assert_successful_html(fixture, 'export')
21
21
  end
22
22
 
@@ -25,10 +25,13 @@ class TestExport < Test::Pwl::AppTestCase
25
25
  assert_equal(0, rc.exitstatus, "Expected exit status 0, but it was #{rc.exitstatus}. STDERR was: #{err}")
26
26
  assert(err.empty?, "Expected empty STDERR, but it yielded #{err}")
27
27
 
28
+ # ignore generated UUIDs, but insist on format
29
+ out.gsub!(/id=\"[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\"/, 'id="mock-uuid"')
30
+
28
31
  actual = Nokogiri::HTML(out)
29
32
  expected = Nokogiri::HTML(expected_out)
30
33
 
31
- differences = actual.diff(expected, :added => true, :removed => true)
34
+ differences = expected.diff(actual, :added => true, :removed => true)
32
35
 
33
36
  assert_equal(0, differences.count, "Unexpected differences in output. Diff:\n" << differences.collect{|change, node|
34
37
  case change
@@ -13,10 +13,10 @@ class TestExportJSON < Test::Pwl::AppTestCase
13
13
  test_vector.each{|k,v|
14
14
  assert_successful('', "add '#{k}' '#{v}'")
15
15
  }
16
-
16
+
17
17
  now = DateTime.now.strftime('%F %R')
18
18
  fixture = fixture("test_all.json")
19
-
19
+
20
20
  assert_successful_json(fixture, 'export --format json')
21
21
  end
22
22
 
@@ -27,22 +27,25 @@ class TestExportJSON < Test::Pwl::AppTestCase
27
27
 
28
28
  actual = JSON.parse(out)
29
29
  expected = JSON.parse(expected_out)
30
-
30
+
31
31
  # fix up actuals to match expectations
32
32
  actual["created"] = "2012-03-28T21:54:21+02:00"
33
33
  actual["last_accessed"] = "2012-03-28T22:01:49+02:00"
34
34
  actual["last_modified"] = "2012-03-29T22:46:29+02:00"
35
+ actual['entries'].each do |entry|
36
+ entry['uuid'] = 'mock-uuid'
37
+ end
35
38
 
36
39
  # This is essentially the same as
37
40
  # assert_equal(expected, actual)
38
41
  # but it provides better diagnostic output on error
39
42
  json_diff(expected, actual)
40
43
  end
41
-
44
+
42
45
  private
43
46
  def json_diff(expected, actual, context = nil)
44
- assert_equal(expected.class, actual.class)
45
-
47
+ assert_equal(expected.class, actual.class, "JSON in context #{context} has unexpected class:")
48
+
46
49
  case expected
47
50
  when Hash
48
51
  actual.keys.each do |key|
@@ -13,10 +13,10 @@ class TestExportYAML < Test::Pwl::AppTestCase
13
13
  test_vector.each{|k,v|
14
14
  assert_successful('', "add '#{k}' '#{v}'")
15
15
  }
16
-
16
+
17
17
  now = DateTime.now.strftime('%F %R')
18
18
  fixture = fixture("test_all.yaml")
19
-
19
+
20
20
  assert_successful_yaml(fixture, 'export --format yaml')
21
21
  end
22
22
 
@@ -27,22 +27,25 @@ class TestExportYAML < Test::Pwl::AppTestCase
27
27
 
28
28
  actual = YAML.load(out)
29
29
  expected = YAML.load(expected_out)
30
-
30
+
31
31
  # fix up actuals to match expectations
32
32
  actual[:created] = "2012-03-28T21:54:21+02:00"
33
33
  actual[:last_accessed] = "2012-03-28T22:01:49+02:00"
34
34
  actual[:last_modified] = "2012-03-29T22:46:29+02:00"
35
+ actual[:entries].each do |entry|
36
+ entry[:uuid] = 'mock-uuid'
37
+ end
35
38
 
36
39
  # This is essentially the same as
37
40
  # assert_equal(expected, actual)
38
41
  # but it provides better diagnostic output on error
39
42
  yaml_diff(expected, actual)
40
43
  end
41
-
44
+
42
45
  private
43
46
  def yaml_diff(expected, actual, context = nil)
44
47
  #assert_equal(expected.class, actual.class)
45
-
48
+
46
49
  case expected
47
50
  when Hash
48
51
  actual.keys.each do |key|
@@ -17,7 +17,7 @@ class TestInit < Test::Pwl::AppTestCase
17
17
  # $
18
18
  #
19
19
  def test_matching_passwords
20
- cmd = "bin/pwl init --force --verbose --file \"#{@locker_file}\""
20
+ cmd = "bin/pwl init --force --verbose --file \"#{locker_file}\""
21
21
 
22
22
  PTY.spawn(cmd){|pwl_out, pwl_in, pid|
23
23
  assert_response('Enter new master password:', pwl_out)
@@ -57,6 +57,26 @@ class TestInit < Test::Pwl::AppTestCase
57
57
  }
58
58
  end
59
59
 
60
+ #
61
+ # Tests that initing with a directory argument fail.
62
+ #
63
+ # A session is expected to look like this:
64
+ #
65
+ # $ bin/pwl init --file /tmp
66
+ # pwl: File expected, but /tmp is a directory. Specify a regular file for the locker.
67
+ # $
68
+ #
69
+ def test_locker_existing_dir
70
+ dir = File.dirname(locker_file)
71
+ assert(File.directory?(dir))
72
+
73
+ cmd = "bin/pwl init --file \"#{dir}\""
74
+
75
+ PTY.spawn(cmd){|pwl_out, pwl_in, pid|
76
+ assert_response("pwl: File expected, but #{dir} is a directory. Specify a regular file for the locker.", pwl_out)
77
+ }
78
+ end
79
+
60
80
  #
61
81
  # Tests that initing an existing locker without --force does not touch the existing locker
62
82
  #
@@ -73,9 +93,9 @@ class TestInit < Test::Pwl::AppTestCase
73
93
 
74
94
  private
75
95
 
76
- def assert_response(expected, actual_io)
77
- if !actual_io.expect(/#{expected}/, 1)
78
- raise StandardError.new("Expected response '#{expected}' was not matched")
96
+ def assert_response(expected, actual_io, timeout = 5)
97
+ if !actual_io.expect(/#{expected}/, timeout)
98
+ raise StandardError.new("Expected response '#{expected}' was not found within timeout of #{timeout} seconds.")
79
99
  end
80
100
  end
81
101
  end
@@ -5,7 +5,7 @@ class TestList < Test::Pwl::AppTestCase
5
5
  def test_list_empty
6
6
  assert_empty(locker.list)
7
7
  assert_error('^$', 'list')
8
- assert_error('^List is empty\.$', 'list --verbose')
8
+ assert_error('^pwl: List is empty\.$', 'list --verbose')
9
9
  end
10
10
 
11
11
  def test_list_all
@@ -50,17 +50,17 @@
50
50
  </tfoot>
51
51
  <tbody>
52
52
 
53
- <tr>
53
+ <tr id="mock-uuid">
54
54
  <td>foo</td>
55
55
  <td>one</td>
56
56
  </tr>
57
57
 
58
- <tr>
58
+ <tr id="mock-uuid">
59
59
  <td>bar</td>
60
60
  <td>two</td>
61
61
  </tr>
62
62
 
63
- <tr>
63
+ <tr id="mock-uuid">
64
64
  <td>Chuck Norris</td>
65
65
  <td>Roundhouse Kick</td>
66
66
  </tr>
@@ -4,16 +4,19 @@
4
4
  "last_modified": "2012-03-29T22:46:29+02:00",
5
5
  "entries": [
6
6
  {
7
- "key": "foo",
8
- "value": "one"
7
+ "uuid": "mock-uuid",
8
+ "name": "foo",
9
+ "password": "one"
9
10
  },
10
11
  {
11
- "key": "bar",
12
- "value": "two"
12
+ "uuid": "mock-uuid",
13
+ "name": "bar",
14
+ "password": "two"
13
15
  },
14
16
  {
15
- "key": "Chuck Norris",
16
- "value": "Roundhouse Kick"
17
+ "uuid": "mock-uuid",
18
+ "name": "Chuck Norris",
19
+ "password": "Roundhouse Kick"
17
20
  }
18
21
  ]
19
22
  }
@@ -3,9 +3,12 @@
3
3
  :last_accessed: '2012-03-28T22:01:49+02:00'
4
4
  :last_modified: '2012-03-29T22:46:29+02:00'
5
5
  :entries:
6
- - :key: foo
6
+ - :uuid: mock-uuid
7
+ :key: foo
7
8
  :value: one
8
- - :key: bar
9
+ - :uuid: mock-uuid
10
+ :key: bar
9
11
  :value: two
10
- - :key: Chuck Norris
12
+ - :uuid: mock-uuid
13
+ :key: Chuck Norris
11
14
  :value: Roundhouse Kick
@@ -16,9 +16,11 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
16
16
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
17
17
  require 'pwl'
18
18
  require 'tmpdir'
19
+ require 'active_support/testing/assertions'
19
20
 
20
21
  class Test::Unit::TestCase
21
22
  FIXTURES_DIR = File.join(File.dirname(__FILE__), 'fixtures')
23
+ include ActiveSupport::Testing::Assertions
22
24
  end
23
25
 
24
26
  module Test
@@ -55,7 +57,7 @@ module Test
55
57
 
56
58
  def assert_successful(expected_out, cmd, password = locker_password)
57
59
  out, err, rc = execute(cmd, password)
58
- assert_equal(0, rc.exitstatus, "Expected exit status 0, but it was #{rc.exitstatus}. STDERR was: #{err}")
60
+ assert_equal(0, rc.exitstatus, "Expected exit status 0, but it was #{rc.exitstatus}. STDERR was: #{err}. Command was '#{cmd}''")
59
61
  assert(err.empty?, "Expected empty STDERR, but it yielded #{err}")
60
62
  assert(out =~ /#{expected_out}/, "'#{out}' did not match expected response '#{expected_out}'")
61
63
  end
@@ -70,7 +72,7 @@ module Test
70
72
  def execute(cmd, password)
71
73
  Open3.capture3("echo \"#{password}\" | #{APP} #{cmd} --file \"#{locker_file}\"")
72
74
  end
73
-
75
+
74
76
  def fixture(name)
75
77
  File.read(File.join(FIXTURES_DIR, name))
76
78
  end
@@ -0,0 +1,67 @@
1
+ require 'helper'
2
+
3
+ class TestEntry < Test::Unit::TestCase
4
+ def setup
5
+ @entry = Pwl::Entry.new
6
+ end
7
+
8
+ def test_construction_state
9
+ assert(!@entry.valid?)
10
+ assert_not_nil(@entry.uuid)
11
+ end
12
+
13
+ def test_uuid_assign_nil
14
+ @entry.name = 'test_uuid_assign_nil'
15
+ @entry.uuid = nil
16
+ assert(!@entry.valid?)
17
+ end
18
+
19
+ def test_uuid_assign_empty
20
+ @entry.name = 'test_uuid_assign_empty'
21
+ @entry.uuid = ''
22
+ assert(!@entry.valid?)
23
+ end
24
+
25
+ def test_uuid_assign_invalid
26
+ @entry.name = 'test_uuid_assign_invalid'
27
+ @entry.uuid = 'invalid'
28
+ assert(!@entry.valid?)
29
+ end
30
+
31
+ def test_uuid_assign_valid
32
+ @entry.name = 'test_uuid_assign_valid'
33
+ @entry.password = 'password is require to be valid'
34
+ @entry.uuid = 'b1f75370-979c-012f-eed1-70def14c3504'
35
+ assert(@entry.valid?)
36
+ end
37
+
38
+ def test_name_assign
39
+ name = 'foobar'
40
+ @entry.name = name
41
+ assert_equal(name, @entry.name)
42
+
43
+ @entry.password = 'password is require to be valid'
44
+ assert(@entry.valid?)
45
+ end
46
+
47
+ def test_name_construction
48
+ name = 'foobar'
49
+ @entry = Pwl::Entry.new(name)
50
+ assert_equal(name, @entry.name)
51
+
52
+ @entry.password = 'password is require to be valid'
53
+ assert(@entry.valid?)
54
+ end
55
+
56
+ def test_name_assign_nil
57
+ assert_nil(@entry.name)
58
+ assert(!@entry.valid?)
59
+ end
60
+
61
+ def test_name_assign_empty
62
+ name = ''
63
+ @entry.name = name
64
+ assert_equal(name, @entry.name)
65
+ assert(!@entry.valid?)
66
+ end
67
+ end