purse 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2008-07-19
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
@@ -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.
@@ -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
@@ -0,0 +1,2 @@
1
+
2
+ For more information on purse, see http://quirkey.com/blog
@@ -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.
@@ -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 }
@@ -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)
@@ -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'
@@ -0,0 +1,238 @@
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 NoMethodError => e
39
+ say("Sorry, there is no action #{action}.\nTry purse --help for a list of commands.")
40
+ end
41
+ hr
42
+ end
43
+
44
+ protected
45
+ def settings
46
+ h1('Setup utility')
47
+ hr
48
+ say("loading settings from : #{Settings.path}")
49
+ Settings.load
50
+ settings = {}
51
+ settings[:root_path] = cli.ask("Root Path for pockets? ") {|q| q.default = Settings.get(:root_path) || File.join(File.expand_path('~'), '.purse', 'pockets') }
52
+ settings[:editor] = cli.ask("Editor for notes? ") {|q| q.default = Settings.get(:editor) || 'vim' }
53
+ hr
54
+ say("saving settings to : #{Settings.path}")
55
+ Settings.settings = settings
56
+ end
57
+
58
+ def init(pocket_name)
59
+ pocket = Pocket.new(pocket_path(pocket_name))
60
+ pocket.init
61
+ pocket
62
+ end
63
+
64
+ def find(pocket_name, note_name)
65
+ say("loading note #{pocket_name}/#{note_name}")
66
+ hr
67
+ pocket = init(pocket_name)
68
+ note = pocket.find(note_name)
69
+ display(note)
70
+ rescue MissingFile
71
+ say("could not find note: #{pocket_name}/#{note_name}")
72
+ if cli.agree("would you like to create it? (y/n)")
73
+ edit(pocket_name, note_name)
74
+ end
75
+ end
76
+
77
+ def display(note)
78
+ decrypt(note)
79
+ h1("Note: #{note.name}",:green)
80
+ hr
81
+ say(note.data)
82
+ hr
83
+ end
84
+
85
+ def save(note, password = nil)
86
+ password ||= cli.ask("Password: ") { |q| q.echo = false }
87
+ note.save(password)
88
+ end
89
+
90
+ def decrypt(note)
91
+ return unless note.encrypted?
92
+ password = cli.ask("Password: ") { |q| q.echo = false }
93
+ note.decrypt(password)
94
+ password
95
+ end
96
+
97
+ def edit(pocket_name, note_name)
98
+ say("loading note #{pocket_name}/#{note_name}")
99
+ hr
100
+ pocket = init(pocket_name)
101
+ pocket.edit(note_name) do |note|
102
+ password = decrypt(note)
103
+ tmp_path = empty_temp_path
104
+ File.open(tmp_path, 'w') {|f| f << note.data }
105
+ execute("#{editor} #{tmp_path}")
106
+ sleep(2)
107
+ data = ""
108
+ File.open(tmp_path, 'r') {|f| data << f.read }
109
+ note.data = data
110
+ hr
111
+ say("saving note #{pocket_name}/#{note_name}")
112
+ save(note, password)
113
+ end
114
+ end
115
+
116
+ def delete(pocket_name, note_name = nil)
117
+ pocket = init(pocket_name)
118
+ if note_name
119
+ note = pocket.find(note_name)
120
+ note.delete if cli.agree("are you sure you want to delete #{pocket_name}/#{note_name}? (y/n)")
121
+ else
122
+ pocket.delete if cli.agree("are you sure you want to delete /#{pocket_name}? (y/n)")
123
+ end
124
+ end
125
+
126
+ def push(pocket_name)
127
+ pocket = init(pocket_name)
128
+ say("Committing local changes for #{pocket_name}")
129
+ pocket.commit
130
+ hr
131
+ set_remote(pocket_name)
132
+ say("Pulling changes from remote (#{pocket.remote})")
133
+ pocket.pull
134
+ hr
135
+ sary("Pushing changes to remote (#{pocket.remote})")
136
+ pocket.push
137
+ end
138
+
139
+ def pull(pocket_name)
140
+ pocket = init(pocket_name)
141
+ say("Committing local changes for #{pocket_name}")
142
+ pocket.commit
143
+ hr
144
+ set_remote(pocket_name)
145
+ say("Pulling changes from remote (#{pocket.remote})")
146
+ pocket.pull
147
+ end
148
+
149
+ def set_remote(pocket_name)
150
+ pocket = init(pocket_name)
151
+ unless pocket.remote
152
+ remote_url = cli.ask("please enter your remote git url (git@github ...)")
153
+ pocket.set_remote(remote_url)
154
+ say("set remote to #{remote_url}")
155
+ end
156
+ end
157
+
158
+ def help(*args)
159
+ h1("Help", :yellow)
160
+ hr
161
+ help_text = File.open(File.join(File.dirname(__FILE__),'help.txt')) {|f| f.read }
162
+ say(help_text)
163
+ end
164
+
165
+ def list(pocket_name = nil, note_name = nil)
166
+ unless pocket_name
167
+ h1("Listing your Pockets", :green)
168
+ hr
169
+ pockets = Dir[File.join(Settings.get(:root_path), '*')].find_all {|file| File.directory?(file) }
170
+ if pockets.empty?
171
+ say("no pockets yet. create one with 'purse pocketname'")
172
+ else
173
+ pockets.each {|p| say("/#{File.basename(p)}/") }
174
+ end
175
+ else
176
+ pocket = init(pocket_name)
177
+ say("Notes in <%= color '(#{pocket_name})', :red %>")
178
+ hr
179
+ pocket.notes.each do |note|
180
+ say("- #{note.name}")
181
+ end
182
+ end
183
+ end
184
+
185
+ def settings_exist?
186
+ return if Settings.get(:root_path) && Settings.get(:editor)
187
+ h1("you must configure purse before you use it", :red)
188
+ settings
189
+ say("rerun this utility any time with purse --settings")
190
+ exit
191
+ end
192
+
193
+ def pocket_path(pocket_name)
194
+ File.join(Settings.get(:root_path), pocket_name)
195
+ end
196
+
197
+ def editor
198
+ Settings.get(:editor)
199
+ end
200
+
201
+ def banner
202
+ hr
203
+ h1('/ Purse /', :white)
204
+ hr
205
+ end
206
+
207
+ def h1(text, color = :red)
208
+ say("<%= color('#{text}', :#{color}) %>")
209
+ end
210
+
211
+ def hr(color = :magenta)
212
+ say("<%= color('-' * 40, :#{color}) %>")
213
+ end
214
+
215
+ def say(message)
216
+ cli.say(message)
217
+ end
218
+
219
+ def cli
220
+ @cli ||= HighLine.new
221
+ end
222
+
223
+ def execute(command)
224
+ `#{command}`
225
+ end
226
+
227
+ def random_temp_name
228
+ "#{rand Time.now.to_i}-#{rand(1000)}--"
229
+ end
230
+
231
+ def empty_temp_path
232
+ temp_dir = File.join(Settings.get(:root_path), 'tmp')
233
+ FileUtils.mkdir_p(temp_dir)
234
+ File.join(temp_dir, random_temp_name)
235
+ end
236
+ end
237
+ end
238
+ 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
+