pwl 0.0.1 → 0.0.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,19 @@
1
+ require 'erb'
2
+
3
+ module Pwl
4
+ module Presenter
5
+ class Html
6
+ attr_reader :locker # used by the ERB template
7
+ DEFAULT_EXPORT_TEMPLATE = File.join(File.dirname(__FILE__), *%w[.. .. .. templates export.html.erb])
8
+
9
+ def initialize(locker)
10
+ @locker = locker
11
+ @template = ERB.new(File.read(DEFAULT_EXPORT_TEMPLATE))
12
+ end
13
+
14
+ def to_s
15
+ @template.result(binding)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ require 'jbuilder'
2
+
3
+ module Pwl
4
+ module Presenter
5
+ class Json
6
+ def initialize(locker)
7
+ @locker = locker
8
+ end
9
+
10
+ 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
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ require 'yaml'
2
+
3
+ module Pwl
4
+ module Presenter
5
+ class Yaml
6
+ def initialize(locker)
7
+ @locker = locker
8
+ end
9
+
10
+ def to_s
11
+ result = {}
12
+ result[:created] = @locker.created.to_s
13
+ result[:last_accessed] = @locker.last_accessed.to_s
14
+ result[:last_modified] = @locker.last_modified.to_s
15
+ result[:entries] = []
16
+ @locker.all.each{|entry|
17
+ result[:entries] << {:key => entry.first, :value => entry.last}
18
+ }
19
+ result.to_yaml
20
+ end
21
+ end
22
+ end
23
+ end
data/pwl.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "pwl"
8
- s.version = "0.0.1"
8
+ s.version = "0.0.2"
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-03-22"
12
+ s.date = "2012-05-02"
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"]
@@ -33,22 +33,31 @@ Gem::Specification.new do |s|
33
33
  "lib/pwl/dialog/cocoa.rb",
34
34
  "lib/pwl/dialog/console.rb",
35
35
  "lib/pwl/dialog/gnome.rb",
36
+ "lib/pwl/locker.rb",
36
37
  "lib/pwl/message.rb",
37
38
  "lib/pwl/password_policy.rb",
38
- "lib/pwl/store.rb",
39
+ "lib/pwl/presenter/html.rb",
40
+ "lib/pwl/presenter/json.rb",
41
+ "lib/pwl/presenter/yaml.rb",
39
42
  "pwl.gemspec",
40
43
  "templates/export.html.erb",
44
+ "test/acceptance/test_add.rb",
41
45
  "test/acceptance/test_basics.rb",
42
46
  "test/acceptance/test_delete.rb",
43
47
  "test/acceptance/test_dialogs.rb",
44
48
  "test/acceptance/test_export.rb",
49
+ "test/acceptance/test_export_json.rb",
50
+ "test/acceptance/test_export_yaml.rb",
45
51
  "test/acceptance/test_get.rb",
46
52
  "test/acceptance/test_init.rb",
47
53
  "test/acceptance/test_list.rb",
48
54
  "test/acceptance/test_passwd.rb",
49
- "test/acceptance/test_put.rb",
50
55
  "test/fixtures/test_all.html",
56
+ "test/fixtures/test_all.json",
57
+ "test/fixtures/test_all.yaml",
51
58
  "test/fixtures/test_empty.html",
59
+ "test/fixtures/test_empty.json",
60
+ "test/fixtures/test_empty.yaml",
52
61
  "test/helper.rb",
53
62
  "test/unit/test_error.rb",
54
63
  "test/unit/test_message.rb",
@@ -61,34 +70,37 @@ Gem::Specification.new do |s|
61
70
  s.homepage = "http://github.com/nerab/pwl"
62
71
  s.licenses = ["MIT"]
63
72
  s.require_paths = ["lib"]
64
- s.rubygems_version = "1.8.15"
73
+ s.rubygems_version = "1.8.24"
65
74
  s.summary = "Command-line password locker"
66
75
 
67
76
  if s.respond_to? :specification_version then
68
77
  s.specification_version = 3
69
78
 
70
79
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
71
- s.add_runtime_dependency(%q<encryptor>, [">= 0"])
72
- s.add_runtime_dependency(%q<commander>, [">= 0"])
73
- s.add_runtime_dependency(%q<activesupport>, [">= 0"])
74
- s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
75
- s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
76
- s.add_development_dependency(%q<jeweler>, ["~> 1.8.3"])
80
+ s.add_runtime_dependency(%q<encryptor>, ["~> 1.1"])
81
+ s.add_runtime_dependency(%q<commander>, ["~> 4.1"])
82
+ s.add_runtime_dependency(%q<activesupport>, ["~> 3.2"])
83
+ s.add_runtime_dependency(%q<jbuilder>, ["~> 0.4"])
84
+ s.add_development_dependency(%q<rdoc>, ["~> 3.1"])
85
+ s.add_development_dependency(%q<bundler>, ["~> 1.1"])
86
+ s.add_development_dependency(%q<jeweler>, ["~> 1.8"])
77
87
  else
78
- s.add_dependency(%q<encryptor>, [">= 0"])
79
- s.add_dependency(%q<commander>, [">= 0"])
80
- s.add_dependency(%q<activesupport>, [">= 0"])
81
- s.add_dependency(%q<rdoc>, ["~> 3.12"])
82
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
83
- s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
88
+ s.add_dependency(%q<encryptor>, ["~> 1.1"])
89
+ s.add_dependency(%q<commander>, ["~> 4.1"])
90
+ s.add_dependency(%q<activesupport>, ["~> 3.2"])
91
+ s.add_dependency(%q<jbuilder>, ["~> 0.4"])
92
+ s.add_dependency(%q<rdoc>, ["~> 3.1"])
93
+ s.add_dependency(%q<bundler>, ["~> 1.1"])
94
+ s.add_dependency(%q<jeweler>, ["~> 1.8"])
84
95
  end
85
96
  else
86
- s.add_dependency(%q<encryptor>, [">= 0"])
87
- s.add_dependency(%q<commander>, [">= 0"])
88
- s.add_dependency(%q<activesupport>, [">= 0"])
89
- s.add_dependency(%q<rdoc>, ["~> 3.12"])
90
- s.add_dependency(%q<bundler>, ["~> 1.0.0"])
91
- s.add_dependency(%q<jeweler>, ["~> 1.8.3"])
97
+ s.add_dependency(%q<encryptor>, ["~> 1.1"])
98
+ s.add_dependency(%q<commander>, ["~> 4.1"])
99
+ s.add_dependency(%q<activesupport>, ["~> 3.2"])
100
+ s.add_dependency(%q<jbuilder>, ["~> 0.4"])
101
+ s.add_dependency(%q<rdoc>, ["~> 3.1"])
102
+ s.add_dependency(%q<bundler>, ["~> 1.1"])
103
+ s.add_dependency(%q<jeweler>, ["~> 1.8"])
92
104
  end
93
105
  end
94
106
 
@@ -44,12 +44,12 @@
44
44
  <td colspan="2">
45
45
  This <a href="http://rdoc.info/github/nerab/pwl/master/frames">pwl</a> export was created on <%= DateTime.now.strftime('%F %R') %>.
46
46
  <br/>
47
- The database at <%= store.path %> was <%= "last modified #{store.last_modified.strftime('%F %R')}" rescue 'never modified' %>.
47
+ The database at <%= locker.path %> was <%= "last modified #{locker.last_modified.strftime('%F %R')}" rescue 'never modified' %>.
48
48
  </td>
49
49
  </tr>
50
50
  </tfoot>
51
51
  <tbody>
52
- <% store.all.each{|key, value|%>
52
+ <% locker.all.each{|key, value|%>
53
53
  <tr>
54
54
  <td><%= key %></td>
55
55
  <td><%= value %></td>
@@ -0,0 +1,19 @@
1
+ require 'helper'
2
+
3
+ # Tests `pwl add`
4
+ class TestAdd < Test::Pwl::AppTestCase
5
+ def test_add_blank_key
6
+ assert_error('may not be blank', 'add')
7
+ end
8
+
9
+ def test_add_simple
10
+ assert_successful('', 'add foo bar')
11
+ assert_successful('^bar$', 'get foo')
12
+ end
13
+
14
+ def test_add_update
15
+ assert_successful('', 'add foo bar')
16
+ assert_successful('', 'add foo baz') # just do it twice
17
+ assert_successful('^baz$', 'get foo')
18
+ end
19
+ end
@@ -7,7 +7,7 @@ class TestDelete < Test::Pwl::AppTestCase
7
7
  end
8
8
 
9
9
  def test_delete_simple
10
- assert_successful('', 'put foo bar')
10
+ assert_successful('', 'add foo bar')
11
11
  assert_successful('', 'delete foo')
12
12
  assert_error('No entry was found for foo', 'get foo')
13
13
  end
@@ -4,23 +4,23 @@ require 'nokogiri/diff'
4
4
  # Tests `pwl export`
5
5
  class TestExport < Test::Pwl::AppTestCase
6
6
  def test_empty
7
- fixture = fixture("test_empty.html").gsub('CREATED_STAMP', DateTime.now.strftime('%F %R')).gsub('MODIFIED_STAMP', 'never').gsub('DATABASE_FILE', store_file)
7
+ fixture = fixture("test_empty.html").gsub('CREATED_STAMP', DateTime.now.strftime('%F %R')).gsub('MODIFIED_STAMP', 'never').gsub('DATABASE_FILE', locker_file)
8
8
  assert_successful_html(fixture, 'export')
9
9
  end
10
10
 
11
11
  def test_all
12
12
  test_vector = Hash['foo', 'one', 'bar', 'two', 'Chuck Norris', 'Roundhouse Kick']
13
13
  test_vector.each{|k,v|
14
- assert_successful('', "put '#{k}' '#{v}'")
14
+ assert_successful('', "add '#{k}' '#{v}'")
15
15
  }
16
16
 
17
17
  now = DateTime.now.strftime('%F %R')
18
- fixture = fixture("test_all.html").gsub('CREATED_STAMP', now).gsub('MODIFIED_STAMP', now).gsub('DATABASE_FILE', store_file)
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
 
23
- def assert_successful_html(expected_out, cmd, password = store_password)
23
+ def assert_successful_html(expected_out, cmd, password = locker_password)
24
24
  out, err, rc = execute(cmd, password)
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}")
@@ -0,0 +1,59 @@
1
+ require 'helper'
2
+ require 'json'
3
+
4
+ # Tests `pwl export --format json`
5
+ class TestExportJSON < Test::Pwl::AppTestCase
6
+ def test_empty
7
+ fixture = fixture("test_empty.json")
8
+ assert_successful_json(fixture, 'export --format json')
9
+ end
10
+
11
+ def test_all
12
+ test_vector = Hash['foo', 'one', 'bar', 'two', 'Chuck Norris', 'Roundhouse Kick']
13
+ test_vector.each{|k,v|
14
+ assert_successful('', "add '#{k}' '#{v}'")
15
+ }
16
+
17
+ now = DateTime.now.strftime('%F %R')
18
+ fixture = fixture("test_all.json")
19
+
20
+ assert_successful_json(fixture, 'export --format json')
21
+ end
22
+
23
+ def assert_successful_json(expected_out, cmd, password = locker_password)
24
+ out, err, rc = execute(cmd, password)
25
+ assert_equal(0, rc.exitstatus, "Expected exit status 0, but it was #{rc.exitstatus}. STDERR was: #{err}")
26
+ assert(err.empty?, "Expected empty STDERR, but it yielded #{err}")
27
+
28
+ actual = JSON.parse(out)
29
+ expected = JSON.parse(expected_out)
30
+
31
+ # fix up actuals to match expectations
32
+ actual["created"] = "2012-03-28T21:54:21+02:00"
33
+ actual["last_accessed"] = "2012-03-28T22:01:49+02:00"
34
+ actual["last_modified"] = "2012-03-29T22:46:29+02:00"
35
+
36
+ # This is essentially the same as
37
+ # assert_equal(expected, actual)
38
+ # but it provides better diagnostic output on error
39
+ json_diff(expected, actual)
40
+ end
41
+
42
+ private
43
+ def json_diff(expected, actual, context = nil)
44
+ assert_equal(expected.class, actual.class)
45
+
46
+ case expected
47
+ when Hash
48
+ actual.keys.each do |key|
49
+ json_diff(expected[key], actual[key], "#{context}/#{String == expected[key].class ? '@' : ''}#{key}")
50
+ end
51
+ when Array
52
+ actual.each_with_index do |e, i|
53
+ json_diff(expected[i], actual[i], "#{context}[#{i}]")
54
+ end
55
+ else
56
+ assert_equal(expected, actual, "#{context} is not the same:")
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,59 @@
1
+ require 'helper'
2
+ require 'yaml'
3
+
4
+ # Tests `pwl export --format yaml`
5
+ class TestExportYAML < Test::Pwl::AppTestCase
6
+ def test_empty
7
+ fixture = fixture("test_empty.yaml")
8
+ assert_successful_yaml(fixture, 'export --format yaml')
9
+ end
10
+
11
+ def test_all
12
+ test_vector = Hash['foo', 'one', 'bar', 'two', 'Chuck Norris', 'Roundhouse Kick']
13
+ test_vector.each{|k,v|
14
+ assert_successful('', "add '#{k}' '#{v}'")
15
+ }
16
+
17
+ now = DateTime.now.strftime('%F %R')
18
+ fixture = fixture("test_all.yaml")
19
+
20
+ assert_successful_yaml(fixture, 'export --format yaml')
21
+ end
22
+
23
+ def assert_successful_yaml(expected_out, cmd, password = locker_password)
24
+ out, err, rc = execute(cmd, password)
25
+ assert_equal(0, rc.exitstatus, "Expected exit status 0, but it was #{rc.exitstatus}. STDERR was: #{err}")
26
+ assert(err.empty?, "Expected empty STDERR, but it yielded #{err}")
27
+
28
+ actual = YAML.load(out)
29
+ expected = YAML.load(expected_out)
30
+
31
+ # fix up actuals to match expectations
32
+ actual[:created] = "2012-03-28T21:54:21+02:00"
33
+ actual[:last_accessed] = "2012-03-28T22:01:49+02:00"
34
+ actual[:last_modified] = "2012-03-29T22:46:29+02:00"
35
+
36
+ # This is essentially the same as
37
+ # assert_equal(expected, actual)
38
+ # but it provides better diagnostic output on error
39
+ yaml_diff(expected, actual)
40
+ end
41
+
42
+ private
43
+ def yaml_diff(expected, actual, context = nil)
44
+ #assert_equal(expected.class, actual.class)
45
+
46
+ case expected
47
+ when Hash
48
+ actual.keys.each do |key|
49
+ yaml_diff(expected[key], actual[key], "#{context}/#{String == expected[key].class ? '@' : ''}#{key}")
50
+ end
51
+ when Array
52
+ actual.each_with_index do |e, i|
53
+ yaml_diff(expected[i], actual[i], "#{context}[#{i}]")
54
+ end
55
+ else
56
+ assert_equal(expected, actual, "#{context} is not the same:")
57
+ end
58
+ end
59
+ end
@@ -11,7 +11,7 @@ class TestGet < Test::Pwl::AppTestCase
11
11
  end
12
12
 
13
13
  def test_get_known_key
14
- assert_successful('', 'put foo bar') # TODO Use a fixture instead of put
14
+ assert_successful('', 'add foo bar') # TODO Use a fixture instead of add
15
15
  assert_successful('^bar$', 'get foo')
16
16
  end
17
17
  end
@@ -13,11 +13,11 @@ class TestInit < Test::Pwl::AppTestCase
13
13
  # **************
14
14
  # Enter master password again:
15
15
  # **************
16
- # Successfully initialized new store at ...
16
+ # Successfully initialized new locker at ...
17
17
  # $
18
18
  #
19
19
  def test_matching_passwords
20
- cmd = "bin/pwl init --force --verbose --file \"#{@store_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)
@@ -26,7 +26,7 @@ class TestInit < Test::Pwl::AppTestCase
26
26
  assert_response('Enter master password again:', pwl_out)
27
27
  pwl_in.puts("secr3tPassw0rd")
28
28
 
29
- assert_response('Successfully initialized new store', pwl_out)
29
+ assert_response('Successfully initialized new locker', pwl_out)
30
30
  }
31
31
  end
32
32
 
@@ -44,7 +44,7 @@ class TestInit < Test::Pwl::AppTestCase
44
44
  # $
45
45
  #
46
46
  def test_unmatching_passwords
47
- cmd = "bin/pwl init --force --verbose --file \"#{store_file}\""
47
+ cmd = "bin/pwl init --force --verbose --file \"#{locker_file}\""
48
48
 
49
49
  PTY.spawn(cmd){|pwl_out, pwl_in, pid|
50
50
  assert_response('Enter new master password:', pwl_out)
@@ -58,14 +58,14 @@ class TestInit < Test::Pwl::AppTestCase
58
58
  end
59
59
 
60
60
  #
61
- # Tests that initing an existing store without --force does not touch the existing store
61
+ # Tests that initing an existing locker without --force does not touch the existing locker
62
62
  #
63
63
  def test_exists
64
64
  assert_error('already exists', "init")
65
65
  end
66
66
 
67
67
  #
68
- # Tests that cancelling a forced re-init does not change the store file
68
+ # Tests that cancelling a forced re-init does not change the locker file
69
69
  #
70
70
  def test_cancel
71
71
  # TODO
@@ -3,7 +3,7 @@ require 'helper'
3
3
  # Tests `pwl list`
4
4
  class TestList < Test::Pwl::AppTestCase
5
5
  def test_list_empty
6
- assert_empty(store.list)
6
+ assert_empty(locker.list)
7
7
  assert_error('^$', 'list')
8
8
  assert_error('^List is empty\.$', 'list --verbose')
9
9
  end
@@ -11,7 +11,7 @@ class TestList < Test::Pwl::AppTestCase
11
11
  def test_list_all
12
12
  test_vector = Hash['foo', 'one', 'bar', 'two', 'Chuck Norris', 'Roundhouse Kick']
13
13
  test_vector.each{|k,v|
14
- assert_successful('', "put '#{k}' '#{v}'")
14
+ assert_successful('', "add '#{k}' '#{v}'")
15
15
  }
16
16
 
17
17
  assert_successful(test_vector.keys.join('-'), 'list -s "-"')
@@ -20,7 +20,7 @@ class TestList < Test::Pwl::AppTestCase
20
20
  def test_list_filter
21
21
  test_vector = Hash['foo', 'one', 'foot', 'two', 'Homer Simpson', 'Apu Nahasapeemapetilon']
22
22
  test_vector.each{|k,v|
23
- assert_successful('', "put '#{k}' '#{v}'")
23
+ assert_successful('', "add '#{k}' '#{v}'")
24
24
  }
25
25
 
26
26
  filter = 'foo'