pwl 0.0.2 → 0.0.3

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.
@@ -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