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.
- data/History.txt +21 -1
- data/README.txt +2 -1
- data/lib/yak.rb +149 -42
- metadata +23 -3
data/History.txt
CHANGED
@@ -1,4 +1,24 @@
|
|
1
|
-
=== 1.0.
|
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
|
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.
|
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
|
-
|
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
|
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
|
-
#
|
55
|
-
|
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
|
-
|
58
|
-
|
75
|
+
usrhome = File.expand_path "~#{user}/"
|
76
|
+
dropbox = File.expand_path "~#{user}/Dropbox"
|
59
77
|
|
60
|
-
if
|
61
|
-
|
62
|
-
|
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
|
-
|
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 "~#{
|
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
|
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 =
|
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
|
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
|
260
|
-
password
|
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
|
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
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
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
|
322
|
-
|
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
|
332
|
-
|
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
|
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.
|
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-
|
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.
|
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
|