pwl 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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'