pwss 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.textile +70 -34
- data/bin/pwss +230 -110
- data/lib/pwss.rb +4 -3
- data/lib/pwss/bank_account.rb +18 -0
- data/lib/pwss/credit_card.rb +23 -0
- data/lib/pwss/entry.rb +23 -21
- data/lib/pwss/software_license.rb +21 -0
- data/lib/pwss/version.rb +1 -1
- data/pwss.gemspec +8 -6
- metadata +18 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f0d6de35d7d59295771fff8e0710f121b9fcaf3c
|
4
|
+
data.tar.gz: 15b6b84a494a01fdb2c94833481dc1bbc5c08818
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a6951a825180bdda38b6a26da7895bbb422862466cadfc1ea95703a050ae2c542ba2b61fb45a489c2ed3af83f6429843bc8dec6a668933acba6f305258b077e
|
7
|
+
data.tar.gz: 1ce2596579e801b3313ec443a98aac562ec94b3c2a933b59b3ad51bc35f1c8bdcd730c0c3795a0ff8318be528fb1a37177e6c0ec7b9288ea6fc35f9fe05a25e4
|
data/README.textile
CHANGED
@@ -2,49 +2,72 @@ h1. Pwss
|
|
2
2
|
|
3
3
|
A password manager in the spirit of "pws":https://github.com/janlelis/pws.
|
4
4
|
|
5
|
+
PWSS can store multiple entries in a file and, more important, it allows user to specify various types of entries (e.g., BankAccount) and different infos for each entry (e.g., URL for Internet passwords).
|
6
|
+
|
5
7
|
Features:
|
6
8
|
|
7
|
-
*
|
8
|
-
|
9
|
-
|
9
|
+
* PWSS manages password files. A password file store passwords and other
|
10
|
+
sensitive information
|
11
|
+
|
12
|
+
* Entries in a password file can be of the following pre-defined types:
|
13
|
+
Entry, CreditCard, BankAccount, SoftwareLicense
|
14
|
+
|
15
|
+
* Information stored for each type:
|
16
|
+
|
17
|
+
- Entry: title, username, password, url, description
|
18
|
+
- CreditCard: title, issuer, name_on_card, card_number, valid_from,
|
19
|
+
valid_till, verification_number, pin, url, notes
|
20
|
+
- BankAccount: title, name, iban, url, description
|
21
|
+
- SoftwareLicense: title, version, license_number, licensed_to,
|
22
|
+
email, purchased_on
|
23
|
+
|
10
24
|
* CRUD (create, read, update, delete) commands are available to
|
11
|
-
operate on entries and
|
12
|
-
|
13
|
-
*
|
14
|
-
*
|
15
|
-
|
16
|
-
|
25
|
+
operate on entries and password files
|
26
|
+
|
27
|
+
* The user can manage different password files (e.g., work, personal)
|
28
|
+
* Password files can be encrypted
|
29
|
+
* Encrypted password files can be decrypted, for instance, to batch process
|
30
|
+
entries, to migrate to another tool, or to manually edit entries
|
31
|
+
* Entries are human-readable (and editable), when the password file is not
|
32
|
+
encrypted
|
17
33
|
|
18
34
|
h2. Installation
|
19
35
|
|
20
|
-
|
36
|
+
Type from the command line:
|
37
|
+
|
38
|
+
bc. $ gem install pwss
|
21
39
|
|
22
|
-
|
40
|
+
h2. Quick Start
|
23
41
|
|
24
|
-
|
42
|
+
Try the following:
|
25
43
|
|
26
|
-
bc. $
|
44
|
+
bc. $ pwss init
|
45
|
+
$ pwss add
|
46
|
+
$ pwss get <title you gave with previous command>
|
27
47
|
|
28
|
-
|
48
|
+
For some more information:
|
29
49
|
|
30
|
-
bc. $
|
50
|
+
bc. $ pwss help # get information from the command line
|
51
|
+
$ pwss -h # command syntax
|
31
52
|
|
32
|
-
h2.
|
53
|
+
h2. Detailed Instructions
|
33
54
|
|
34
|
-
*Getting started.* @pwss@ stores passwords in a YAML file (also called "password
|
55
|
+
*Getting started.* @pwss@ stores passwords in a YAML file (also called "safe" or "password file" in the following), possibly encrypted.
|
35
56
|
|
36
57
|
A typical usage scenario is the following:
|
37
58
|
|
38
59
|
# @pwss init@ will create a new encrypted password safe in @~/.pwss.yaml.enc@
|
39
60
|
# @pwss add@ will add a new entry to the file
|
40
|
-
# @pwss get
|
61
|
+
# @pwss get string@ will retrieve all entries whose *title* contains @string@ 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)
|
41
62
|
|
42
|
-
*Using multiple safes.* If you want to create multiple password
|
63
|
+
*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:
|
43
64
|
|
44
65
|
# @pwss -f MYFILE init@
|
45
66
|
# @pwss -f MYFILE add@
|
46
67
|
# @pwss -f MYFILE get@
|
47
68
|
|
69
|
+
*Do not forget to use the extension @.enc@, if your password file to be encrypted.* (See "Encrypted and Plain files", below.)
|
70
|
+
|
48
71
|
*Controlling how long passwords are made available* Use the @-w@ option to determine how long the password is made available in the clipboard. For instance:
|
49
72
|
|
50
73
|
bc. $ pwss get my_email -w 3
|
@@ -53,7 +76,13 @@ will retrieve entry whose title is @my_email@ and make the password available in
|
|
53
76
|
|
54
77
|
Use @0@ to keep the password in the clipboard till a key is pressed.
|
55
78
|
|
56
|
-
*Automatically Generated Password* pwss can automatically generate passwords for entries which are added or updated
|
79
|
+
*Automatically Generated Password* pwss can automatically generate passwords for entries which are added or updated.
|
80
|
+
|
81
|
+
The generated passwords are random sequences of chars and symbols and 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, if the website you're generating the password for does not accept certain classes of characters.
|
82
|
+
|
83
|
+
Use the @-g LENGTH@ option to determine the password length.
|
84
|
+
|
85
|
+
*The automatically generated password is made available in the clipboard, so that it can be used as needed*.
|
57
86
|
|
58
87
|
For instance:
|
59
88
|
|
@@ -61,27 +90,25 @@ bc. $ pwss update my_email -g 10 -a -w 20
|
|
61
90
|
|
62
91
|
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.
|
63
92
|
|
64
|
-
*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.
|
93
|
+
*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.
|
65
94
|
|
66
95
|
For instance:
|
67
96
|
|
68
|
-
bc. $ pwss -f a.yaml.enc
|
97
|
+
bc. $ pwss init -f a.yaml.enc
|
69
98
|
|
70
|
-
will
|
99
|
+
will initialize an encrypted safe @a.yaml.enc@.
|
71
100
|
|
72
101
|
By contrast,
|
73
102
|
|
74
|
-
bc. $ pwss -f a.yaml
|
103
|
+
bc. $ pwss init -f a.yaml
|
75
104
|
|
76
|
-
|
105
|
+
Encrypting sensitive information is a good idea. (Just in case you were looking for 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.
|
77
106
|
|
78
|
-
|
79
|
-
|
80
|
-
*Moving from plain to encrypted.* Use the @encrypt@ and @decrypt@ commands at any time to move from the plain to the encrypted format.
|
107
|
+
*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.
|
81
108
|
|
82
109
|
bc. $ pwss -f YOURFILE encrypt
|
83
110
|
|
84
|
-
will encrypt @YOURFILE
|
111
|
+
will encrypt @YOURFILE@, while @decrypt@ will perform the opposite operation.
|
85
112
|
|
86
113
|
*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.)
|
87
114
|
|
@@ -136,20 +163,29 @@ Notice that only @title@ and @password@ are required.
|
|
136
163
|
|
137
164
|
h2. Changelog
|
138
165
|
|
166
|
+
* *Release 0.3.0*
|
167
|
+
** 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.
|
168
|
+
** 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.
|
169
|
+
|
170
|
+
* *Release 0.2.0* (never really made it to the public -- use version 0.3.0)
|
171
|
+
** 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
|
172
|
+
** an empty string can now be used to exit (instead of -1) when multiple matches are found
|
173
|
+
|
139
174
|
* *Release 0.1.0*
|
140
175
|
** the update command now allows one to update the password or any other field of existing entries
|
141
176
|
** a simple password generator allows pwss to generate a random password
|
142
177
|
** most commands make the password of the selected entry available in the clipboard (useful, for instance, if you automatically generate a password)
|
143
178
|
** 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.
|
144
179
|
|
145
|
-
h2. License
|
180
|
+
h2. License
|
146
181
|
|
147
182
|
Licensed under the terms of the MIT License.
|
148
183
|
|
184
|
+
|
149
185
|
h2. Contributing
|
150
186
|
|
151
|
-
1. Fork it (
|
152
|
-
2. Create your feature branch (
|
153
|
-
3. Commit your changes (
|
154
|
-
4. Push to the branch (
|
187
|
+
1. Fork it (http://github.com/<my-github-username>/pwss/fork )
|
188
|
+
2. Create your feature branch (@git checkout -b my-new-feature@)
|
189
|
+
3. Commit your changes (@git commit -am 'Add some feature'@)
|
190
|
+
4. Push to the branch (@git push origin my-new-feature@)
|
155
191
|
5. Create new Pull Request
|
data/bin/pwss
CHANGED
@@ -1,45 +1,130 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'fileutils'
|
4
|
-
require '
|
4
|
+
require 'slop'
|
5
5
|
require 'date'
|
6
6
|
|
7
7
|
require "pwss"
|
8
8
|
require "pwss/version"
|
9
9
|
require "pwss/cipher"
|
10
10
|
require "pwss/entry"
|
11
|
+
require "pwss/credit_card"
|
12
|
+
require "pwss/bank_account"
|
13
|
+
require "pwss/software_license"
|
11
14
|
require "pwss/fileops"
|
12
15
|
|
13
|
-
|
14
|
-
|
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
|
+
|
28
|
+
version = Pwss::VERSION
|
29
|
+
man = <<EOS
|
30
|
+
NAME
|
31
|
+
pwss -- A command-line password manager
|
32
|
+
|
33
|
+
SYNOPSYS
|
34
|
+
pwss [-h|-v]
|
35
|
+
pwss command [options] [args]
|
36
|
+
|
37
|
+
DESCRIPTION
|
38
|
+
PWSS is a password manager, in the spirit of pws.
|
39
|
+
|
40
|
+
Features:
|
41
|
+
|
42
|
+
* PWSS manages password files. A password file store passwords and other
|
43
|
+
sensitive information
|
44
|
+
|
45
|
+
* Entries in a password file can be of the following pre-defined types:
|
46
|
+
Entry, CreditCard, BankAccount, SoftwareLicense
|
47
|
+
|
48
|
+
* Information stored for each type:
|
49
|
+
|
50
|
+
- Entry: title, username, password, url, description
|
51
|
+
- CreditCard: title, issuer, name_on_card, card_number, valid_from,
|
52
|
+
valid_till, verification_number, pin, url, notes
|
53
|
+
- BankAccount: title, name, iban, url, description
|
54
|
+
- SoftwareLicense: title, version, license_number, licensed_to,
|
55
|
+
email, purchased_on
|
56
|
+
|
57
|
+
* CRUD (create, read, update, delete) commands are available to
|
58
|
+
operate on entries and password files
|
59
|
+
|
60
|
+
* The user can manage different password files (e.g., work, personal)
|
61
|
+
* Password files can be encrypted
|
62
|
+
* Encrypted password files can be decrypted, for instance, to batch process
|
63
|
+
entries, to migrate to another tool, or to manually edit entries
|
64
|
+
* Entries are human-readable (and editable), when the password file is not
|
65
|
+
encrypted
|
66
|
+
|
67
|
+
EXAMPLES
|
68
|
+
pwss -h # get syntax of each command
|
69
|
+
|
70
|
+
# scenario
|
71
|
+
pwss init -f a.enc # generate an encrypted safe a.enc
|
72
|
+
pwss add -f a.enc -g 16 -a # add an entry (generating a password)
|
73
|
+
pwss get -f a.enc my secret account # find an entry
|
15
74
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
* CRUD (create, read, update, delete) commands are available to
|
26
|
-
operate on entries and safes
|
27
|
-
* Safes can be encrypted
|
28
|
-
* Encrypted safes can be decrypted, for instance, to batch process
|
29
|
-
entries, to migrate to another tool, or to manually edit entries
|
30
|
-
* Entries are human-readable (and editable), when not encrypted
|
75
|
+
VERSION
|
76
|
+
This is version #{version}
|
77
|
+
|
78
|
+
LICENSE
|
79
|
+
MIT
|
80
|
+
|
81
|
+
SEE ALSO
|
82
|
+
pwss -h
|
83
|
+
https://github.com/avillafiorita/pwss
|
31
84
|
EOS
|
32
85
|
|
33
|
-
p.syntax "pwss <subcommand> [options] [args]"
|
34
|
-
p.option 'filename', '-f FILE', '--filename FILE', 'Password file'
|
35
|
-
p.option 'wait', '-w SECS', '--wait SECS', 'Number of seconds password is available in the clipboard (use 0 for interactive).'
|
36
86
|
|
37
|
-
p.command(:init) do |c|
|
38
|
-
c.syntax "init"
|
39
|
-
c.description 'Init a new password file (= password safe)'
|
40
87
|
|
41
|
-
|
42
|
-
|
88
|
+
#
|
89
|
+
# Main App Starts Here!
|
90
|
+
#
|
91
|
+
opts = Slop.parse :help => true do
|
92
|
+
# the default filename
|
93
|
+
DEFAULT_FILENAME = File.join(Dir.home, ".pwss.yaml.enc")
|
94
|
+
# the default number of seconds password is available in the clipboard
|
95
|
+
DEFAULT_SECS = 30
|
96
|
+
|
97
|
+
banner "pwss [-h|-v]\npwss command [options] [args]"
|
98
|
+
|
99
|
+
##############################################################################
|
100
|
+
on "-v", "--version", 'Print version information' do
|
101
|
+
puts "pwss version #{version}"
|
102
|
+
end
|
103
|
+
|
104
|
+
##############################################################################
|
105
|
+
command :help do
|
106
|
+
banner "pwss help"
|
107
|
+
description "Print detailed information about how to use pwss"
|
108
|
+
|
109
|
+
run do |_, _|
|
110
|
+
puts man
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
##############################################################################
|
115
|
+
command :init do
|
116
|
+
banner "pwss init [options]"
|
117
|
+
description "Init a new password file"
|
118
|
+
|
119
|
+
on "-f", "--filename=", "Password file to create. Use extension '.enc' to encrypt it."
|
120
|
+
|
121
|
+
run do |opts, args|
|
122
|
+
filename = opts.to_hash[:filename] || DEFAULT_FILENAME
|
123
|
+
|
124
|
+
if File.exists?(filename)
|
125
|
+
puts "Error: file #{filename} already exists."
|
126
|
+
exit 1
|
127
|
+
end
|
43
128
|
|
44
129
|
empty_safe = "# safe created on #{Date.today}\n"
|
45
130
|
|
@@ -58,12 +143,15 @@ EOS
|
|
58
143
|
end
|
59
144
|
end
|
60
145
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
146
|
+
##############################################################################
|
147
|
+
command :list do
|
148
|
+
banner "pwss list [options]"
|
149
|
+
description "List all entries of a file (e.g., to decrypt or batch process)"
|
150
|
+
|
151
|
+
on "-f", "--filename=", "Password file to use."
|
152
|
+
|
153
|
+
run do |opts, args|
|
154
|
+
filename = opts.to_hash[:filename] || DEFAULT_FILENAME
|
67
155
|
|
68
156
|
string, _ = file2string filename
|
69
157
|
entries = YAML::load(string) || Array.new
|
@@ -72,39 +160,55 @@ EOS
|
|
72
160
|
end
|
73
161
|
end
|
74
162
|
|
75
|
-
|
76
|
-
|
77
|
-
|
163
|
+
##############################################################################
|
164
|
+
command :get do
|
165
|
+
banner "pwss get [options] string"
|
166
|
+
description "Get password for entry matching <string> in the title field"
|
167
|
+
|
168
|
+
on "-f", "--filename=", "Password file to use."
|
169
|
+
on "-w", "--wait=", "Seconds password is available in the clipboard (0 = interactive).", as: Integer
|
170
|
+
|
171
|
+
run do |opts, args|
|
172
|
+
filename = opts.to_hash[:filename] || DEFAULT_FILENAME
|
173
|
+
waiting = opts.to_hash[:wait] || DEFAULT_SECS
|
78
174
|
|
79
|
-
c.action do |args, opts|
|
80
|
-
filename = opts['filename'] || DEFAULT_FILENAME
|
81
|
-
waiting = opts['wait'] ? opts['wait'].to_i : 30
|
82
|
-
|
83
175
|
string, _ = file2string filename
|
84
176
|
entries = YAML::load(string) || Array.new
|
85
177
|
|
86
178
|
password = Pwss::get args.join(" "), entries
|
87
|
-
|
179
|
+
if password
|
180
|
+
Cipher.password_to_clipboard password, waiting
|
181
|
+
end
|
88
182
|
end
|
89
183
|
end
|
90
184
|
|
91
|
-
|
92
|
-
|
93
|
-
|
185
|
+
|
186
|
+
##############################################################################
|
187
|
+
command :add do
|
188
|
+
banner "pwss add [options]"
|
189
|
+
description "Add an entry and copy its password in the clipboard"
|
190
|
+
|
191
|
+
on "-f", "--filename=", "Password file to use."
|
192
|
+
on "-w", "--wait=", "Seconds password is available in the clipboard (0 = interactive).", as: Integer
|
94
193
|
|
95
|
-
|
96
|
-
c.option "alnum", "-a", "--alnum", "use only alphanumeric characters for the generated password"
|
194
|
+
on "-e", "--entry=", "Create an entry of type TYPE (Entry, CreditCard, BankAccount, SoftwareLicense).\n Default to 'Entry', which is good enough for websites credentials."
|
97
195
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
196
|
+
on "-g", "--generate=", "Generate a random password of given length.", as: Integer
|
197
|
+
on "-a", "--alnum", "Use only alphanumeric chars for the randomly generated password."
|
198
|
+
|
199
|
+
run do |opts, args|
|
200
|
+
filename = opts.to_hash[:filename] || DEFAULT_FILENAME
|
201
|
+
waiting = opts.to_hash[:wait] || DEFAULT_SECS
|
202
|
+
length = opts.to_hash[:generate] || 0
|
203
|
+
type = opts.to_hash[:type] || "Entry"
|
204
|
+
alnum = opts.to_hash[:alnum]
|
102
205
|
|
103
206
|
string, password = file2string filename
|
104
207
|
|
208
|
+
puts "Adding an entry of type: #{type}"
|
105
209
|
# ask for a new entry
|
106
|
-
pe = Pwss::
|
107
|
-
pe.ask length,
|
210
|
+
pe = eval("Pwss::" + type).new
|
211
|
+
pe.ask length, alnum
|
108
212
|
|
109
213
|
# add the entry to the safe
|
110
214
|
entries = YAML::load(string) || Array.new
|
@@ -122,24 +226,30 @@ EOS
|
|
122
226
|
|
123
227
|
puts "Entry added."
|
124
228
|
|
125
|
-
# make password available in the clipboard
|
126
|
-
|
229
|
+
# make password available in the clipboard, if there is a password to make available
|
230
|
+
if pe.entry["password"]
|
231
|
+
Cipher.password_to_clipboard pe.entry["password"], waiting
|
232
|
+
end
|
127
233
|
end
|
128
234
|
end
|
129
235
|
|
130
|
-
|
131
|
-
|
132
|
-
|
236
|
+
##############################################################################
|
237
|
+
command :update do
|
238
|
+
banner "pwss update [options] string"
|
239
|
+
description "Update given field of user-selected entry matching <string>"
|
133
240
|
|
134
|
-
|
135
|
-
|
136
|
-
|
241
|
+
on "-f", "--filename=", "Password file to use."
|
242
|
+
on "-w", "--wait=", "Seconds password is available in the clipboard (0 = interactive).", as: Integer
|
243
|
+
on "-g", "--generate=", "Generate a random password of given length.", as: Integer
|
244
|
+
on "-a", "--alnum", "Use only alphanumeric chars for the randomly generated password."
|
245
|
+
on '--field=', 'Field to update (if not specified, update the password field).'
|
137
246
|
|
138
|
-
|
139
|
-
filename = opts[
|
140
|
-
waiting
|
141
|
-
length
|
142
|
-
|
247
|
+
run do |opts, args|
|
248
|
+
filename = opts.to_hash[:filename] || DEFAULT_FILENAME
|
249
|
+
waiting = opts.to_hash[:wait] || DEFAULT_SECS
|
250
|
+
length = opts.to_hash[:generate] || 0
|
251
|
+
alnum = opts.to_hash[:alnum]
|
252
|
+
field = opts.to_hash[:field]
|
143
253
|
|
144
254
|
string, password = file2string filename
|
145
255
|
|
@@ -150,7 +260,7 @@ EOS
|
|
150
260
|
entries, entry_password = Pwss::update_field args.join(" "), entries, field
|
151
261
|
else
|
152
262
|
# update password
|
153
|
-
entries, entry_password = Pwss::update args.join(" "), entries, length,
|
263
|
+
entries, entry_password = Pwss::update args.join(" "), entries, length, alnum
|
154
264
|
end
|
155
265
|
|
156
266
|
# check status of input file and encrypt if necessary
|
@@ -166,22 +276,25 @@ EOS
|
|
166
276
|
puts "Entry updated."
|
167
277
|
|
168
278
|
# copy to clipboard the new password
|
169
|
-
|
279
|
+
if entry_password
|
280
|
+
Cipher.password_to_clipboard entry_password, waiting
|
281
|
+
end
|
170
282
|
end
|
171
283
|
end
|
172
284
|
|
285
|
+
##############################################################################
|
286
|
+
# Look for entries matching string, offer the user to select one of the
|
287
|
+
# matching entries, and destroy the entry.
|
288
|
+
# The command asks for confirmation even if there is only one matching entry.
|
289
|
+
# Destroyed entries cannot be recovered (unless you dig in the backup file).
|
290
|
+
command :destroy do
|
291
|
+
banner "pwss destroy [options] string"
|
292
|
+
description "Destroy a user-selected entry matching <string>, after user confirmation."
|
173
293
|
|
174
|
-
|
175
|
-
c.syntax "destroy string"
|
176
|
-
c.description "Show entries matching <string> and let the user select one to destroy"
|
294
|
+
on "-f", "--filename=", "Password file to create. Use extension '.enc' to encrypt it."
|
177
295
|
|
178
|
-
|
179
|
-
|
180
|
-
# The command asks for confirmation even if there is only one matching entry.
|
181
|
-
# Destroyed entries cannot be recovered (unless you dig in the backup file).
|
182
|
-
|
183
|
-
c.action do |args, opts|
|
184
|
-
filename = opts['filename'] || DEFAULT_FILENAME
|
296
|
+
run do |opts, args|
|
297
|
+
filename = opts.to_hash[:filename] || DEFAULT_FILENAME
|
185
298
|
|
186
299
|
string, password = file2string filename
|
187
300
|
entries = YAML::load(string)
|
@@ -201,64 +314,71 @@ EOS
|
|
201
314
|
puts "Entry deleted."
|
202
315
|
end
|
203
316
|
end
|
204
|
-
|
205
317
|
|
206
|
-
|
207
|
-
#
|
208
|
-
|
318
|
+
##############################################################################
|
319
|
+
# OPERATIONS ON PASSWORD FILES
|
320
|
+
##############################################################################
|
209
321
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
322
|
+
##############################################################################
|
323
|
+
command :encrypt do
|
324
|
+
banner "pwss encrypt [options]"
|
325
|
+
description "Encrypt a password safe"
|
326
|
+
|
327
|
+
on "-f", "--filename=", "Password file to encrypt. Write to <file>.enc."
|
328
|
+
|
329
|
+
run do |opts, _|
|
330
|
+
filename = opts.to_hash[:filename] || DEFAULT_FILENAME.sub(/\.enc$/, "")
|
331
|
+
|
332
|
+
if not File.exists?(filename)
|
333
|
+
puts "Error: file #{filename} does not exist."
|
334
|
+
exit 1
|
335
|
+
end
|
216
336
|
|
217
337
|
password = Cipher::check_password
|
218
338
|
data = FileOps::load filename
|
219
339
|
encrypted = Cipher::encrypt data, password
|
220
340
|
|
221
341
|
enc_filename = filename + ".enc"
|
342
|
+
|
343
|
+
if File.exists?(enc_filename)
|
344
|
+
FileOps::backup enc_filename
|
345
|
+
puts "Warning: existing #{enc_filename} backupped to #{enc_filename}~"
|
346
|
+
end
|
222
347
|
FileOps::save enc_filename, encrypted
|
223
348
|
puts "An encrypted copy now lives in #{enc_filename}"
|
224
349
|
puts "You might want to check everything is ok and delete the plain file: #{filename}"
|
225
350
|
end
|
226
351
|
end
|
227
352
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
353
|
+
##############################################################################
|
354
|
+
command :decrypt do
|
355
|
+
banner "pwss decrypt [options]"
|
356
|
+
description "Decrypt a password safe"
|
357
|
+
|
358
|
+
on "-f", "--filename=", "Password file to decrypt. Write to <file>, without '.enc'."
|
359
|
+
|
360
|
+
run do |opts, _|
|
361
|
+
filename = opts.to_hash[:filename] || DEFAULT_FILENAME
|
362
|
+
|
363
|
+
if not File.exists?(filename)
|
364
|
+
puts "Error: file #{filename} does not exist."
|
365
|
+
exit 1
|
366
|
+
end
|
234
367
|
|
235
368
|
password = Cipher::ask_password
|
236
369
|
data = FileOps::load filename
|
237
370
|
decrypted = Cipher::decrypt data, password
|
238
371
|
|
239
372
|
dec_filename = filename.sub(/\.enc$/,"")
|
373
|
+
if File.exists?(dec_filename)
|
374
|
+
FileOps::backup dec_filename
|
375
|
+
puts "Warning: existing #{dec_filename} backupped to #{dec_filename}~"
|
376
|
+
end
|
377
|
+
|
240
378
|
FileOps::save dec_filename, decrypted
|
241
379
|
puts "A decrypted copy now lives in #{dec_filename}"
|
242
380
|
puts "You might want to check everything is ok and delete #{filename}, if you wish."
|
243
381
|
end
|
244
382
|
end
|
245
383
|
|
246
|
-
p.command(:help) do |c|
|
247
|
-
c.action do |_,_|
|
248
|
-
puts p.to_s
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
p.default_command(:help)
|
253
|
-
|
254
|
-
# load filename and decrypt, if necessary
|
255
|
-
# return the filename as string and the password (in case you need to save)
|
256
|
-
def file2string filename
|
257
|
-
string = FileOps::load filename
|
258
|
-
if FileOps::encrypted? filename then
|
259
|
-
password = Cipher::ask_password
|
260
|
-
string = Cipher::decrypt string, password
|
261
|
-
end
|
262
|
-
[string, password]
|
263
|
-
end
|
264
384
|
end
|
data/lib/pwss.rb
CHANGED
@@ -85,12 +85,13 @@ module Pwss
|
|
85
85
|
|
86
86
|
if found.size > 1 or confirm_even_if_one then
|
87
87
|
printf "\nVarious matches." if found.size > 1
|
88
|
-
printf "\nSelect entry by ID (0..#{found.size-1})
|
88
|
+
printf "\nSelect entry by ID (0..#{found.size-1}); -1 or empty string to exit: "
|
89
89
|
|
90
90
|
id = STDIN.gets.chomp.to_i
|
91
91
|
while (id < -1 or id >= found.size)
|
92
|
-
printf "Select entry by ID (0..#{found.size-1})
|
93
|
-
|
92
|
+
printf "Select entry by ID (0..#{found.size-1}); -1 or empty string to exit: "
|
93
|
+
response = STDIN.gets.chomp
|
94
|
+
id = response == "" ? -1 : response.to_i
|
94
95
|
end
|
95
96
|
if id == -1 then
|
96
97
|
exit -1
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'pwss/entry'
|
2
|
+
|
3
|
+
module Pwss
|
4
|
+
class BankAccount < Entry
|
5
|
+
def initialize
|
6
|
+
super
|
7
|
+
@fields = {
|
8
|
+
"title" => ["Readline.readline('title: ')", "'title'"],
|
9
|
+
"name" => ["Readline.readline('name: ')", "'name'"],
|
10
|
+
"iban" => ["Readline.readline('iban: ')", "ITkk xaaa aabb bbbc cccc cccc ccc"],
|
11
|
+
"created_at" => ["", "Date.today"],
|
12
|
+
"updated_at" => ["", "nil"],
|
13
|
+
"url" => ["Readline.readline('url: ')", "''"],
|
14
|
+
"description" => ["get_lines", "''"]
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'pwss/entry'
|
2
|
+
|
3
|
+
module Pwss
|
4
|
+
class CreditCard < Entry
|
5
|
+
def initialize
|
6
|
+
super
|
7
|
+
@fields = {
|
8
|
+
"title" => ["Readline.readline('title: ')", "'title'"],
|
9
|
+
"issuer" => ["Readline.readline('issuer: ')", "MasterCard"],
|
10
|
+
"name_on_card" => ["Readline.readline('name on card: ')", "'john doe'"],
|
11
|
+
"card_number" => ["Readline.readline('number: ')", "000-0000-0000-0000"],
|
12
|
+
"valid_from" => ["Readline.readline('valid from: ')", "Sep 2014"],
|
13
|
+
"valid_till" => ["Readline.readline('valid till: ')", "Sep 2018"],
|
14
|
+
"verification_number" => ["Readline.readline('verification number: ')", "000"],
|
15
|
+
"pin" => ["Readline.readline('pin: ')", "0000"],
|
16
|
+
"created_at" => ["", "Date.today"],
|
17
|
+
"updated_at" => ["", "nil"],
|
18
|
+
"url" => ["Readline.readline('url: ')", "''"],
|
19
|
+
"notes" => ["get_lines", "''"]
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/pwss/entry.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require 'readline'
|
2
|
+
require 'pwss/cipher'
|
3
|
+
require 'date'
|
2
4
|
|
3
5
|
module Pwss
|
4
6
|
#
|
@@ -6,41 +8,41 @@ module Pwss
|
|
6
8
|
# It is a wrapper to a Hash
|
7
9
|
#
|
8
10
|
class Entry
|
9
|
-
INPUT_F=0
|
10
|
-
DEFAULT=1
|
11
|
-
PROMPT=2
|
11
|
+
INPUT_F = 0
|
12
|
+
DEFAULT = 1
|
12
13
|
|
13
|
-
|
14
|
-
FIELDS = {
|
15
|
-
"title" => ["Readline.readline('title: ')", "'title'"],
|
16
|
-
"username" => ["Readline.readline('username: ')", "''"],
|
17
|
-
"password" => ["Cipher.check_or_generate('password for entry', length, alnum)", "''"],
|
18
|
-
"created_at" => ["", "Date.today"],
|
19
|
-
"updated_at" => ["", "nil"],
|
20
|
-
"url" => ["Readline.readline('url: ')", "''"],
|
21
|
-
"description" => ["get_lines", "''"]
|
22
|
-
}
|
23
|
-
|
24
|
-
# the values (a Hash) of this issue
|
25
|
-
attr_reader :entry
|
14
|
+
attr_reader :entry, :fields
|
26
15
|
|
27
16
|
def initialize
|
28
17
|
@entry = Hash.new
|
18
|
+
|
19
|
+
# the fields of an entry, together with:
|
20
|
+
# - the function to ask the
|
21
|
+
# - the default value
|
22
|
+
@fields = {
|
23
|
+
"title" => ["Readline.readline('title: ')", "'title'"],
|
24
|
+
"username" => ["Readline.readline('username: ')", "''"],
|
25
|
+
"password" => ["Cipher.check_or_generate('password for entry', length, alnum)", "''"],
|
26
|
+
"created_at" => ["", "Date.today"],
|
27
|
+
"updated_at" => ["", "nil"],
|
28
|
+
"url" => ["Readline.readline('url: ')", "''"],
|
29
|
+
"description" => ["get_lines", "''"]
|
30
|
+
}
|
29
31
|
end
|
30
32
|
|
31
33
|
# interactively ask from command line all fields specified in FIELDS
|
32
34
|
# arguments length and alnum are for password generation
|
33
|
-
def ask length, alnum
|
34
|
-
|
35
|
-
@entry[key] = (eval
|
35
|
+
def ask length = 8, alnum = true
|
36
|
+
@fields.keys.each do |key|
|
37
|
+
@entry[key] = (eval @fields[key][INPUT_F]) || (eval @fields[key][DEFAULT])
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
39
41
|
# initialize all fields with the default values
|
40
42
|
# (and set title to the argument)
|
41
43
|
# def set_fields title
|
42
|
-
#
|
43
|
-
# @entry[k] = eval(
|
44
|
+
# fields.keys.each do |k|
|
45
|
+
# @entry[k] = eval(fields[k][DEFAULT])
|
44
46
|
# end
|
45
47
|
# @entry['title'] = title
|
46
48
|
# end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'pwss/entry'
|
2
|
+
|
3
|
+
module Pwss
|
4
|
+
class SoftwareLicense < Entry
|
5
|
+
def initialize
|
6
|
+
super
|
7
|
+
@fields = {
|
8
|
+
"title" => ["Readline.readline('title: ')", "'title'"],
|
9
|
+
"version" => ["Readline.readline('version: ')", "0.0.1"],
|
10
|
+
"license_number" => ["Readline.readline('license number: ')", "000-0000-0000-0000"],
|
11
|
+
"licensed_to" => ["Readline.readline('licensed to: ')", "'John Doe'"],
|
12
|
+
"email" => ["Readline.readline('email: ')", "jdoe@example.com"],
|
13
|
+
"purchased_on" => ["Readline.readline('purchased on: ')", "'Date.today'"],
|
14
|
+
"created_at" => ["", "Date.today"],
|
15
|
+
"updated_at" => ["", "nil"],
|
16
|
+
"url" => ["Readline.readline('url: ')", "''"],
|
17
|
+
"notes" => ["get_lines", "''"]
|
18
|
+
}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/pwss/version.rb
CHANGED
data/pwss.gemspec
CHANGED
@@ -9,12 +9,14 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Adolfo Villafiorita"]
|
10
10
|
spec.email = ["adolfo.villafiorita@me.com"]
|
11
11
|
spec.summary = %q{A password manager in the spirit of pwss}
|
12
|
-
spec.description = %q{PWSS is a password
|
12
|
+
spec.description = %q{PWSS is a command-line password manager, in the spirit of pws
|
13
13
|
Distinguishing features:
|
14
|
-
-
|
15
|
-
-
|
16
|
-
-
|
17
|
-
-
|
14
|
+
- the command manages different password files
|
15
|
+
- a password file can store multiple entries
|
16
|
+
- entries are of different types (Entry, CreditCard, BankAccount)
|
17
|
+
- each type stores specific information (e.g., name, card_number for CreditCards)
|
18
|
+
- a password file can be encrypted or in plain text (if you wish to do so)
|
19
|
+
- decrypt and encrypt commands allow to edit password files directly
|
18
20
|
}
|
19
21
|
spec.homepage = "http://www.github.com/avillafiorita/pwss"
|
20
22
|
spec.license = "MIT"
|
@@ -27,6 +29,6 @@ Distinguishing features:
|
|
27
29
|
spec.add_development_dependency "bundler", "~> 1.5"
|
28
30
|
spec.add_development_dependency "rake"
|
29
31
|
|
30
|
-
spec.add_runtime_dependency '
|
32
|
+
spec.add_runtime_dependency 'slop', '~> 3.6.0', '>= 3.6.0'
|
31
33
|
spec.add_runtime_dependency 'encryptor', '~> 1.3.0', '>= 1.3.0'
|
32
34
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pwss
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adolfo Villafiorita
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -39,25 +39,25 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: slop
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 3.6.0
|
48
48
|
- - ">="
|
49
49
|
- !ruby/object:Gem::Version
|
50
|
-
version:
|
50
|
+
version: 3.6.0
|
51
51
|
type: :runtime
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
55
|
- - "~>"
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version:
|
57
|
+
version: 3.6.0
|
58
58
|
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version:
|
60
|
+
version: 3.6.0
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: encryptor
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -79,12 +79,14 @@ dependencies:
|
|
79
79
|
- !ruby/object:Gem::Version
|
80
80
|
version: 1.3.0
|
81
81
|
description: |
|
82
|
-
PWSS is a password
|
82
|
+
PWSS is a command-line password manager, in the spirit of pws
|
83
83
|
Distinguishing features:
|
84
|
-
-
|
85
|
-
-
|
86
|
-
-
|
87
|
-
-
|
84
|
+
- the command manages different password files
|
85
|
+
- a password file can store multiple entries
|
86
|
+
- entries are of different types (Entry, CreditCard, BankAccount)
|
87
|
+
- each type stores specific information (e.g., name, card_number for CreditCards)
|
88
|
+
- a password file can be encrypted or in plain text (if you wish to do so)
|
89
|
+
- decrypt and encrypt commands allow to edit password files directly
|
88
90
|
email:
|
89
91
|
- adolfo.villafiorita@me.com
|
90
92
|
executables:
|
@@ -99,9 +101,12 @@ files:
|
|
99
101
|
- Rakefile
|
100
102
|
- bin/pwss
|
101
103
|
- lib/pwss.rb
|
104
|
+
- lib/pwss/bank_account.rb
|
102
105
|
- lib/pwss/cipher.rb
|
106
|
+
- lib/pwss/credit_card.rb
|
103
107
|
- lib/pwss/entry.rb
|
104
108
|
- lib/pwss/fileops.rb
|
109
|
+
- lib/pwss/software_license.rb
|
105
110
|
- lib/pwss/version.rb
|
106
111
|
- pwss.gemspec
|
107
112
|
homepage: http://www.github.com/avillafiorita/pwss
|
@@ -129,3 +134,4 @@ signing_key:
|
|
129
134
|
specification_version: 4
|
130
135
|
summary: A password manager in the spirit of pwss
|
131
136
|
test_files: []
|
137
|
+
has_rdoc:
|