pwss 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,190 +0,0 @@
1
- h1. Pwss
2
-
3
- A password manager in the spirit of "pws":https://github.com/janlelis/pws.
4
-
5
- Features:
6
-
7
- * PWSS manages password *files*:
8
- ** A password file can store different entries (password and other sensitive information)
9
- ** The user can manage different password files (e.g., work, personal)
10
- * Entries in a password file can be any of Entry, CreditCard, BankAccount, SoftwareLicense. Each type stores a different set of infos:
11
- ** *Entry:* title, username, password, url, description
12
- ** *CreditCard:* title, issuer, name_on_card, card_number, valid_from, valid_till, verification_number, pin, url, notes
13
- ** *BankAccount:* title, name, iban, url, description
14
- ** *SoftwareLicense: title, version, license_number, licensed_to, email, purchased_on
15
- * Password files can be encrypted
16
- * Encrypted password files can be decrypted, for instance, to batch process entries, to migrate to another tool, or to manually edit entries
17
- * Entries are human-readable (and editable), when the password file is not encrypted
18
-
19
- h2. Installation
20
-
21
- Type from the command line:
22
-
23
- bc. $ gem install pwss
24
-
25
- h2. Quick Start
26
-
27
- Try the following:
28
-
29
- bc. $ pwss init
30
- $ pwss add First Entry
31
- $ pwss get First
32
-
33
- For some more information:
34
-
35
- bc. $ pwss man # get information from the command line
36
- $ pwss -h # command syntax
37
-
38
- h2. Detailed Instructions
39
-
40
- *Getting started.* @pwss@ stores passwords in a YAML file (also called "safe" or "password file" in the following), possibly encrypted.
41
-
42
- A typical usage scenario is the following:
43
-
44
- # @pwss init@ will create a new encrypted password safe in @~/.pwss.yaml.enc@. If you specify a filename without the @.enc@ extension, the password safe will be stored in plain text (see below).
45
- # @pwss add@ will add a new entry to the file
46
- # @pwss get string@ will retrieve all entries whose *title* contains @string@, let the user choose an entry, and make the password of the chosen entry available in the clipboard for a given period (the default is 30 seconds; the option @-w@ controls the amount of time the password is available)
47
-
48
- *Using multiple safes.* If you want to create multiple password files or store a password file in a non-standard location, use the @-f@ (@--filename@) option:
49
-
50
- # @pwss init -f MYFILE@
51
- # @pwss add -f MYFILE@
52
- # @pwss get -f MYFILE@
53
-
54
- *Do not forget to use the extension @.enc@, if your password file to be encrypted.* (See "Encrypted and Plain files", below.)
55
-
56
- *Controlling how long passwords are made available for* Use the @-w@ option to determine how long the password is made available in the clipboard. For instance:
57
-
58
- bc. $ pwss get my_email -w 3
59
-
60
- will retrieve a user selected entry whose title is @my_email@ and make the password available in the clipboard for @3@ seconds.
61
-
62
- Use @0@ to keep the password in the clipboard till a key is pressed.
63
-
64
- *Automatically Generated Password* pwss can automatically generate passwords for entries which are added or updated.
65
-
66
- The generated passwords are random sequences of chars and symbols. No attempt is made to make them readable or simpler to remember. You can use the @-a@ option to limit the generator to use only digits and letters ([0-9a-zA-Z]): this is useful, for instance, for websites which do accept certain classes of characters.
67
-
68
- Use the @-g LENGTH@ option to determine the password length.
69
-
70
- *The automatically generated password is made available in the clipboard, so that it can be used as needed*.
71
-
72
- For instance:
73
-
74
- bc. $ pwss update my_email -g 10 -a -w 20
75
-
76
- will update the @my_email@ entry, by replacing the existing password with one of length @10@ automatically generated by @pwss@; the password contains only alphabetic characters and digits. The new password will be made available in the clipboard for @20@ seconds.
77
-
78
- *Encrypted and Plain Files.* @pwss@ works equally well with encrypted and plain files. More in details, the file extension determines whether @pwss@ tries to decrypt/encrypt the file or not. Use @.enc@ extension to tell @pwss@ the file is encrypted; any other extension will tell @pwss@ to treat the file as plain text.
79
-
80
- For instance:
81
-
82
- bc. $ pwss init -f a.yaml.enc
83
-
84
- will initialize an encrypted safe @a.yaml.enc@.
85
-
86
- By contrast,
87
-
88
- bc. $ pwss init -f a.yaml
89
-
90
- Encrypting sensitive information is a good idea. (Just in case you were expecting a witty statement.) However, if you use @pwss@ to store non-critical infomation, prefer to edit the password safe with a text editor, or use another application for managing encryption and decryption, using @pwss@ with the file in plain format might be more convenient.
91
-
92
- *Moving from plain to encrypted.* You can use the @encrypt@ and @decrypt@ commands at any time to move from the plain to the encrypted format.
93
-
94
- bc. $ pwss -f YOURFILE encrypt
95
-
96
- will encrypt @YOURFILE@, while @decrypt@ will perform the opposite operation.
97
-
98
- *Starting from an Existing File.* You can also start from an existing file, as long as it is an array of YAML records, each containing, at least, a @title@ and a @password@ field. (See next section, for the file structure.)
99
-
100
- In this scenario, you can use the following commands to get started:
101
-
102
- # @pwss -f YOURFILE encrypt@ will encrypt your existing password file
103
- # @mv YOURFILE.enc ~/.pwss.yaml.enc@ moves the encrypted file to the default location (not necessary, but it simplifies the workflow)
104
-
105
- To add entries to the password safe, use the @add@ command. If you prefer to operate on the file using a text editor, you can also use the @decrypt@ and @encrypt@ commands.
106
-
107
- *Defining your entries.* @pwss@ requires entries to have only a @title@ and a @password@ field. If you want you can define and store your own records in the yaml files.
108
-
109
- *Getting Help.*
110
-
111
- bc. $ pwss
112
-
113
- will show all command options.
114
-
115
- h2. Under the Hood
116
-
117
- @pwss@ adopts a human-readable format for storing passwords, when the file is not encrypted, of course! (Unless you have mathematical super-powers and can read encrypted text.)
118
-
119
- The password files is a YAML file containing an array of entries. By default, entries have the following records:
120
-
121
- * title
122
- * username
123
- * password
124
- * url
125
- * description
126
-
127
- Example
128
-
129
- <pre>
130
- - title: A webservice
131
- username: username@example.com
132
- password: 1234567890
133
- url: http://www.example.com
134
- description: >
135
- with a password like the one above, who needs a password safe
136
-
137
- - title: My email
138
- username: username@example.com
139
- password: 1234567890
140
- url: http://www.example.com
141
- description: >
142
- Also available via email client, with the following connection parameters
143
- smtp.example.com
144
- imap.example.com
145
- </pre>
146
-
147
- Notice that only @title@ and @password@ are required.
148
-
149
- h2. Changelog
150
-
151
- * *Release 0.5.1* fixes a bug of the "add" command, which threw an error if the title was not supplied on the command line. When adding an entry, now it is possible to specify the title on the command line or just wait for the title prompt
152
- * *Release 0.5.0* This is a release mainly focused on improving interaction. It includes small changes to the command syntax and improved exit conditions. In details:
153
- ** *add* now accepts the title in the command line. For instance @pwss add New Entry@
154
- ** *new* is now an alias for the *add* command
155
- ** *update* now requires to specify the field: use @-p@, @--password@, or @--field password@, if you want to update the password
156
- ** show the usage summary, if no arguments are given
157
- ** *C-c* is now trapped and properly managed (clearing the clipboard)
158
- ** decryption errors are now properly managed
159
- ** the content of the clipboard is now restored after the waiting period
160
-
161
- * *Release 0.4.0*
162
- ** New @--stdout@ option will output password to standard output (useful for integration with other applications)
163
- ** New @--select N@ option will automatically select the @N@th entry (rather than asking the user to select an entry).
164
-
165
- * *Release 0.3.0*
166
- ** internal refactoring: CLI parsing is now based on "Slop":https://github.com/leejarvis/slop. The documentation has been revised and should now be simpler to understand.
167
- ** added some controls to avoid overwriting existing files (in particular: init, encrypt, and decrypt). The command is now less Unix-like, but I hope you will appreciate a bit more safety.
168
-
169
- * *Release 0.2.0* (never really made it to the public -- use version 0.3.0)
170
- ** it is now possible to add entries of various types (= with different fields). The supported types include: CreditCard, BankAccount, SoftwareLicense. Use the -e (--entry) option to specify the type of entry to add
171
- ** an empty string can now be used to exit (instead of -1) when multiple matches are found
172
-
173
- * *Release 0.1.0*
174
- ** the update command now allows one to update the password or any other field of existing entries
175
- ** a simple password generator allows pwss to generate a random password
176
- ** most commands make the password of the selected entry available in the clipboard (useful, for instance, if you automatically generate a password)
177
- ** a destroy command allows one to delete an entry from a safe. Similar to get, all entries matching a query are shown. The user is then asked to select which entry has to be deleted or stop. User confirmation is required even in case of a single match.
178
-
179
- h2. License
180
-
181
- Licensed under the terms of the MIT License.
182
-
183
-
184
- h2. Contributing
185
-
186
- 1. Fork it (http://github.com/<my-github-username>/pwss/fork )
187
- 2. Create your feature branch (@git checkout -b my-new-feature@)
188
- 3. Commit your changes (@git commit -am 'Add some feature'@)
189
- 4. Push to the branch (@git push origin my-new-feature@)
190
- 5. Create new Pull Request
data/bin/pwss DELETED
@@ -1,445 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'fileutils'
4
- require 'slop'
5
- require 'date'
6
-
7
- require "pwss"
8
- require "pwss/version"
9
- require "pwss/cipher"
10
- require "pwss/entry"
11
- require "pwss/credit_card"
12
- require "pwss/bank_account"
13
- require "pwss/software_license"
14
- require "pwss/fileops"
15
-
16
- # load filename and decrypt, if necessary
17
- # return the filename as string and the password (in case you need to save)
18
- def file2string filename
19
- string = FileOps::load filename
20
- if FileOps::encrypted? filename then
21
- password = Cipher::ask_password
22
- string = Cipher::decrypt string, password
23
- end
24
- [string, password]
25
- end
26
-
27
- # add and new are command aliases. Unfortunately slop does not seem to support aliases.
28
- # hence this function, which is called by both commands.
29
- def add opts, args
30
- filename = opts.to_hash[:filename] || DEFAULT_FILENAME
31
- waiting = opts.to_hash[:wait] || DEFAULT_SECS
32
- length = opts.to_hash[:generate] || 0
33
- type = opts.to_hash[:type] || "Entry"
34
- alnum = opts.to_hash[:alnum]
35
-
36
- default_title = args.join(" ")
37
- string, password = file2string filename
38
-
39
- puts "Adding #{default_title != "" ? "entry '" + default_title + "'" : "an entry"} of type '#{type}' to #{filename}"
40
- # ask for a new entry
41
- if default_title != "" then
42
- overrides = {"title" => ["Readline.readline('title (leave empty for \"#{default_title}\"): ')", "'#{default_title}'"]}
43
- else
44
- overrides = Hash.new
45
- end
46
- pe = eval("Pwss::" + type).new
47
- pe.ask length, alnum, overrides
48
-
49
- # add the entry to the safe
50
- entries = YAML::load(string) || Array.new
51
- entries << pe.entry
52
-
53
- # check status of input file and encrypt if necessary
54
- if FileOps::encrypted? filename then
55
- new_string = Cipher::encrypt entries.to_yaml, password
56
- else
57
- new_string = entries.to_yaml
58
- end
59
-
60
- FileOps::backup filename
61
- FileOps::save filename, new_string
62
-
63
- puts "Entry added."
64
-
65
- # make password available in the clipboard, if there is a password to make available
66
- if pe.entry["password"]
67
- Cipher.password_to_clipboard pe.entry["password"], waiting
68
- end
69
- end
70
-
71
- version = Pwss::VERSION
72
- man = <<EOS
73
- NAME
74
- pwss -- A command-line password manager
75
-
76
- SYNOPSYS
77
- pwss [-h|-v]
78
- pwss command [options] [args]
79
-
80
- DESCRIPTION
81
- PWSS is a password manager, in the spirit of pws.
82
-
83
- Features:
84
-
85
- * PWSS manages password *files*:
86
- - A password file can store different entries (password and other
87
- sensitive information)
88
- - The user can manage different password files (e.g., work, personal)
89
-
90
- * Entries in a password file can be any of Entry, CreditCard, BankAccount,
91
- SoftwareLicense. Each type stores a different set of infos:
92
-
93
- - Entry: title, username, password, url, description
94
- - CreditCard: title, issuer, name_on_card, card_number, valid_from,
95
- valid_till, verification_number, pin, url, notes
96
- - BankAccount: title, name, iban, url, description
97
- - SoftwareLicense: title, version, license_number, licensed_to,
98
- email, purchased_on
99
-
100
- * Password files can be encrypted
101
-
102
- * Encrypted password files can be decrypted, for instance, to batch process
103
- entries, to migrate to another tool, or to manually edit entries
104
-
105
- * Entries are human-readable (and editable), when the password file is not
106
- encrypted
107
-
108
- EXAMPLES
109
- pwss -h # get syntax of each command
110
-
111
- # scenario
112
- pwss init -f a.enc # generate an encrypted safe a.enc
113
- pwss add -f a.enc -g 16 -a # add an entry (pwss will generate a random 16-char password)
114
- pwss get -f a.enc my secret account # find an entry
115
-
116
- VERSION
117
- This is version #{version}
118
-
119
- LICENSE
120
- MIT
121
-
122
- SEE ALSO
123
- pwss -h
124
- pwss man
125
- https://github.com/avillafiorita/pwss
126
- EOS
127
-
128
-
129
-
130
- #
131
- # Main App Starts Here!
132
- #
133
- cmd = nil
134
- opts = Slop.parse :help => true, :strict => true do
135
- # the default filename
136
- DEFAULT_FILENAME = File.join(Dir.home, ".pwss.yaml.enc")
137
- # the default number of seconds password is available in the clipboard
138
- DEFAULT_SECS = 30
139
-
140
- banner "pwss [-h|-v]\npwss command [options] [args]"
141
-
142
- ##############################################################################
143
- on "-v", "--version", 'Print version information' do
144
- cmd = "version"
145
- puts "pwss version #{version}"
146
- end
147
-
148
- ##############################################################################
149
- command :man do
150
- banner "pwss man"
151
- description "Print detailed information about how to use pwss"
152
-
153
- run do |_, _|
154
- cmd = "man"
155
- puts man
156
- end
157
- end
158
-
159
- ##############################################################################
160
- command :init do
161
- banner "pwss init [options]"
162
- description "Init a new password file"
163
-
164
- on "-f", "--filename=", "Password file to create. Use extension '.enc' to encrypt it."
165
-
166
- run do |opts, args|
167
- cmd = "init"
168
- filename = opts.to_hash[:filename] || DEFAULT_FILENAME
169
-
170
- if File.exists?(filename)
171
- puts "Error: file #{filename} already exists."
172
- exit 1
173
- end
174
-
175
- empty_safe = "# safe created on #{Date.today}\n"
176
-
177
- # check status of input file and encrypt if necessary
178
- if FileOps::encrypted? filename then
179
- password = Cipher::check_password
180
- new_string = Cipher::encrypt empty_safe, password
181
- else
182
- new_string = empty_safe
183
- end
184
-
185
- FileOps::backup(filename) if File.exists?(filename)
186
- FileOps::save filename, new_string
187
-
188
- puts "New safe created in #{filename}"
189
- end
190
- end
191
-
192
- ##############################################################################
193
- command :list do
194
- banner "pwss list [options]"
195
- description "List all entries of a file (e.g., to decrypt or batch process)"
196
-
197
- on "-f", "--filename=", "Password file to use."
198
-
199
- run do |opts, args|
200
- cmd = "list"
201
-
202
- filename = opts.to_hash[:filename] || DEFAULT_FILENAME
203
-
204
- string, _ = file2string filename
205
- entries = YAML::load(string) || Array.new
206
-
207
- Pwss::list entries
208
- end
209
- end
210
-
211
- ##############################################################################
212
- command :get do
213
- banner "pwss get [options] string"
214
- description "Get password for entry matching <string> in the title field"
215
-
216
- on "-f", "--filename=", "Password file to use"
217
- on "-w", "--wait=", "Seconds password is available in the clipboard (0 = interactive)", as: Integer
218
- on "--stdout", "Output the password to standard output"
219
- on "--select=", "Select the N-th matching entry", as: Integer
220
-
221
- run do |opts, args|
222
- cmd = "get"
223
-
224
- filename = opts.to_hash[:filename] || DEFAULT_FILENAME
225
- waiting = opts.to_hash[:wait] || DEFAULT_SECS
226
- stdout_opt = opts.to_hash[:stdout]
227
- entry_no = opts.to_hash[:select] || nil
228
-
229
- string, _ = file2string filename
230
- entries = YAML::load(string) || Array.new
231
-
232
- password = Pwss::get args.join(" "), entries, entry_no
233
-
234
- if password then
235
- stdout_opt ? printf("%s", password) : Cipher.password_to_clipboard(password, waiting)
236
- end
237
-
238
- end
239
- end
240
-
241
-
242
- ##############################################################################
243
- command :add do
244
- banner "pwss add [options] [entry title]"
245
- description "Add an entry and copy its password in the clipboard"
246
-
247
- on "-f", "--filename=", "Password file to use"
248
- on "-w", "--wait=", "Seconds password is available in the clipboard (0 = interactive)", as: Integer
249
-
250
- on "-e", "--entry=", "Create an entry of type TYPE (Entry, CreditCard, BankAccount, SoftwareLicense).\n Default to 'Entry', which is good enough for websites credentials"
251
-
252
- on "-g", "--generate=", "Generate a random password of given length.", as: Integer
253
- on "-a", "--alnum", "Use only alphanumeric chars for the randomly generated password"
254
-
255
- run do |opts, args|
256
- cmd = "add"
257
- add opts, args
258
- end
259
- end
260
-
261
- command :new do
262
- banner "pwss new [options] [entry title]"
263
- description "An alias for add"
264
-
265
- on "-f", "--filename=", "Password file to use"
266
- on "-w", "--wait=", "Seconds password is available in the clipboard (0 = interactive)", as: Integer
267
-
268
- on "-e", "--entry=", "Create an entry of type TYPE (Entry, CreditCard, BankAccount, SoftwareLicense).\n Default to 'Entry', which is good enough for websites credentials"
269
-
270
- on "-g", "--generate=", "Generate a random password of given length.", as: Integer
271
- on "-a", "--alnum", "Use only alphanumeric chars for the randomly generated password"
272
-
273
- run do |opts, args|
274
- cmd = "new"
275
- add opts, args
276
- end
277
- end
278
-
279
- ##############################################################################
280
- command :update do
281
- banner "pwss update [options] string"
282
- description "Update given field of user-selected entry matching <string>"
283
-
284
- on "-f", "--filename=", "Password file to use"
285
- on "-w", "--wait=", "Seconds password is available in the clipboard (0 = interactive)", as: Integer
286
- on "-g", "--generate=", "Generate a random password of given length", as: Integer
287
- on "-a", "--alnum", "Use only alphanumeric chars for the randomly generated password"
288
- on "--field=", 'Field to update'
289
- on "-p", "--password", "an alias for --field password"
290
-
291
- run do |opts, args|
292
- cmd = "update"
293
-
294
- filename = opts.to_hash[:filename] || DEFAULT_FILENAME
295
- waiting = opts.to_hash[:wait] || DEFAULT_SECS
296
- length = opts.to_hash[:generate] || 0
297
- alnum = opts.to_hash[:alnum]
298
- field = opts.to_hash[:password] ? "password" : opts.to_hash[:field]
299
-
300
- if not field then
301
- puts "Please specify a field to update (used --field ... or -p)"
302
- exit 1
303
- end
304
-
305
- string, password = file2string filename
306
-
307
- # load entries and update
308
- entries = YAML::load(string) || Array.new
309
-
310
- if field == "password" then
311
- # update password
312
- entries, entry_password = Pwss::update args.join(" "), entries, length, alnum
313
- else
314
- entries, entry_password = Pwss::update_field args.join(" "), entries, field
315
- end
316
-
317
- # check status of input file and encrypt if necessary
318
- if FileOps::encrypted? filename then
319
- new_string = Cipher::encrypt entries.to_yaml, password
320
- else
321
- new_string = entries.to_yaml
322
- end
323
-
324
- FileOps::backup filename
325
- FileOps::save filename, new_string
326
-
327
- puts "Entry updated."
328
-
329
- # copy to clipboard the new password
330
- if entry_password
331
- Cipher.password_to_clipboard entry_password, waiting
332
- end
333
- end
334
- end
335
-
336
- ##############################################################################
337
- # Look for entries matching string, offer the user to select one of the
338
- # matching entries, and destroy the entry.
339
- # The command asks for confirmation even if there is only one matching entry.
340
- # Destroyed entries cannot be recovered (unless you dig in the backup file).
341
- command :destroy do
342
- banner "pwss destroy [options] string"
343
- description "Destroy a user-selected entry matching <string>, after user confirmation."
344
-
345
- on "-f", "--filename=", "Password file to create. Use extension '.enc' to encrypt it."
346
-
347
- run do |opts, args|
348
- cmd = "destroy"
349
-
350
- filename = opts.to_hash[:filename] || DEFAULT_FILENAME
351
-
352
- string, password = file2string filename
353
- entries = YAML::load(string)
354
-
355
- entries = Pwss::destroy args.join(" "), entries
356
-
357
- # check status of input file and encrypt if necessary
358
- if FileOps::encrypted? filename then
359
- new_string = Cipher::encrypt entries.to_yaml, password
360
- else
361
- new_string = entries.to_yaml
362
- end
363
-
364
- FileOps::backup filename
365
- FileOps::save filename, new_string
366
-
367
- puts "Entry deleted."
368
- end
369
- end
370
-
371
- ##############################################################################
372
- # OPERATIONS ON PASSWORD FILES
373
- ##############################################################################
374
-
375
- ##############################################################################
376
- command :encrypt do
377
- banner "pwss encrypt [options]"
378
- description "Encrypt a password safe"
379
-
380
- on "-f", "--filename=", "Password file to encrypt. Write to <file>.enc."
381
-
382
- run do |opts, _|
383
- cmd = "encrypt"
384
-
385
- filename = opts.to_hash[:filename] || DEFAULT_FILENAME.sub(/\.enc$/, "")
386
-
387
- if not File.exists?(filename)
388
- puts "Error: file #{filename} does not exist."
389
- exit 1
390
- end
391
-
392
- password = Cipher::check_password
393
- data = FileOps::load filename
394
- encrypted = Cipher::encrypt data, password
395
-
396
- enc_filename = filename + ".enc"
397
-
398
- if File.exists?(enc_filename)
399
- FileOps::backup enc_filename
400
- puts "Warning: existing #{enc_filename} backupped to #{enc_filename}~"
401
- end
402
- FileOps::save enc_filename, encrypted
403
- puts "An encrypted copy now lives in #{enc_filename}"
404
- puts "You might want to check everything is ok and delete the plain file: #{filename}"
405
- end
406
- end
407
-
408
- ##############################################################################
409
- command :decrypt do
410
- banner "pwss decrypt [options]"
411
- description "Decrypt a password safe"
412
-
413
- on "-f", "--filename=", "Password file to decrypt. Write to <file>, without '.enc'."
414
-
415
- run do |opts, _|
416
- cmd = "decrypt"
417
-
418
- filename = opts.to_hash[:filename] || DEFAULT_FILENAME
419
-
420
- if not File.exists?(filename)
421
- puts "Error: file #{filename} does not exist."
422
- exit 1
423
- end
424
-
425
- password = Cipher::ask_password
426
- data = FileOps::load filename
427
- decrypted = Cipher::decrypt data, password
428
-
429
- dec_filename = filename.sub(/\.enc$/,"")
430
- if File.exists?(dec_filename)
431
- FileOps::backup dec_filename
432
- puts "Warning: existing #{dec_filename} backupped to #{dec_filename}~"
433
- end
434
-
435
- FileOps::save dec_filename, decrypted
436
- puts "A decrypted copy now lives in #{dec_filename}"
437
- puts "You might want to check everything is ok and delete #{filename}, if you wish."
438
- end
439
- end
440
-
441
- end
442
-
443
- if cmd == nil then
444
- puts opts
445
- end