shh 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Secret Squirrel
4
4
 
5
- This is a command line utility for managing secure information such as accounts, passwords as individual files so that they can be easily managed in a version control repository.
5
+ This is a command line utility for managing secure information such as accounts, passwords as individual files so that they can be easily managed in either a hg or git version control repository.
6
6
 
7
7
  You won't be hiding anything from the NSA with this level of encryption so it isn't recommended that you make your repository publicly accessible.
8
8
 
@@ -12,6 +12,8 @@ Now with more tab completion and multi line editing!
12
12
 
13
13
  Here you sit expectantly in front of a computer at the command line.
14
14
 
15
+ Either read the explanation below or checkout the following gist:
16
+
15
17
  == Install
16
18
 
17
19
  gem install shh
@@ -26,6 +28,8 @@ Opens all 'secrets' stored in foo/.secret
26
28
 
27
29
  > shh foo
28
30
 
31
+ Note that shh will crash if the parent directory of .secret does not contain either a .hg or .git.
32
+
29
33
  == Authenticate
30
34
 
31
35
  Enter your passphrase
@@ -36,52 +40,37 @@ This passphrase will be used to encrypt and decrypt all of your secrets so don't
36
40
 
37
41
  This mode allows you to view and edit 'entries' (which are encrypted hashes stored in files)
38
42
 
39
- > list
40
-
41
- bitbucket (260f34de-6779-4367-af2a-44184dec1cc1)
42
- amazon (291a3e6c-2c7b-4960-a146-1f6635d9a74e)
43
- yahoo (2fe408e7-7f2b-4dc0-854a-c92c21f131ae)
44
- evernote (41ad0a21-eafc-4f70-9b0d-0251be207b9e)
45
- gmail (8b35c1f2-851d-40fc-bd12-c2aad12c370a)
46
- rememberthemilk (a499f612-d034-4e49-82a8-6967d29653a1)
47
-
48
- * list - list entries
49
- * edit <name> - edit or create entry
50
- * view <name> - view entry
51
- * quit
52
-
53
- == Viewing mode
54
-
55
- This mode allows you to view (but not edit) an existing entry
56
-
57
- > view bitbucket
58
- (bitbucket) > list
59
- id,name,password,username
60
- (bitbucket) > view username
61
- markryall
43
+ > ls
62
44
 
63
- list keys, show key, copy key or quit? c password
45
+ amazon
46
+ bitbucket
47
+ evernote
48
+ gmail
49
+ rememberthemilk
50
+ yahoo
64
51
 
65
- * list - show entry keys
66
- * view <key> - view entry value on screen
67
- * copy <key> - copy entry value to clipboard
68
- * launch <key> - launch entry value in default browser (available if it starts with http)
69
- * run <key> - execute ruby script (available if it starts with #!/usr/bin/env ruby)
52
+ * ls - list entries
53
+ * cd <name> - edit or create entry
54
+ * history <name> - view changes related to an entry
55
+ * exhume <cs> <name> - view entry as at the specified changeset
70
56
  * quit
71
57
 
72
58
  == Editing mode
73
59
 
74
- This mode is viewing mode plus some editing commands
75
-
76
- > edit bitbucket
77
- (bitbucket) > set foo
60
+ > cd bitbucket
61
+ shh:bitbucket > set foo
78
62
  Enter new value for foo
79
63
  bar
80
64
  (bitbucket) > delete foo
81
65
 
66
+ * ls - list keys
82
67
  * edit <key> - edit or create key using text editor (notepad or EDITOR)
83
68
  * set <key> - edit or create key from prompt
84
- * delete <key> - remove a key
69
+ * cat/less/more - show the value associated with a key
70
+ * cp - copies the value of a key to the system clipboard
71
+ * launch - launches the value associated with the key (really only useful for launching a url)
72
+ * exec - executes the value associated with the key as a script (see scripting below)
73
+ * rm <key> - remove a key
85
74
 
86
75
  == Quitting mode
87
76
 
@@ -89,13 +78,9 @@ You don't want to be a quitter
89
78
 
90
79
  == Scripting
91
80
 
92
- In a script the following objects are available:
93
-
94
- * splat.clipboard = <text> - allows content to be copied to the clipboard
95
- * splat.browser - a watir compatible browser
96
- * hash - the current selected entry
81
+ In a script the current entry is available as a variable called 'entry'
97
82
 
98
- Example:
83
+ Very Contrived Example:
99
84
 
100
85
  browser = 'http://www.github.com/login'.to_browser
101
86
  browser.text_field(:id, 'login_field').set hash['username']
@@ -105,6 +90,5 @@ Example:
105
90
  = Future plans for world domination
106
91
 
107
92
  * Add some color
108
- * Add help
109
- * add some source control (hg/git) commands
110
- * add commands for displaying history of entries
93
+ * Add more history commands using source control (hg/git) commands
94
+ * Support other source control systems
data/bin/shh CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- $:.unshift File.dirname(__FILE__)+'/../lib'
3
+ $:.unshift File.expand_path(File.dirname(__FILE__))+'/../lib'
4
4
  require 'shh/cli'
5
- Shh::Cli.execute(*ARGV)
5
+ Shh::Cli.execute(*ARGV)
@@ -0,0 +1,28 @@
1
+ require 'crypt/blowfish'
2
+
3
+ module Shh
4
+ class BlowfishSerialiser
5
+ def initialize serialiser, passphrase
6
+ @blowfish = ::Crypt::Blowfish.new(passphrase)
7
+ @serialiser = serialiser
8
+ end
9
+
10
+ def read io
11
+ decrypted_io = StringIO.new
12
+ while l = io.read(8) do
13
+ decrypted_io.print @blowfish.decrypt_block(l)
14
+ end
15
+ @serialiser.read StringIO.new(decrypted_io.string.gsub("\0",''))
16
+ end
17
+
18
+ def write io, hash
19
+ serialised_io = StringIO.new
20
+ @serialiser.write serialised_io, hash
21
+ serialised_io.rewind
22
+ while l = serialised_io.read(8) do
23
+ while l.size < 8 do l += "\0" end
24
+ io.print @blowfish.encrypt_block(l)
25
+ end
26
+ end
27
+ end
28
+ end
data/lib/shh/cli.rb CHANGED
@@ -1,16 +1,20 @@
1
1
  require 'rubygems'
2
- require 'shh/repository'
3
2
  require 'shh/prompt'
4
3
  require 'shh/entries_menu'
4
+ require 'shh/blowfish_serialiser'
5
+ require 'flat_hash/serialiser'
6
+ require 'flat_hash/repository'
5
7
 
6
8
  module Shh
7
9
  class Cli
8
10
  def self.execute *args
9
11
  prompt = Prompt.new
10
12
  passphrase = prompt.ask('Enter your passphrase', :silent => true)
11
- path = args.shift || ('~')
12
-
13
- EntriesMenu.new(prompt, Repository.new(passphrase, path)).push
13
+ path = args.shift || '~'
14
+ Dir.chdir(File.expand_path(path)) do
15
+ serialiser = BlowfishSerialiser.new(FlatHash::Serialiser.new, passphrase)
16
+ EntriesMenu.new(prompt, FlatHash::Repository.new(serialiser, '.secret')).push
17
+ end
14
18
  end
15
19
  end
16
20
  end
@@ -0,0 +1,13 @@
1
+ class Shh::Command::CommitChanges
2
+ attr_reader :help
3
+
4
+ def initialize repository, io
5
+ @io, @repository = io, repository
6
+ @help = "Commits all pending changes to vcs (note that this will add _all_ pending changes not only cards)"
7
+ @usage = "<commit message>"
8
+ end
9
+
10
+ def execute text=nil
11
+ @repository.addremovecommit text
12
+ end
13
+ end
@@ -0,0 +1,26 @@
1
+ require 'active_support/core_ext/hash'
2
+ require 'shh/command/historic_entry_command'
3
+
4
+ class Shh::Command::DiffEntry
5
+ include Shh::Command::HistoricEntryCommand
6
+
7
+ def help
8
+ "Displays changes made since the specified revision of the entry\nRevision is a number representing the number of changesets to go back in history (ie. 0 is the most recently committed version)"
9
+ end
10
+
11
+ def execute text=nil
12
+ with_current_and_historic_entry(text) do |current, changeset, historic|
13
+ diff = current.diff(historic)
14
+ if diff.empty?
15
+ puts "no changes"
16
+ else
17
+ added = current.keys - historic.keys
18
+ removed = historic.keys-current.keys
19
+ modified = diff.keys - (added + removed)
20
+ puts "added #{added.join(',')}" unless added.empty?
21
+ puts "removed #{removed.join(',')}" unless removed.empty?
22
+ puts "modified #{modified.join(',')}" unless modified.empty?
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ module Shh::Command::EntriesCommand
2
+ def initialize entry, io
3
+ @entry, @io = entry, io
4
+ end
5
+
6
+ def usage
7
+ "<key name>"
8
+ end
9
+
10
+ def completion text
11
+ @entry.keys.grep(/^#{text}/).sort || []
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ require 'uuidtools'
2
+ require 'shh/command/historic_entry_command'
3
+ require 'shh/entry_menu'
4
+
5
+ class Shh::Command::ExhumeEntry
6
+ include Shh::Command::HistoricEntryCommand
7
+
8
+ def help
9
+ "Enters a subshell for viewing the specifed entry as it was at the specified revision\nRevision is a number representing the number of changesets to go back in history (ie. 0 is the most recently committed version)"
10
+ end
11
+
12
+ def execute text=nil
13
+ with_current_and_historic_entry(text) do |current, changeset, historic|
14
+ puts "warning: you are viewing #{historic['name']} as at #{changeset.id}, any changes you make will be discarded"
15
+ Shh::EntryMenu.new(@io, historic).push
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ module Shh::Command::HistoricEntryCommand
2
+ def initialize repository, io
3
+ @repository, @io = repository, io
4
+ end
5
+
6
+ def usage
7
+ "<entry name> <revision>"
8
+ end
9
+
10
+ def completion text
11
+ @repository.map{|entry| entry['name']}.grep(/^#{text}/).sort || []
12
+ end
13
+ private
14
+ def with_current_and_historic_entry text
15
+ if text =~ /^(.*) (\d+)$/
16
+ name, rev = $1, $2.to_i
17
+ return unless name
18
+ return if name.empty?
19
+ current = @repository.find { |entry| entry['name'] == name }
20
+ return unless current
21
+ cs = @repository.history(current.id)[rev]
22
+ return unless cs
23
+ yield current, cs, @repository.element_at(cs.id, current.id)
24
+ end
25
+ end
26
+ end
@@ -9,8 +9,15 @@ class Shh::Command::ListEntries
9
9
 
10
10
  def execute text=nil
11
11
  @repository.each do |entry|
12
- next if text and !(entry['name'] =~ /#{text}/)
13
- @io.say "#{entry['name']} (#{entry['id']})"
12
+ unless entry.id == entry['id']
13
+ puts "Encryption failure! Did you enter the correct password?"
14
+ return
15
+ end
16
+ end
17
+ @repository.sort{|l,r| (l['name']) <=> (r['name'])}.each do |entry|
18
+ description = "#{entry['name']} (#{entry.id})"
19
+ next if text and !(description =~ /#{text}/)
20
+ @io.say description
14
21
  end
15
22
  end
16
23
  end
@@ -15,9 +15,11 @@ class Shh::Command::OpenEntry
15
15
  end
16
16
 
17
17
  def execute name=nil
18
- entry = @repository.find_by_name(name)
19
- entry ||= {'name' => name, 'id' => UUIDTools::UUID.random_create.to_s}
18
+ return unless name
19
+ return if name.empty?
20
+ entry = @repository.find { |entry| entry['name'] == name }
21
+ entry ||= {'name' => name, 'id' => UUIDTools::UUID.random_create.to_s }
20
22
  Shh::EntryMenu.new(@io, entry).push
21
- @repository.persist entry
23
+ @repository[entry['id']] = entry
22
24
  end
23
25
  end
@@ -0,0 +1,26 @@
1
+ class Shh::Command::ShowHistory
2
+ attr_reader :usage, :help
3
+
4
+ def initialize repository, io
5
+ @repository, @io = repository, io
6
+ @usage = "(<substring>)"
7
+ @help = "Shows history for a given entry"
8
+ end
9
+
10
+ def completion text
11
+ @repository.map{|entry| entry['name']}.grep(/^#{text}/).sort || []
12
+ end
13
+
14
+ def execute name=nil
15
+ entry = @repository.find { |entry| entry['name'] == name }
16
+ id = entry ? entry.id : nil
17
+ first = true
18
+ @repository.history(id).each do |cs|
19
+ puts '-------' unless first
20
+ puts "#{cs.id} #{cs.time}"
21
+ puts "#{cs.author}"
22
+ puts "#{cs.description}"
23
+ first = false
24
+ end
25
+ end
26
+ end
@@ -12,5 +12,11 @@ class Shh::EntriesMenu
12
12
  'ls' => load_command(:list_entries, @repository, @io),
13
13
  'cd' => load_command(:open_entry, @repository, @io)
14
14
  }
15
+ if @repository.vcs_supported?
16
+ @commands['history'] = load_command(:show_history, @repository, @io)
17
+ @commands['exhume'] = load_command(:exhume_entry, @repository, @io)
18
+ @commands['diff'] = load_command(:diff_entry, @repository, @io)
19
+ @commands['ci'] = load_command(:commit_changes, @repository, @io)
20
+ end
15
21
  end
16
22
  end
@@ -7,11 +7,15 @@ class Shh::EntryMenu
7
7
 
8
8
  def initialize io, entry
9
9
  @io, @entry = io, entry
10
+ show_command = load_command(:show_key, entry, io)
11
+ edit_command = load_command(:edit_key, entry, io)
10
12
  @commands = {
11
13
  'ls' => load_command(:list_keys, entry, io),
12
14
  'set' => load_command(:set_key, entry, io),
13
- 'edit' => load_command(:edit_key, entry, io),
14
- 'cat' => load_command(:show_key, entry, io),
15
+ 'edit' => edit_command,
16
+ 'cat' => show_command,
17
+ 'less' => show_command,
18
+ 'more' => show_command,
15
19
  'cp' => load_command(:copy_key, entry, io),
16
20
  'launch' => load_command(:launch_key, entry, io),
17
21
  'rm' => load_command(:remove_key, entry, io),
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shh
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 11
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
8
  - 1
8
- - 7
9
- version: 0.1.7
9
+ - 8
10
+ version: 0.1.8
10
11
  platform: ruby
11
12
  authors:
12
13
  - Mark Ryall
@@ -14,121 +15,169 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-06-15 00:00:00 +10:00
18
+ date: 2010-08-21 00:00:00 +10:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
- name: highline
22
+ name: flat_hash
22
23
  prerelease: false
23
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
24
26
  requirements:
25
27
  - - ~>
26
28
  - !ruby/object:Gem::Version
29
+ hash: 27
27
30
  segments:
28
- - 1
29
- - 5
31
+ - 0
32
+ - 0
30
33
  - 2
31
- version: 1.5.2
34
+ version: 0.0.2
32
35
  type: :runtime
33
36
  version_requirements: *id001
34
37
  - !ruby/object:Gem::Dependency
35
- name: uuidtools
38
+ name: highline
36
39
  prerelease: false
37
40
  requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 13
46
+ segments:
47
+ - 1
48
+ - 6
49
+ - 1
50
+ version: 1.6.1
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: uuidtools
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
38
58
  requirements:
39
59
  - - ~>
40
60
  - !ruby/object:Gem::Version
61
+ hash: 9
41
62
  segments:
42
63
  - 2
43
64
  - 1
44
65
  - 1
45
66
  version: 2.1.1
46
67
  type: :runtime
47
- version_requirements: *id002
68
+ version_requirements: *id003
48
69
  - !ruby/object:Gem::Dependency
49
70
  name: crypt
50
71
  prerelease: false
51
- requirement: &id003 !ruby/object:Gem::Requirement
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
52
74
  requirements:
53
75
  - - ~>
54
76
  - !ruby/object:Gem::Version
77
+ hash: 27
55
78
  segments:
56
79
  - 1
57
80
  - 1
58
81
  - 4
59
82
  version: 1.1.4
60
83
  type: :runtime
61
- version_requirements: *id003
84
+ version_requirements: *id004
62
85
  - !ruby/object:Gem::Dependency
63
86
  name: splat
64
87
  prerelease: false
65
- requirement: &id004 !ruby/object:Gem::Requirement
88
+ requirement: &id005 !ruby/object:Gem::Requirement
89
+ none: false
66
90
  requirements:
67
91
  - - ~>
68
92
  - !ruby/object:Gem::Version
93
+ hash: 27
69
94
  segments:
70
95
  - 0
71
96
  - 1
72
97
  - 0
73
98
  version: 0.1.0
74
99
  type: :runtime
75
- version_requirements: *id004
100
+ version_requirements: *id005
76
101
  - !ruby/object:Gem::Dependency
77
102
  name: shell_shock
78
103
  prerelease: false
79
- requirement: &id005 !ruby/object:Gem::Requirement
104
+ requirement: &id006 !ruby/object:Gem::Requirement
105
+ none: false
80
106
  requirements:
81
107
  - - ~>
82
108
  - !ruby/object:Gem::Version
109
+ hash: 25
83
110
  segments:
84
111
  - 0
85
112
  - 0
86
113
  - 3
87
114
  version: 0.0.3
88
115
  type: :runtime
89
- version_requirements: *id005
116
+ version_requirements: *id006
117
+ - !ruby/object:Gem::Dependency
118
+ name: activesupport
119
+ prerelease: false
120
+ requirement: &id007 !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ hash: 19
126
+ segments:
127
+ - 2
128
+ - 3
129
+ - 8
130
+ version: 2.3.8
131
+ type: :runtime
132
+ version_requirements: *id007
90
133
  - !ruby/object:Gem::Dependency
91
134
  name: rake
92
135
  prerelease: false
93
- requirement: &id006 !ruby/object:Gem::Requirement
136
+ requirement: &id008 !ruby/object:Gem::Requirement
137
+ none: false
94
138
  requirements:
95
139
  - - ~>
96
140
  - !ruby/object:Gem::Version
141
+ hash: 49
97
142
  segments:
98
143
  - 0
99
144
  - 8
100
145
  - 7
101
146
  version: 0.8.7
102
147
  type: :development
103
- version_requirements: *id006
148
+ version_requirements: *id008
104
149
  - !ruby/object:Gem::Dependency
105
150
  name: gemesis
106
151
  prerelease: false
107
- requirement: &id007 !ruby/object:Gem::Requirement
152
+ requirement: &id009 !ruby/object:Gem::Requirement
153
+ none: false
108
154
  requirements:
109
155
  - - ~>
110
156
  - !ruby/object:Gem::Version
157
+ hash: 25
111
158
  segments:
112
159
  - 0
113
160
  - 0
114
161
  - 3
115
162
  version: 0.0.3
116
163
  type: :development
117
- version_requirements: *id007
164
+ version_requirements: *id009
118
165
  - !ruby/object:Gem::Dependency
119
166
  name: orangutan
120
167
  prerelease: false
121
- requirement: &id008 !ruby/object:Gem::Requirement
168
+ requirement: &id010 !ruby/object:Gem::Requirement
169
+ none: false
122
170
  requirements:
123
171
  - - ~>
124
172
  - !ruby/object:Gem::Version
173
+ hash: 17
125
174
  segments:
126
175
  - 0
127
176
  - 0
128
177
  - 7
129
178
  version: 0.0.7
130
179
  type: :development
131
- version_requirements: *id008
180
+ version_requirements: *id010
132
181
  description: |
133
182
  A command line utility that manages accounts and passwords as individual encypted files
134
183
 
@@ -140,10 +189,16 @@ extensions: []
140
189
  extra_rdoc_files: []
141
190
 
142
191
  files:
192
+ - lib/shh/blowfish_serialiser.rb
143
193
  - lib/shh/cli.rb
194
+ - lib/shh/command/commit_changes.rb
144
195
  - lib/shh/command/copy_key.rb
196
+ - lib/shh/command/diff_entry.rb
145
197
  - lib/shh/command/edit_key.rb
198
+ - lib/shh/command/entries_command.rb
146
199
  - lib/shh/command/execute_key.rb
200
+ - lib/shh/command/exhume_entry.rb
201
+ - lib/shh/command/historic_entry_command.rb
147
202
  - lib/shh/command/key_command.rb
148
203
  - lib/shh/command/launch_key.rb
149
204
  - lib/shh/command/list_entries.rb
@@ -151,13 +206,12 @@ files:
151
206
  - lib/shh/command/open_entry.rb
152
207
  - lib/shh/command/remove_key.rb
153
208
  - lib/shh/command/set_key.rb
209
+ - lib/shh/command/show_history.rb
154
210
  - lib/shh/command/show_key.rb
155
211
  - lib/shh/commands.rb
156
- - lib/shh/crypt.rb
157
212
  - lib/shh/entries_menu.rb
158
213
  - lib/shh/entry_menu.rb
159
214
  - lib/shh/prompt.rb
160
- - lib/shh/repository.rb
161
215
  - bin/shh
162
216
  - README.rdoc
163
217
  - MIT-LICENSE
@@ -171,23 +225,27 @@ rdoc_options: []
171
225
  require_paths:
172
226
  - lib
173
227
  required_ruby_version: !ruby/object:Gem::Requirement
228
+ none: false
174
229
  requirements:
175
230
  - - ">="
176
231
  - !ruby/object:Gem::Version
232
+ hash: 3
177
233
  segments:
178
234
  - 0
179
235
  version: "0"
180
236
  required_rubygems_version: !ruby/object:Gem::Requirement
237
+ none: false
181
238
  requirements:
182
239
  - - ">="
183
240
  - !ruby/object:Gem::Version
241
+ hash: 3
184
242
  segments:
185
243
  - 0
186
244
  version: "0"
187
245
  requirements: []
188
246
 
189
247
  rubyforge_project:
190
- rubygems_version: 1.3.6
248
+ rubygems_version: 1.3.7
191
249
  signing_key:
192
250
  specification_version: 3
193
251
  summary: command line utility for managing secure information
data/lib/shh/crypt.rb DELETED
@@ -1,25 +0,0 @@
1
- require 'crypt/blowfish'
2
-
3
- module Shh
4
- class Crypt
5
- def initialize passphrase
6
- @blowfish = ::Crypt::Blowfish.new(passphrase)
7
- end
8
-
9
- def encrypt text, out_io
10
- in_io = StringIO.new(text)
11
- while l = in_io.read(8) do
12
- while l.size < 8 do l += "\0" end
13
- out_io.print @blowfish.encrypt_block(l)
14
- end
15
- end
16
-
17
- def decrypt in_io
18
- out_io = StringIO.new
19
- while l = in_io.read(8) do
20
- out_io.print @blowfish.decrypt_block(l)
21
- end
22
- out_io.string.gsub("\0",'')
23
- end
24
- end
25
- end
@@ -1,44 +0,0 @@
1
- require 'yaml'
2
- require 'shh/crypt'
3
- require 'fileutils'
4
-
5
- module Shh
6
- class Repository
7
- include Enumerable
8
-
9
- attr_reader :folder
10
-
11
- def initialize passphrase, path
12
- @folder = Pathname.new(File.expand_path(path)) + '.secret'
13
- @folder.mkpath
14
- @crypt = Crypt.new(passphrase)
15
- end
16
-
17
- def each
18
- @folder.children.each do |child|
19
- entry = load(child)
20
- yield entry if entry
21
- end
22
- end
23
-
24
- def find_by_name name
25
- each {|e| return e if e['name'] == name}
26
- nil
27
- end
28
-
29
- def load path
30
- return nil if path.directory?
31
- yaml = path.open('rb') {|io| @crypt.decrypt(io) }
32
- entry = YAML::load(yaml)
33
- unless entry and path.basename.to_s == entry['id']
34
- $stderr.puts "failed to deserialise #{path}"
35
- return nil
36
- end
37
- entry
38
- end
39
-
40
- def persist entry
41
- (@folder + entry['id']).open('wb') {|io| @crypt.encrypt(entry.to_yaml, io) }
42
- end
43
- end
44
- end