Skip to content
Browse files

Add simple HTML export using built-in ERB template

  • Loading branch information...
1 parent 7b96209 commit 91bafd195d6a0bfe833b1ec0a8c3bf4f69dcfbd7 Nicholas E. Rabenau committed Mar 10, 2012
View
32 bin/pwm
@@ -27,14 +27,16 @@ program :help, 'Exit Status', "#{program(:name)} sets the following exit status
program :help, 'Author', 'Nicholas E. Rabenau <nerab@gmx.at>'
DEFAULT_STORE_FILE = File.expand_path("~/.#{program(:name)}.pstore")
+DEFAULT_EXPORT_TEMPLATE = File.join(File.dirname(__FILE__), *%w[.. templates export.html.erb])
+
store_file = DEFAULT_STORE_FILE
global_option '-V', '--verbose', 'Enable verbose output'
global_option('-f', '--file FILE', 'Determine the file that holds the store'){|file| store_file = file}
global_option '-g', '--gui', 'Request the master password using an OS-specific GUI dialog. This option takes precedence over STDIN.'
command :init do |c|
- c.syntax = "#{program(:name)} init"
+ c.syntax = "#{program(:name)} #{c.name}"
c.summary = 'Initializes a new store'
c.description = 'This command initializes a new password store. Password quality is enforced using validation rules.'
c.example "Initializes a new password store in #{DEFAULT_STORE_FILE}", "#{program(:name)} #{c.name}"
@@ -68,7 +70,7 @@ command :init do |c|
end
command :get do |c|
- c.syntax = "#{program(:name)} get NAME"
+ c.syntax = "#{program(:name)} #{c.name} NAME"
c.summary = 'Retrieves the value for NAME and prints it to STDOUT.'
c.description = 'This command retrieves the value stored under NAME and prints it on STDOUT.'
c.example 'Reads the value stored under the name "foo" and prints it to STDOUT', "#{program(:name)} #{c.name} foo"
@@ -91,7 +93,7 @@ command :get do |c|
end
command :list do |c|
- c.syntax = "#{program(:name)} list [FILTER]"
+ c.syntax = "#{program(:name)} #{c.name} [FILTER]"
c.summary = 'Lists all names with optional FILTER.'
c.description = 'This command prints all names to STDOUT. If present, only those names matching FILTER will be returned.'
c.example 'Prints all names', "#{program(:name)} #{c.name}"
@@ -122,7 +124,7 @@ command :list do |c|
end
command :put do |c|
- c.syntax = "#{program(:name)} put NAME [VALUE]"
+ c.syntax = "#{program(:name)} #{c.name} NAME [VALUE]"
c.summary = 'Stores VALUE under NAME'
c.description = 'Adds or updates the entry stored under NAME. If NAME is already present in the store, it will be updated with VALUE. If NAME is not already present in the store, a new entry will be created. If VALUE is not given, it will be read from STDIN.'
c.example 'Stores the value "bar" under the name "foo"', "#{program(:name)} #{c.name} foo bar"
@@ -161,7 +163,7 @@ command :put do |c|
end
command :delete do |c|
- c.syntax = "#{program(:name)} delete NAME"
+ c.syntax = "#{program(:name)} #{c.name} NAME"
c.summary = 'Deletes the entry stored under NAME'
c.description = 'Deletes the complete entry that is stored under NAME. If NAME is not present in the store, an error will thrown.'
c.example 'Deletes what was stored under the name "foo"', "#{program(:name)} #{c.name} foo"
@@ -181,7 +183,7 @@ command :delete do |c|
end
command :passwd do |c|
- c.syntax = "#{program(:name)} passwd [NEW_MASTER_PASSWORD]"
+ c.syntax = "#{program(:name)} #{c.name} [NEW_MASTER_PASSWORD]"
c.summary = 'Changes the master password to NEW_MASTER_PASSWORD.'
c.description = 'This command changes the master password of the store. Password quality is enforced using validation rules.'
c.action do |args, options|
@@ -224,6 +226,24 @@ command :passwd do |c|
end
end
+command :export do |c|
+ c.syntax = "#{program(:name)} #{c.name}"
+ c.summary = 'Exports all entries.'
+ c.description = 'This command prints all entries to STDOUT.'
+ c.example 'Prints all entries', "#{program(:name)} #{c.name}"
+ c.action do |args, options|
+ exit_with(:file_not_found, options.verbose, :file => store_file) unless File.exists?(store_file)
+
+ begin
+ template = ERB.new(File.read(DEFAULT_EXPORT_TEMPLATE))
+ store = Pwm::Store.open(store_file, get_password('Enter master password:', options.gui))
+ puts template.result(binding)
+ rescue Pwm::Dialog::Cancelled
+ exit_with(:aborted, options.verbose)
+ end
+ end
+end
+
def exit_with(error_code, verbose, msg_args = {})
msg = EXIT_CODES[error_code]
raise "No message defined for error #{error_code}" if !msg
View
13 lib/pwm/store.rb
@@ -165,7 +165,7 @@ def delete(key)
end
#
- # Return all keys, optionally filtered by filter.
+ # Return all keys, optionally filtered by filter
#
def list(filter = nil)
@backend.transaction(true){
@@ -180,6 +180,17 @@ def list(filter = nil)
end
#
+ # Return all entries
+ #
+ def all
+ result = {}
+ @backend.transaction(true){
+ @backend[:user].each{|k,v| result[decrypt(k)] = decrypt(v)}
+ }
+ result
+ end
+
+ #
# Change the master password to +new_master_password+. Note that we don't take a password confirmation here.
# This is up to a UI layer.
#
View
38 templates/export.html.erb
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>pwd export</title>
+ <style type="text/css">
+ table { page-break-inside:auto }
+ tr { page-break-inside:avoid; page-break-after:auto }
+ thead { display:table-header-group }
+ tfoot { display:table-footer-group }
+ </style>
+</head>
+<body>
+ <table>
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>Value</th>
+ </tr>
+ </thead>
+ <tfoot>
+ <tr>
+ <td>Exported from pwm</td>
+ <td>Last modified: <%= store.last_modified.strftime('%F') rescue 'never' %></td>
+ <td></td>
+ </tr>
+ </tfoot>
+ <tbody>
+ <% store.all.each{|key, value|%>
+ <tr>
+ <td><%= key %></td>
+ <td><%= value %></td>
+ </tr>
+ <% } %>
+ </tbody>
+ </table>
+</body>
+</html>
View
19 test/acceptance/test_export.rb
@@ -0,0 +1,19 @@
+require 'helper'
+
+# Tests `pwm export`
+class TestExport < Test::Pwm::AppTestCase
+ def test_empty
+ fixture = fixture("test_empty.html").gsub('DATE_TIME_STAMP', 'never')
+# assert_successful(fixture, 'export')
+ end
+
+ def test_all
+ test_vector = Hash['foo', 'one', 'bar', 'two', 'Chuck Norris', 'Roundhouse Kick']
+ test_vector.each{|k,v|
+ assert_successful('', "put '#{k}' '#{v}'")
+ }
+
+ fixture = fixture("test_all.html").gsub('DATE_TIME_STAMP', DateTime.now.strftime('%F'))
+ assert_successful(fixture, 'export')
+ end
+end
View
48 test/fixtures/test_all.html
@@ -0,0 +1,48 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>pwd export</title>
+ <style type="text/css">
+ table { page-break-inside:auto }
+ tr { page-break-inside:avoid; page-break-after:auto }
+ thead { display:table-header-group }
+ tfoot { display:table-footer-group }
+ </style>
+</head>
+<body>
+ <table>
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>Value</th>
+ </tr>
+ </thead>
+ <tfoot>
+ <tr>
+ <td>Exported from pwm</td>
+ <td>Last modified: 2012-03-10</td>
+ <td></td>
+ </tr>
+ </tfoot>
+ <tbody>
+
+ <tr>
+ <td>foo</td>
+ <td>one</td>
+ </tr>
+
+ <tr>
+ <td>bar</td>
+ <td>two</td>
+ </tr>
+
+ <tr>
+ <td>Chuck Norris</td>
+ <td>Roundhouse Kick</td>
+ </tr>
+
+ </tbody>
+ </table>
+</body>
+</html>
View
33 test/fixtures/test_empty.html
@@ -0,0 +1,33 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <title>pwd export</title>
+ <style type="text/css">
+ table { page-break-inside:auto }
+ tr { page-break-inside:avoid; page-break-after:auto }
+ thead { display:table-header-group }
+ tfoot { display:table-footer-group }
+ </style>
+</head>
+<body>
+ <table>
+ <thead>
+ <tr>
+ <th>Name</th>
+ <th>Value</th>
+ </tr>
+ </thead>
+ <tfoot>
+ <tr>
+ <td>Exported from pwm</td>
+ <td>Last modified: DATE_TIME_STAMP</td>
+ <td></td>
+ </tr>
+ </tfoot>
+ <tbody>
+
+ </tbody>
+ </table>
+</body>
+</html>
View
5 test/helper.rb
@@ -18,6 +18,7 @@
require 'tmpdir'
class Test::Unit::TestCase
+ FIXTURES_DIR = File.join(File.dirname(__FILE__), 'fixtures')
end
module Test
@@ -69,6 +70,10 @@ def assert_error(expected_err, cmd, password = store_password)
def execute(cmd, password)
Open3.capture3("echo \"#{password}\" | #{APP} #{cmd} --file \"#{store_file}\"")
end
+
+ def fixture(name)
+ File.read(File.join(FIXTURES_DIR, name))
+ end
end
end
end
View
9 test/unit/test_store_crud.rb
@@ -45,6 +45,15 @@ def test_list
}
end
+ def test_all
+ test_vector = Hash['foo', 'one', 'bar', 'two', 'Chuck Norris', 'Roundhouse Kick']
+ test_vector.each{|k,v| store.put(k, v)}
+ assert_equal(test_vector, store.all)
+ store.all.each{|k,v|
+ assert_equal(test_vector[k], v)
+ }
+ end
+
def test_list_filter
test_vector = Hash['foo', 'one', 'bar', 'two', 'Chuck Norris', 'Roundhouse Kick']
test_vector.each{|k,v| store.put(k, v)}

0 comments on commit 91bafd1

Please sign in to comment.
Something went wrong with that request. Please try again.