pwss 0.5.1 → 0.6.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.
@@ -0,0 +1,19 @@
1
+ require 'pwss/generators/entry'
2
+
3
+ module Pwss
4
+ class SoftwareLicense < Entry
5
+ def initialize
6
+ super
7
+ @fields = [
8
+ "title",
9
+ "version",
10
+ "licensed_to",
11
+ "license_number",
12
+ "email",
13
+ "purchased_on",
14
+ "url",
15
+ "description"
16
+ ]
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,94 @@
1
+ require 'clipboard'
2
+
3
+ module Pwss
4
+ # some functions to manage password generation and clipboard
5
+ module Password
6
+ DEFAULT_PASSWORD_LENGTH=16
7
+
8
+ # generate a password
9
+ #
10
+ # optional hash +arguments+ allows to define a strategy for
11
+ # generating a password and the password length of automatically
12
+ # generated passwords)
13
+ #
14
+ #
15
+ def self.password arguments = {}
16
+ strategy = arguments[:strategy] || 'random'
17
+ length = arguments[:length] || DEFAULT_PASSWORD_LENGTH
18
+
19
+ case strategy
20
+ when 'random'
21
+ return Pwss::Password.random_password(length, false)
22
+ when 'alpha'
23
+ return Pwss::Password.random_password(length, true)
24
+ when 'ask'
25
+ return Pwss::Password.ask_password_twice "new password for entry"
26
+ when 'pwgen'
27
+ begin
28
+ password = %x(pwgen -N1 #{length}).chomp
29
+ return password
30
+ rescue
31
+ raise "Error: pwgen not found. Use one of random, alpha, or ask."
32
+ end
33
+ else
34
+ raise "Error: strategy not understood. Use one of random, alpha, pwgen, or ask"
35
+ end
36
+ end
37
+
38
+ # Ask for a password fom the command line
39
+ def self.ask_password prompt="Enter master password: "
40
+ printf prompt
41
+ system "stty -echo"
42
+ password = $stdin.gets.chomp
43
+ system "stty echo"
44
+ puts ""
45
+ password
46
+ end
47
+
48
+ # Ask for a password twice and make sure it is entered the same
49
+ def self.ask_password_twice prompt="master password"
50
+ match = false
51
+ while ! match
52
+ password = ask_password "Enter #{prompt}: "
53
+ repeat = ask_password "Repeat #{prompt}: "
54
+ match = (password == repeat)
55
+
56
+ if match == false then
57
+ puts "Error! Password do not match. Please enter them again."
58
+ end
59
+ end
60
+ password
61
+ end
62
+
63
+ # Generate a random password
64
+ # (Adapted from: http://randompasswordsgenerator.net/tutorials/ruby-random-password-generator.html)
65
+ def self.random_password length=DEFAULT_PASSWORD_LENGTH, alnum=false
66
+ chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ1234567890'
67
+ chars += '!@#$%^&*()_+=[]{}<>/~,.;:|' if not alnum
68
+ Array.new(length) { chars[rand(chars.length)].chr }.join
69
+ end
70
+
71
+ #
72
+ # make a field available to the clipboard for a given time (in seconds).
73
+ #
74
+ def self.to_clipboard field_name, value, counter = 30
75
+ old_clipboard = Clipboard.paste
76
+ Clipboard.copy value
77
+
78
+ begin
79
+ if counter <= 0
80
+ STDIN.flush
81
+ puts "\n#{field_name.capitalize} available in clipboard: press enter when you are done."
82
+ STDIN.getc
83
+ else
84
+ puts "\n#{field_name.capitalize} available in clipboard for #{counter} seconds."
85
+ sleep(counter)
86
+ end
87
+ Clipboard.copy old_clipboard
88
+ rescue Exception => e
89
+ Clipboard.copy old_clipboard
90
+ puts "Clipboard restored"
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,183 @@
1
+ require 'yaml'
2
+
3
+ #
4
+ # A password safe is a list of entries
5
+ #
6
+
7
+ module Pwss
8
+ class Safe
9
+ attr_reader :filename, :entries, :password
10
+
11
+ def initialize filename
12
+ @filename = filename
13
+ @password = nil
14
+ @entries = Array.new
15
+ end
16
+
17
+ def rename new_filename
18
+ @filename = new_filename
19
+ end
20
+
21
+ def load
22
+ string = FileOps::load @filename
23
+ if FileOps::symmetric? filename then
24
+ @password = Password::ask_password
25
+ string = Cipher::decrypt string, password
26
+ elsif FileOps::gpg? filename then
27
+ crypto = GPGME::Crypto.new
28
+ cipher = crypto.decrypt string
29
+ string = cipher.to_s
30
+ end
31
+ @entries = YAML::load(string) || Array.new
32
+ end
33
+
34
+
35
+ def save
36
+ if FileOps::symmetric? filename then
37
+ if not @password
38
+ @password = Password::ask_password_twice
39
+ end
40
+ new_string = Cipher::encrypt @entries.to_yaml, @password
41
+ elsif FileOps::gpg? filename then
42
+ crypto = GPGME::Crypto.new
43
+ cipher = crypto.encrypt @entries.to_yaml, :recipients => "pwss-agent@example.com"
44
+ new_string = cipher.to_s
45
+ else
46
+ new_string = entries.to_yaml
47
+ end
48
+ FileOps::backup filename if File.exist? filename
49
+ FileOps::save filename, new_string
50
+ end
51
+
52
+
53
+ # switch from plain to encrypted file
54
+ # the function changes the filename and sets a password (if needed)
55
+ # this function requires the file to be loaded since it changes the filename
56
+ def toggle_encryption hash = Hash.new
57
+ password = hash[:password] || nil
58
+ schema = hash[:schema] || :gpg
59
+
60
+ if FileOps::encrypted? filename then
61
+ @password = nil
62
+ @filename = @filename.sub(/\.(gpg|enc)$/, "")
63
+ else
64
+ @password = password
65
+ @filename = schema == :gpg ? @filename + ".gpg" : @filename + ".enc"
66
+ end
67
+ end
68
+
69
+
70
+ def add new_entry
71
+ @entries << new_entry
72
+ end
73
+
74
+
75
+ def update id, field, new_value
76
+ @entries[id][field] = new_value
77
+ end
78
+
79
+
80
+ def destroy id
81
+ @entries.delete_at(id) if id != -1
82
+ end
83
+
84
+
85
+ # return the pairs [entry, id] matching a string
86
+ def match string
87
+ entries.each_with_index.select { |e, i| e["title"].downcase.include?(string.downcase) }
88
+ end
89
+
90
+
91
+ def get id
92
+ entries[id]
93
+ end
94
+
95
+ def get_pruned id
96
+ entry = entries[id]
97
+ new_entry = entry.dup
98
+ entry.keys.map { |x| new_entry[x] = "********" if Pwss::Fields::sensitive? x }
99
+ new_entry
100
+ end
101
+
102
+ def get_field id, field
103
+ entries[id][field]
104
+ end
105
+
106
+ def [](id)
107
+ entries[id]
108
+ end
109
+
110
+ # return the entries after pruning some fields
111
+ # fields is an array of strings
112
+ def prune fields
113
+ entries.map { |x| Safe.prune_entry x, fields }
114
+ end
115
+
116
+ # prune fields (array of strings) from entry, by deleting the corresponding key
117
+ # this is used to clean databases when support for some fields is dropeed (e.g.,
118
+ # created_at, updated_at)
119
+ def self.prune_entry entry, fields
120
+ @new_entry = entry.dup
121
+ fields.map { |x| @new_entry.delete(x) }
122
+ @new_entry
123
+ end
124
+
125
+ # return the entries showing only some fields
126
+ # fields is an array of strings
127
+ #def pick fields
128
+ # entries.map { |x| Safe.cherry_pick_entry x, fields }
129
+ #end
130
+
131
+ # return only some fields from entry
132
+ # def self.cherry_pick_entry entry, fields
133
+ # @new_entry = Hash.new
134
+ # fields.each do |f|
135
+ # @new_entry[f] = entry[f]
136
+ # end
137
+ # @new_entry
138
+ # end
139
+
140
+ #
141
+ # Let the user select an id from a list
142
+ #
143
+ # entries_with_ids is a array of [entry, id] (e.g. the output of match)
144
+ # even_if_one requires to select the entry even if there is one match
145
+ #
146
+ def self.choose_entry entries_with_ids, even_if_one = false
147
+ if entries_with_ids == nil or entries_with_ids.size == 0
148
+ puts "No entry matches your search criteria. Exiting."
149
+ return -1
150
+ end
151
+
152
+ entries = entries_with_ids.map { |x| x[0] }
153
+ ids = entries_with_ids.map { |x| x[1] }
154
+
155
+ if even_if_one or entries.size > 1
156
+ entries.size > 1 ? puts("pwss matches:") : puts("pwss match:")
157
+ # pruned = entries.map { |x| Pwss::Safe.prune_entry x, ["password", "pin", "verification_number"] }
158
+ entries.each_with_index do |e, i|
159
+ puts Pwss::Safe.entry_to_s ids[i], e
160
+ end
161
+ id = nil
162
+ puts "\n"
163
+ while (id != -1 and not ids.include?(id))
164
+ response = Readline.readline "Select entry by ID (#{ids.join(", ")}); -1 or empty string to exit: "
165
+ id = response == "" ? -1 : response.to_i
166
+ end
167
+ else
168
+ puts "pwss has one match:"
169
+ # pruned = Pwss::Safe.prune_entry entries[0], ["password", "pin", "verification_number"]
170
+ puts Pwss::Safe.entry_to_s ids[0], entries[0]
171
+ id = ids[0]
172
+ end
173
+ id
174
+ end
175
+
176
+ private
177
+
178
+ def self.entry_to_s id, entry
179
+ "#{"%4d" % id}. #{entry["title"]}"
180
+ end
181
+
182
+ end
183
+ end
@@ -1,3 +1,3 @@
1
1
  module Pwss
2
- VERSION = "0.5.1"
2
+ VERSION = "0.6.0"
3
3
  end
@@ -8,27 +8,33 @@ Gem::Specification.new do |spec|
8
8
  spec.version = Pwss::VERSION
9
9
  spec.authors = ["Adolfo Villafiorita"]
10
10
  spec.email = ["adolfo.villafiorita@me.com"]
11
- spec.summary = %q{A password manager in the spirit of pwss}
11
+
12
+ spec.summary = %q{A password manager in the spirit of pass and pws}
12
13
  spec.description = %q{PWSS is a command-line password manager, in the spirit of pws
13
14
  Distinguishing features:
14
- - the command manages different password files
15
+ - pwss manages different password files
15
16
  - 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
17
+ - entries can be of different types (e.g., Entry, CreditCard, BankAccount)
18
+ - each type stores specific information (e.g., card_number for CreditCards)
19
+ - a password file can be encrypted or stored in plain text (if you wish to do so)
20
+ - decrypt and encrypt commands allow one to edit password files with a text editor
21
+ - clipboard integration
22
+ - multi-platform
20
23
  }
21
24
  spec.homepage = "http://www.github.com/avillafiorita/pwss"
22
25
  spec.license = "MIT"
23
26
 
24
- spec.files = `git ls-files -z`.split("\x0")
25
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
26
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
27
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
28
+ spec.bindir = "exe"
29
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
30
  spec.require_paths = ["lib"]
28
31
 
29
- spec.add_development_dependency "bundler", "~> 1.5"
30
- spec.add_development_dependency "rake"
32
+ spec.add_development_dependency "bundler", "~> 1.10"
33
+ spec.add_development_dependency "rake", "~> 10.0"
34
+ spec.add_development_dependency "minitest"
31
35
 
32
- spec.add_runtime_dependency 'slop', '~> 3.6.0', '>= 3.6.0'
33
- spec.add_runtime_dependency 'encryptor', '~> 1.3.0', '>= 1.3.0'
36
+ spec.add_runtime_dependency 'slop', '~> 4.3.0', '>= 4.3.0'
37
+ spec.add_runtime_dependency 'encryptor', '~> 1.3.0', '~> 1.3.0'
38
+ spec.add_runtime_dependency 'clipboard', '~> 1.0.6', '>= 1.0.6'
39
+ spec.add_runtime_dependency 'gpgme', '~> 2.0.12', '>= 2.0.12'
34
40
  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.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adolfo Villafiorita
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2015-09-21 00:00:00.000000000 Z
11
+ date: 2016-06-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,16 +16,30 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.5'
19
+ version: '1.10'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.5'
26
+ version: '1.10'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - ">="
@@ -44,20 +58,20 @@ dependencies:
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: 3.6.0
61
+ version: 4.3.0
48
62
  - - ">="
49
63
  - !ruby/object:Gem::Version
50
- version: 3.6.0
64
+ version: 4.3.0
51
65
  type: :runtime
52
66
  prerelease: false
53
67
  version_requirements: !ruby/object:Gem::Requirement
54
68
  requirements:
55
69
  - - "~>"
56
70
  - !ruby/object:Gem::Version
57
- version: 3.6.0
71
+ version: 4.3.0
58
72
  - - ">="
59
73
  - !ruby/object:Gem::Version
60
- version: 3.6.0
74
+ version: 4.3.0
61
75
  - !ruby/object:Gem::Dependency
62
76
  name: encryptor
63
77
  requirement: !ruby/object:Gem::Requirement
@@ -65,28 +79,64 @@ dependencies:
65
79
  - - "~>"
66
80
  - !ruby/object:Gem::Version
67
81
  version: 1.3.0
68
- - - ">="
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
69
87
  - !ruby/object:Gem::Version
70
88
  version: 1.3.0
89
+ - !ruby/object:Gem::Dependency
90
+ name: clipboard
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: 1.0.6
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: 1.0.6
71
99
  type: :runtime
72
100
  prerelease: false
73
101
  version_requirements: !ruby/object:Gem::Requirement
74
102
  requirements:
75
103
  - - "~>"
76
104
  - !ruby/object:Gem::Version
77
- version: 1.3.0
105
+ version: 1.0.6
78
106
  - - ">="
79
107
  - !ruby/object:Gem::Version
80
- version: 1.3.0
108
+ version: 1.0.6
109
+ - !ruby/object:Gem::Dependency
110
+ name: gpgme
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: 2.0.12
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: 2.0.12
119
+ type: :runtime
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: 2.0.12
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: 2.0.12
81
129
  description: |
82
130
  PWSS is a command-line password manager, in the spirit of pws
83
131
  Distinguishing features:
84
- - the command manages different password files
132
+ - pwss manages different password files
85
133
  - 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
134
+ - entries can be of different types (e.g., Entry, CreditCard, BankAccount)
135
+ - each type stores specific information (e.g., card_number for CreditCards)
136
+ - a password file can be encrypted or stored in plain text (if you wish to do so)
137
+ - decrypt and encrypt commands allow one to edit password files with a text editor
138
+ - clipboard integration
139
+ - multi-platform
90
140
  email:
91
141
  - adolfo.villafiorita@me.com
92
142
  executables:
@@ -95,18 +145,28 @@ extensions: []
95
145
  extra_rdoc_files: []
96
146
  files:
97
147
  - ".gitignore"
148
+ - ".travis.yml"
98
149
  - Gemfile
99
150
  - LICENSE.txt
100
- - README.textile
151
+ - README.md
101
152
  - Rakefile
102
- - bin/pwss
153
+ - bin/console
154
+ - bin/setup
155
+ - exe/pwss
103
156
  - lib/pwss.rb
104
- - lib/pwss/bank_account.rb
105
157
  - lib/pwss/cipher.rb
106
- - lib/pwss/credit_card.rb
107
- - lib/pwss/entry.rb
158
+ - lib/pwss/cli/command_semantics.rb
159
+ - lib/pwss/cli/command_syntax.rb
108
160
  - lib/pwss/fileops.rb
109
- - lib/pwss/software_license.rb
161
+ - lib/pwss/generators/bank_account.rb
162
+ - lib/pwss/generators/code.rb
163
+ - lib/pwss/generators/credit_card.rb
164
+ - lib/pwss/generators/entry.rb
165
+ - lib/pwss/generators/fields.rb
166
+ - lib/pwss/generators/sim.rb
167
+ - lib/pwss/generators/software_license.rb
168
+ - lib/pwss/password.rb
169
+ - lib/pwss/safe.rb
110
170
  - lib/pwss/version.rb
111
171
  - pwss.gemspec
112
172
  homepage: http://www.github.com/avillafiorita/pwss
@@ -129,8 +189,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
189
  version: '0'
130
190
  requirements: []
131
191
  rubyforge_project:
132
- rubygems_version: 2.4.5.1
192
+ rubygems_version: 2.5.1
133
193
  signing_key:
134
194
  specification_version: 4
135
- summary: A password manager in the spirit of pwss
195
+ summary: A password manager in the spirit of pass and pws
136
196
  test_files: []