pwss 0.1.0 → 0.3.0
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.
- 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:
|