quirkey-purse 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,10 @@
1
+ == 0.1.1 2008-10-29
2
+
3
+ * minor enhancements:
4
+ * Error handling for git integration
5
+ * Prompt before creating pockets
6
+
7
+ == 0.1.0 2008-10-28
8
+
9
+ * 1 major enhancement:
10
+ * Initial release
data/License.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Quirkey NYC, LLC
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest.txt ADDED
@@ -0,0 +1,15 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ PostInstall.txt
5
+ README.txt
6
+ Rakefile
7
+ bin/purse
8
+ lib/purse.rb
9
+ lib/purse/cli.rb
10
+ lib/purse/error.rb
11
+ lib/purse/note.rb
12
+ lib/purse/pocket.rb
13
+ lib/purse/settings.rb
14
+ lib/purse/version.rb
15
+ lib/purse/help.txt
data/PostInstall.txt ADDED
@@ -0,0 +1,2 @@
1
+
2
+ For more information on purse, see http://quirkey.com/blog
data/README.txt ADDED
@@ -0,0 +1,82 @@
1
+ = purse
2
+
3
+ http://quirkey.rubyforge.org/purse
4
+
5
+ == DESCRIPTION:
6
+
7
+ A simple way of storing private/sensitive info and then sharing it with others using git
8
+
9
+ == SYNOPSIS:
10
+
11
+ Purse stores information in a two level folder system. The basic piece of stored information is a 'note'.
12
+ A 'pocket' is a folder containing one to many notes. A *pocket* can be synced between mutlple users/computers
13
+ using a remote git repository.
14
+
15
+ To configure for the first time:
16
+
17
+ purse
18
+
19
+ and follow the handy on screen instructions.
20
+
21
+ To create a new pocket/note.
22
+
23
+ purse pocketname notename
24
+
25
+ It will prompt you asking if you want to create the note.
26
+ Once you've edited in your favorite editor and saved, purse
27
+ will use Blowfish to encrypt the note with the password you provide.
28
+
29
+ Then you can display the note with:
30
+
31
+ purse pocketname notename
32
+
33
+ or edit with:
34
+
35
+ purse pocketname notename --edit
36
+
37
+ Each time it will ask you for the password you initially provided to encrypt it.
38
+
39
+ For more commands/info run:
40
+
41
+ purse --help
42
+
43
+ == REQUIREMENTS:
44
+
45
+ purse requires a couple of gems, namely
46
+ highline -- for command line tools
47
+ termios
48
+ crypt -- for encryption
49
+ git -- for uh, git
50
+
51
+ == INSTALL:
52
+
53
+ sudo gem install purse
54
+
55
+ then run
56
+
57
+ purse
58
+
59
+ == LICENSE:
60
+
61
+ (The MIT License)
62
+
63
+ Copyright (c) 2008 Quirkey NYC, LLC
64
+
65
+ Permission is hereby granted, free of charge, to any person obtaining
66
+ a copy of this software and associated documentation files (the
67
+ 'Software'), to deal in the Software without restriction, including
68
+ without limitation the rights to use, copy, modify, merge, publish,
69
+ distribute, sublicense, and/or sell copies of the Software, and to
70
+ permit persons to whom the Software is furnished to do so, subject to
71
+ the following conditions:
72
+
73
+ The above copyright notice and this permission notice shall be
74
+ included in all copies or substantial portions of the Software.
75
+
76
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
77
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
78
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
79
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
80
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
81
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
82
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
data/bin/purse ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+
4
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'purse')
5
+
6
+ Purse::Cli.run(ARGV)
data/lib/purse.rb ADDED
@@ -0,0 +1,14 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'rubygems'
5
+ require 'git'
6
+ require 'crypt/blowfish'
7
+ require 'highline'
8
+ require 'yaml'
9
+
10
+ require 'purse/error'
11
+ require 'purse/settings'
12
+ require 'purse/pocket'
13
+ require 'purse/note'
14
+ require 'purse/cli'
data/lib/purse/cli.rb ADDED
@@ -0,0 +1,247 @@
1
+ module Purse
2
+ class Cli
3
+
4
+ ACTION_PREFIX = /^--/
5
+
6
+ # purse pursename #=> initialize or pull
7
+ # purse pursename notename #=> pocket.find(notename) if it doesnt exist first pull then ask if you want to create it
8
+ # purse pursename notename --edit #=> open in EDITOR save and push
9
+ # purse pursename push
10
+ # purse pursename pull
11
+ # purse settings/ purse # rerun settings
12
+ class << self
13
+ def run(args)
14
+ begin
15
+ banner
16
+ settings_exist?
17
+ action = args.detect {|a| a =~ ACTION_PREFIX }
18
+ args.reject! {|a| a == action}
19
+ pocket_name, note_name = args[0], args[1]
20
+ if !action.nil? && action != ''
21
+ action = action.gsub(ACTION_PREFIX,'')
22
+ send(action, *([pocket_name, note_name].compact))
23
+ else
24
+ case note_name
25
+ when 'push'
26
+ push(pocket_name)
27
+ when 'pull'
28
+ pull(pocket_name)
29
+ when ''
30
+ when nil
31
+ list(pocket_name)
32
+ else
33
+ find(pocket_name, note_name)
34
+ end
35
+ end
36
+ rescue MissingFile
37
+ say("Could not find note: #{pocket_name}/#{note_name}")
38
+ rescue Git::GitExecuteError => e
39
+ say(e)
40
+ rescue NoMethodError => e
41
+ say("Sorry, there is no action #{action}.\nTry purse --help for a list of commands. #{e}")
42
+ end
43
+ hr
44
+ end
45
+
46
+ protected
47
+ def settings
48
+ h1('Setup utility')
49
+ hr
50
+ say("loading settings from : #{Settings.path}")
51
+ Settings.load
52
+ settings = {}
53
+ settings[:root_path] = cli.ask("Root Path for pockets? ") {|q| q.default = Settings.get(:root_path) || File.join(File.expand_path('~'), '.purse', 'pockets') }
54
+ settings[:editor] = cli.ask("Editor for notes? ") {|q| q.default = Settings.get(:editor) || 'vim' }
55
+ hr
56
+ say("saving settings to : #{Settings.path}")
57
+ Settings.settings = settings
58
+ end
59
+
60
+ def init(pocket_name)
61
+ pocket = Pocket.new(pocket_path(pocket_name))
62
+ if !pocket.exists?
63
+ say("could not find pocket /#{pocket_name}")
64
+ if cli.agree("would you like to create it? (y/n)")
65
+ pocket.init
66
+ else
67
+ exit
68
+ end
69
+ end
70
+ pocket
71
+ end
72
+
73
+ def find(pocket_name, note_name)
74
+ say("loading note #{pocket_name}/#{note_name}")
75
+ hr
76
+ pocket = init(pocket_name)
77
+ note = pocket.find(note_name)
78
+ display(note)
79
+ rescue MissingFile
80
+ say("could not find note: #{pocket_name}/#{note_name}")
81
+ if cli.agree("would you like to create it? (y/n)")
82
+ edit(pocket_name, note_name)
83
+ end
84
+ end
85
+
86
+ def display(note)
87
+ decrypt(note)
88
+ h1("Note: #{note.name}",:green)
89
+ hr
90
+ say(note.data)
91
+ hr
92
+ end
93
+
94
+ def save(note, password = nil)
95
+ password ||= cli.ask("Password: ") { |q| q.echo = false }
96
+ note.save(password)
97
+ end
98
+
99
+ def decrypt(note)
100
+ return unless note.encrypted?
101
+ password = cli.ask("Password: ") { |q| q.echo = false }
102
+ note.decrypt(password)
103
+ password
104
+ end
105
+
106
+ def edit(pocket_name, note_name)
107
+ say("loading note #{pocket_name}/#{note_name}")
108
+ hr
109
+ pocket = init(pocket_name)
110
+ pocket.edit(note_name) do |note|
111
+ password = decrypt(note)
112
+ tmp_path = empty_temp_path
113
+ File.open(tmp_path, 'w') {|f| f << note.data }
114
+ execute("#{editor} #{tmp_path}")
115
+ sleep(2)
116
+ data = ""
117
+ File.open(tmp_path, 'r') {|f| data << f.read }
118
+ note.data = data
119
+ hr
120
+ say("saving note #{pocket_name}/#{note_name}")
121
+ save(note, password)
122
+ end
123
+ end
124
+
125
+ def delete(pocket_name, note_name = nil)
126
+ pocket = init(pocket_name)
127
+ if note_name
128
+ note = pocket.find(note_name)
129
+ note.delete if cli.agree("are you sure you want to delete #{pocket_name}/#{note_name}? (y/n)")
130
+ else
131
+ pocket.delete if cli.agree("are you sure you want to delete /#{pocket_name}? (y/n)")
132
+ end
133
+ end
134
+
135
+ def push(pocket_name)
136
+ pocket = init(pocket_name)
137
+ say("Committing local changes for #{pocket_name}")
138
+ pocket.commit
139
+ hr
140
+ set_remote(pocket_name)
141
+ say("Pulling changes from remote (#{pocket.remote})")
142
+ pocket.pull
143
+ hr
144
+ say("Pushing changes to remote (#{pocket.remote})")
145
+ pocket.push
146
+ end
147
+
148
+ def pull(pocket_name)
149
+ pocket = init(pocket_name)
150
+ say("Committing local changes for #{pocket_name}")
151
+ pocket.commit
152
+ hr
153
+ set_remote(pocket_name)
154
+ say("Pulling changes from remote (#{pocket.remote})")
155
+ pocket.pull
156
+ end
157
+
158
+ def set_remote(pocket_name)
159
+ pocket = init(pocket_name)
160
+ unless pocket.remote
161
+ remote_url = cli.ask("please enter your remote git url (git@github ...)")
162
+ pocket.set_remote(remote_url)
163
+ say("set remote to #{remote_url}")
164
+ end
165
+ end
166
+
167
+ def help(*args)
168
+ h1("Help", :yellow)
169
+ hr
170
+ help_text = File.open(File.join(File.dirname(__FILE__),'help.txt')) {|f| f.read }
171
+ say(help_text)
172
+ end
173
+
174
+ def list(pocket_name = nil, note_name = nil)
175
+ unless pocket_name
176
+ h1("Listing your Pockets", :green)
177
+ hr
178
+ pockets = Dir[File.join(Settings.get(:root_path), '*')].find_all {|file| File.directory?(file) }
179
+ if pockets.empty?
180
+ say("no pockets yet. create one with 'purse pocketname'")
181
+ else
182
+ pockets.each {|p| say("/#{File.basename(p)}/") }
183
+ end
184
+ else
185
+ pocket = init(pocket_name)
186
+ say("Notes in <%= color '(#{pocket_name})', :red %>")
187
+ hr
188
+ pocket.notes.each do |note|
189
+ say("- #{note.name}")
190
+ end
191
+ end
192
+ end
193
+
194
+ def settings_exist?
195
+ return if Settings.get(:root_path) && Settings.get(:editor)
196
+ h1("you must configure purse before you use it", :red)
197
+ settings
198
+ say("rerun this utility any time with purse --settings")
199
+ exit
200
+ end
201
+
202
+ def pocket_path(pocket_name)
203
+ File.join(Settings.get(:root_path), pocket_name)
204
+ end
205
+
206
+ def editor
207
+ Settings.get(:editor)
208
+ end
209
+
210
+ def banner
211
+ hr
212
+ h1('/ Purse /', :white)
213
+ hr
214
+ end
215
+
216
+ def h1(text, color = :red)
217
+ say("<%= color('#{text}', :#{color}) %>")
218
+ end
219
+
220
+ def hr(color = :magenta)
221
+ say("<%= color('-' * 40, :#{color}) %>")
222
+ end
223
+
224
+ def say(message)
225
+ cli.say(message)
226
+ end
227
+
228
+ def cli
229
+ @cli ||= HighLine.new
230
+ end
231
+
232
+ def execute(command)
233
+ `#{command}`
234
+ end
235
+
236
+ def random_temp_name
237
+ "#{rand Time.now.to_i}-#{rand(1000)}--"
238
+ end
239
+
240
+ def empty_temp_path
241
+ temp_dir = File.join(Settings.get(:root_path), 'tmp')
242
+ FileUtils.mkdir_p(temp_dir)
243
+ File.join(temp_dir, random_temp_name)
244
+ end
245
+ end
246
+ end
247
+ end
@@ -0,0 +1,10 @@
1
+ module Purse
2
+ class Error < RuntimeError; end
3
+
4
+ class MissingParameter < Error; end;
5
+ class MissingFile < Error; end
6
+
7
+ def self.check_for_parameter(name, param)
8
+ raise MissingParameter, "You must set a #{name}" if param.nil? || param.strip == ''
9
+ end
10
+ end
@@ -0,0 +1,54 @@
1
+ -- General --
2
+
3
+ Purse stores information in a two level folder system.
4
+ The basic piece of stored information is a 'note'.
5
+ A 'pocket' is a folder containing one to many notes.
6
+ A *pocket* can be synced between mutlple users/computers using a remote git repository.
7
+
8
+ -- Commands --
9
+
10
+ purse
11
+ purse --list
12
+
13
+ List Pockets
14
+
15
+ purse --help
16
+
17
+ Display this message
18
+
19
+ purse --settings
20
+
21
+ Run the settings utility
22
+
23
+ purse pocketname
24
+
25
+ List the notes in pocket 'pocketname'
26
+
27
+ purse pocketname --delete
28
+
29
+ Destroy the pocket: pocketname
30
+
31
+ purse pocketname --pull
32
+
33
+ Pull the pocket 'pocketname' from a remote git repository.
34
+ Will prompt for URL the first time its run.
35
+
36
+ purse pocketname --push
37
+
38
+ Push the pocket 'pocketname' to a remote git repository.
39
+ Will prompt for URL the first time its run.
40
+
41
+ purse pocketname notename
42
+
43
+ Display or create the note 'notename' in the pocket 'pocketname'.
44
+ Will prompt for password.
45
+
46
+ purse pocketname notename --edit
47
+
48
+ Edit or create the note 'notename' in the pocket 'pocketname'.
49
+ Will prompt for password.
50
+
51
+ purse pocketname notename --delete
52
+
53
+ Delete the note 'notename' in the pocket 'pocketname'.
54
+