yak 1.0.2 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/History.txt +21 -1
  2. data/README.txt +2 -1
  3. data/lib/yak.rb +149 -42
  4. metadata +23 -3
@@ -1,4 +1,24 @@
1
- === 1.0.1 / 2010-02-22
1
+ === 1.0.3 / 2010-02-22
2
+
3
+ * Enhancements:
4
+
5
+ * Added Dropbox support
6
+
7
+ * Added setup routine for first run
8
+
9
+ * Added -p option to print to stdout
10
+
11
+ * Added delete data option
12
+
13
+ * Customizable data file location
14
+
15
+ * Bugfixes:
16
+
17
+ * First run has setup
18
+
19
+ * Cipher error catching updated
20
+
21
+ === 1.0.2 / 2010-02-22
2
22
 
3
23
  * Renaming to Yak
4
24
 
data/README.txt CHANGED
@@ -15,7 +15,8 @@ Session is the length of time in seconds that Yak will remember the
15
15
  master password:
16
16
  :session: 30
17
17
 
18
- If using sessions is not desired and you want to enter the master, set:
18
+ If using sessions is not desired and you want to enter the
19
+ master password every time, set:
19
20
  :session: false
20
21
 
21
22
  Always set the password by default, use:
data/lib/yak.rb CHANGED
@@ -20,10 +20,12 @@ require 'session'
20
20
  # :password: plain_text_password
21
21
  # To turn off password confirmation prompts:
22
22
  # :confirm_prompt: false
23
+ # To set the path to the yak data file:
24
+ # :data_file: /path/to/file
23
25
 
24
26
  class Yak
25
27
 
26
- VERSION = "1.0.2"
28
+ VERSION = "1.0.3"
27
29
 
28
30
  DEFAULT_CONFIG = {:session => 30}
29
31
 
@@ -34,35 +36,83 @@ class Yak
34
36
  # ...
35
37
 
36
38
  def self.run argv=ARGV
37
- config = DEFAULT_CONFIG.merge load_config
39
+ user = `whoami`.chomp
40
+
41
+ check_user_setup user
42
+
43
+ config = DEFAULT_CONFIG.merge load_config(user)
38
44
 
39
45
  options = parse_args argv
40
46
 
41
- yak = new `whoami`.chomp, config
47
+ yak = new user, config
48
+
49
+ yak.connect_data
50
+ yak.start_session
42
51
 
43
52
  args = [options[:action], yak, options[:key], options[:value]].compact
44
53
 
45
54
  self.send(*args)
46
55
 
47
- rescue OpenSSL::CipherError => e
56
+ rescue OpenSSL::Cipher::CipherError => e
48
57
  $stderr << "Bad password.\n"
49
58
  exit 1
50
59
  end
51
60
 
52
61
 
53
62
  ##
54
- # Load the ~/.yakrc file and return. Creates ~/.yakrc with the
55
- # default config if missing.
63
+ # Setup yak for first run if it hasn't been.
64
+
65
+ def self.check_user_setup user
66
+ user_config_file = yak_config_file user
67
+
68
+ return if File.file? user_config_file
69
+
70
+ hl = HighLine.new $stdin, $stderr
71
+ hl.say "Thanks for installing Yak!"
72
+
73
+ data_file_opts = []
56
74
 
57
- def self.load_config
58
- config_file = File.expand_path "~/.yakrc"
75
+ usrhome = File.expand_path "~#{user}/"
76
+ dropbox = File.expand_path "~#{user}/Dropbox"
59
77
 
60
- if !File.file?(config_file)
61
- File.open(config_file, "w+"){|f| f.write DEFAULT_CONFIG.to_yaml }
62
- $stderr << "Created Yak config file #{config_file}\n"
78
+ data_file_opts << dropbox if File.directory? dropbox
79
+ data_file_opts << usrhome if File.directory? usrhome
80
+
81
+ data_path = hl.choose do |menu|
82
+ menu.prompt = "Where would you like your data file to live?"
83
+ menu.choices(*data_file_opts)
84
+ menu.choice "other" do
85
+ hl.ask "Enter path:"
86
+ end
63
87
  end
64
88
 
65
- YAML.load_file config_file
89
+ data_file = File.join data_path, ".yakdata"
90
+ new_config = DEFAULT_CONFIG.merge(:data_file => data_file)
91
+
92
+ make_config_file user, new_config
93
+ end
94
+
95
+
96
+ ##
97
+ # Load the ~/.yakrc file and return.
98
+
99
+ def self.load_config user
100
+ user_config_file = yak_config_file user
101
+
102
+ YAML.load_file user_config_file
103
+ end
104
+
105
+
106
+ ##
107
+ # Create a new user config file.
108
+
109
+ def self.make_config_file user, new_config=DEFAULT_CONFIG
110
+ user_config_file = yak_config_file user
111
+ config_str = new_config.to_yaml
112
+
113
+ File.open(user_config_file, "w+"){|f| f.write config_str }
114
+ $stderr << "Created Yak config file #{user_config_file}:\n"
115
+ $stderr << "#{config_str}\n"
66
116
  end
67
117
 
68
118
 
@@ -83,6 +133,16 @@ class Yak
83
133
  end
84
134
 
85
135
 
136
+ def self.print_password yak, name
137
+ $stdout << "#{yak.retrieve(name)}\n"
138
+ end
139
+
140
+
141
+ def self.delete_data yak
142
+ yak.delete_data_file! true
143
+ end
144
+
145
+
86
146
  def self.list yak, name=nil
87
147
  key_regex = /#{name || ".+"}/
88
148
 
@@ -118,6 +178,11 @@ class Yak
118
178
  end
119
179
 
120
180
 
181
+ def self.yak_config_file user
182
+ File.expand_path "~#{user}/.yakrc"
183
+ end
184
+
185
+
121
186
  def self.parse_args argv
122
187
  options = {}
123
188
 
@@ -164,6 +229,17 @@ Retrieved passwords get copied to the clipboard by default.
164
229
  'Update the password used for encryption') do |value|
165
230
  options[:action] = :new_password
166
231
  end
232
+
233
+ opt.on('-p', '--print KEY',
234
+ 'Print the password for the given key to stdout') do |key|
235
+ options[:action] = :print_password
236
+ options[:key] = key
237
+ end
238
+
239
+ opt.on('--delete-data',
240
+ 'Delete the data file - lose all saved info') do
241
+ options[:action] = :delete_data
242
+ end
167
243
  end
168
244
 
169
245
  opts.parse! argv
@@ -172,6 +248,11 @@ Retrieved passwords get copied to the clipboard by default.
172
248
  options[:key] ||= argv.shift
173
249
  options[:value] ||= argv.shift
174
250
 
251
+ if options[:action] == :retrieve && options[:key].nil?
252
+ $stderr << opts.to_s
253
+ exit 1
254
+ end
255
+
175
256
  options
176
257
  end
177
258
 
@@ -192,24 +273,21 @@ Retrieved passwords get copied to the clipboard by default.
192
273
  @confirm_prompt = options[:confirm_prompt] if
193
274
  options.has_key? :confirm_prompt
194
275
 
195
- @yak_dir = File.expand_path "~#{@user}/.yak"
276
+ @yak_dir = File.expand_path "~#{user}/.yak"
196
277
  FileUtils.mkdir @yak_dir unless File.directory? @yak_dir
197
278
 
198
279
  @pid_file = File.join @yak_dir, "pid"
199
280
  @password_file = File.join @yak_dir, "password"
200
- @data_file = File.join @yak_dir, "data"
281
+ @data_file = options[:data_file] || File.join(@yak_dir, "data")
201
282
 
202
283
  @session_pid = nil
203
284
  @session_pid = File.read(@pid_file).to_i if File.file? @pid_file
204
285
 
205
- @password = get_password options[:password]
286
+ @password = nil
206
287
 
207
288
  @cipher = OpenSSL::Cipher::Cipher.new "aes-256-cbc"
208
289
 
209
290
  @session_length = options.has_key?(:session) ? options[:session] : 30
210
-
211
- connect_data
212
- start_session
213
291
  end
214
292
 
215
293
 
@@ -227,7 +305,7 @@ Retrieved passwords get copied to the clipboard by default.
227
305
  end
228
306
 
229
307
  File.open(@pid_file, "w+"){|f| f.write pid }
230
- File.open(@password_file, "w+"){|f| f.write @password }
308
+ File.open(@password_file, "w+"){|f| f.write sha_password }
231
309
 
232
310
  Process.detach pid
233
311
  end
@@ -251,16 +329,43 @@ Retrieved passwords get copied to the clipboard by default.
251
329
  end
252
330
 
253
331
 
332
+ ##
333
+ # Check if the data file exists.
334
+
335
+ def data_file_exists?
336
+ File.file? @data_file
337
+ end
338
+
339
+
340
+ ##
341
+ # Deletes the user's data file forever!
342
+
343
+ def delete_data_file! confirm=false
344
+ confirmed = confirm ? @input.agree("Delete all passwords? (y/n)") : true
345
+ FileUtils.rm_f(@data_file) if confirmed
346
+ end
347
+
348
+
349
+ ##
350
+ # Get the SHA-encrypted password used for encoding data.
351
+
352
+ def sha_password
353
+ new_password unless data_file_exists?
354
+ @password ||= get_password
355
+ end
356
+
357
+
254
358
  ##
255
359
  # Get a password from either the password file or by prompting the
256
360
  # user if a password file is unavailable. Returns a sha1 of the password
257
361
  # passed as an arg.
258
362
 
259
- def get_password plain_password=nil
260
- password = File.read @password_file if File.file? @password_file
363
+ def get_password plain_pswd=nil
364
+ password = File.read @password_file if File.file?(@password_file)
365
+
366
+ plain_pswd ||= request_password "Master Password" if !password
261
367
 
262
- password ||=
263
- Digest::SHA1.hexdigest(plain_password || request_password("Yak Password"))
368
+ password ||= Digest::SHA1.hexdigest plain_pswd
264
369
 
265
370
  password
266
371
  end
@@ -271,8 +376,8 @@ Retrieved passwords get copied to the clipboard by default.
271
376
  # Prompts for password confirmation as well.
272
377
 
273
378
  def new_password password=nil
274
- password ||= request_new_password "New Password"
275
- @password = Digest::SHA1.hexdigest password if password
379
+ password ||= request_new_password "Set New Master Password"
380
+ @password = Digest::SHA1.hexdigest password
276
381
  end
277
382
 
278
383
 
@@ -280,13 +385,14 @@ Retrieved passwords get copied to the clipboard by default.
280
385
  # Loads and decrypts the data file into the @data attribute.
281
386
 
282
387
  def connect_data
283
- @data = if File.file? @data_file
284
- data = ""
285
- File.open(@data_file, "rb"){|f| data << f.read }
286
- YAML.load decrypt(data)
287
- else
288
- {}
289
- end
388
+ if data_file_exists?
389
+ data = ""
390
+ File.open(@data_file, "rb"){|f| data << f.read }
391
+ @data = YAML.load decrypt(data)
392
+ else
393
+ @data = {}
394
+ write_data
395
+ end
290
396
  end
291
397
 
292
398
 
@@ -318,27 +424,23 @@ Retrieved passwords get copied to the clipboard by default.
318
424
  ##
319
425
  # Decrypt a string with a given password.
320
426
 
321
- def decrypt string, password=@password
322
- @cipher.decrypt
323
- @cipher.key = password
324
- get_cypher_out string
427
+ def decrypt string, password=nil
428
+ get_cypher_out :decrypt, string, password
325
429
  end
326
430
 
327
431
 
328
432
  ##
329
433
  # Encrypt a string with a given password.
330
434
 
331
- def encrypt string, password=@password
332
- @cipher.encrypt
333
- @cipher.key = password
334
- get_cypher_out string
435
+ def encrypt string, password=nil
436
+ get_cypher_out :encrypt, string, password
335
437
  end
336
438
 
337
439
 
338
440
  ##
339
441
  # Encrypt and write the Yak data back to the data file.
340
442
 
341
- def write_data password=@password
443
+ def write_data password=nil
342
444
  data = encrypt @data.to_yaml, password
343
445
  File.open(@data_file, "w+"){|f| f.write data}
344
446
  end
@@ -376,7 +478,12 @@ Retrieved passwords get copied to the clipboard by default.
376
478
  end
377
479
 
378
480
 
379
- def get_cypher_out string
481
+ def get_cypher_out method, string, password=nil
482
+ password ||= sha_password
483
+
484
+ @cipher.send method
485
+ @cipher.key = password
486
+
380
487
  out = @cipher.update string
381
488
  out << @cipher.final
382
489
  out
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yak
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremie Castagna
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-02-22 00:00:00 -08:00
12
+ date: 2010-02-23 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -32,6 +32,26 @@ dependencies:
32
32
  - !ruby/object:Gem::Version
33
33
  version: 2.4.0
34
34
  version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: rubyforge
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 2.0.3
44
+ version:
45
+ - !ruby/object:Gem::Dependency
46
+ name: gemcutter
47
+ type: :development
48
+ version_requirement:
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 0.3.0
54
+ version:
35
55
  - !ruby/object:Gem::Dependency
36
56
  name: hoe
37
57
  type: :development
@@ -40,7 +60,7 @@ dependencies:
40
60
  requirements:
41
61
  - - ">="
42
62
  - !ruby/object:Gem::Version
43
- version: 2.3.3
63
+ version: 2.5.0
44
64
  version:
45
65
  description: |-
46
66
  Yak is a simple command line app to store and retrieve passwords securely