yak 1.0.2 → 1.0.3

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.
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