purse 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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
+