uberpass 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -2,3 +2,4 @@
2
2
  .bundle
3
3
  Gemfile.lock
4
4
  pkg/*
5
+ password.txt
data/README.rdoc CHANGED
@@ -9,12 +9,22 @@
9
9
  $ openssl genrsa -des3 -out ~/.uberpass/private.pem 2048
10
10
  $ openssl rsa -in ~/.uberpass/private.pem -out ~/.uberpass/public.pem -outform PEM -pubout
11
11
 
12
+ == Dropbox
13
+
14
+ $ mv ~/.uberpass ~/Dropbox/uberpass
15
+ $ ln -s ~/Dropbox/uberpass ~/.uberpass
16
+
12
17
  == Use
13
18
 
14
- You personal passwords:
19
+ Your personal passwords:
15
20
 
16
21
  $ uberpass
17
22
 
18
23
  or your work related passwords:
19
24
 
20
25
  $ uberpass happy_place
26
+
27
+ and getting some help:
28
+
29
+ $ uberpass
30
+ $ uberpass:0.0.4> help
data/lib/uberpass.rb CHANGED
@@ -1,314 +1,11 @@
1
- require 'uberpass/version'
2
1
  require 'openssl'
3
2
  require 'yaml'
4
- require 'ostruct'
5
- require 'securerandom'
6
-
7
- module Uberpass
8
- class Decrypt
9
- attr_reader :decrypted_data
10
-
11
- def initialize(private_key, encrypted_data, encrypted_key, encrypted_iv)
12
- key = OpenSSL::PKey::RSA.new(private_key)
13
- cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
14
- cipher.decrypt
15
- cipher.key = key.private_decrypt(encrypted_key)
16
- cipher.iv = key.private_decrypt(encrypted_iv)
17
-
18
- @decrypted_data = cipher.update(encrypted_data)
19
- @decrypted_data << cipher.final
20
- end
21
- end
22
-
23
- class Encrypt
24
- attr_reader :encrypted_data, :encrypted_key, :encrypted_iv
25
-
26
- def initialize(public_key, decrypted_data)
27
- key = OpenSSL::PKey::RSA.new(public_key)
28
- cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
29
- cipher.encrypt
30
- cipher.key = random_key = cipher.random_key
31
- cipher.iv = random_iv = cipher.random_iv
32
-
33
- @encrypted_data = cipher.update(decrypted_data)
34
- @encrypted_data << cipher.final
35
-
36
- @encrypted_key = key.public_encrypt(random_key)
37
- @encrypted_iv = key.public_encrypt(random_iv)
38
- end
39
- end
40
-
41
- class FileHandler
42
- class << self
43
- attr_accessor :namespace
44
-
45
- def configure
46
- yield self
47
- end
48
-
49
- def name_spaced_file(file_name)
50
- @namespace.nil? ? file_name : "#{file_name}_#{@namespace}"
51
- end
52
-
53
- def private_key_file
54
- File.expand_path("~/.uberpass/private.pem")
55
- end
56
-
57
- def public_key_file
58
- File.expand_path("~/.uberpass/public.pem")
59
- end
60
-
61
- def passwords_file
62
- File.expand_path("~/.uberpass/#{name_spaced_file("passwords")}")
63
- end
64
-
65
- def key_file
66
- File.expand_path("~/.uberpass/#{name_spaced_file("key")}")
67
- end
68
-
69
- def iv_file
70
- File.expand_path("~/.uberpass/#{name_spaced_file("iv")}")
71
- end
72
-
73
- def write(encryptor)
74
- File.open(passwords_file, "w") { |file|
75
- file.write(encryptor.encrypted_data)
76
- }
77
- File.open(key_file, "w") { |file|
78
- file.write(encryptor.encrypted_key)
79
- }
80
- File.open(iv_file, "w") { |file|
81
- file.write(encryptor.encrypted_iv)
82
- }
83
- end
84
-
85
- def decrypted_passwords
86
- if File.exists?(passwords_file)
87
- YAML::load(
88
- Decrypt.new(
89
- File.read(private_key_file),
90
- File.read(passwords_file),
91
- File.read(key_file),
92
- File.read(iv_file)
93
- ).decrypted_data
94
- )
95
- else
96
- {}
97
- end
98
- end
99
-
100
- def show(key)
101
- Hash[*[key, decrypted_passwords[key]]]
102
- end
103
-
104
- def all
105
- decrypted_passwords.map do |entry|
106
- Hash[*entry]
107
- end
108
- end
109
-
110
- def generate_short(key)
111
- encrypt key, SecureRandom.urlsafe_base64(8)
112
- end
113
-
114
- def generate(key)
115
- encrypt key, SecureRandom.urlsafe_base64(24)
116
- end
117
-
118
- def encrypt(key, password)
119
- passwords = decrypted_passwords
120
- entry = passwords[key] = {
121
- "password" => password,
122
- "created_at" => Time.now
123
- }
124
- encryptor = Encrypt.new(File.read(public_key_file), passwords.to_yaml)
125
- write(encryptor)
126
- Hash[*[key, entry]]
127
- end
128
-
129
- def rename(old, new)
130
- passwords = decrypted_passwords
131
- entry = passwords.delete old
132
- passwords[new] = entry
133
- encryptor = Encrypt.new(File.read(public_key_file), passwords.to_yaml)
134
- write(encryptor)
135
- Hash[*[new, entry]]
136
- end
137
-
138
- def destroy(key)
139
- passwords = decrypted_passwords
140
- entry = passwords.delete key
141
- encryptor = Encrypt.new(File.read(public_key_file), passwords.to_yaml)
142
- write(encryptor)
143
- Hash[*[key, entry]]
144
- end
145
-
146
- end
147
- end
148
-
149
- class CLI
150
- class InvalidActionError < StandardError; end
151
- class MissingArgumentError < StandardError; end
152
-
153
- module Actions
154
- attr_accessor :actions
155
3
 
156
- def register_action(*args, &block)
157
- options = args.size == 1 ? {} : (args.last || {})
158
- options[:short] = options[:short].nil? ? args.first[0] : options.delete(:short).to_s
159
- options[:steps] = [] if options[:steps].nil?
160
- options[:filter] = [] if options[:filter].nil?
161
- options[:confirm] = false if options[:confirm].nil?
162
- (@actions ||= []) << OpenStruct.new({ :name => args.first, :proc => block }.merge(options))
163
- end
164
- end
165
-
166
- module Formater
167
- def bold(obj)
168
- "\033[0;1m#{obj}\033[0m"
169
- end
170
-
171
- def red(obj)
172
- "\033[01;31m#{obj}\033[0m"
173
- end
174
-
175
- def green(obj)
176
- "\033[0;32m#{obj}\033[0m"
177
- end
178
-
179
- def gray(obj)
180
- "\033[1;30m#{obj}\033[0m"
181
- end
182
- end
183
-
184
- extend Actions
185
- include Formater
186
-
187
- register_action :generate, :steps => ["key"] do |key|
188
- FileHandler.generate key
189
- end
190
-
191
- register_action :generate_short, :steps => ["key"], :short => :gs do |key|
192
- FileHandler.generate_short key
193
- end
194
-
195
- register_action :destroy, :steps => ["key"], :short => :rm, :confirm => true do |key|
196
- FileHandler.destroy key
197
- end
198
-
199
- register_action :show, :steps => ["key"] do |key|
200
- FileHandler.show key
201
- end
202
-
203
- register_action :encrypt, :steps => ["key", "password"] do |key, password|
204
- FileHandler.encrypt key, password
205
- end
206
-
207
- register_action :rename, :steps => ["key", "new name"] do |old, new|
208
- FileHandler.rename old, new
209
- end
210
-
211
- register_action :list, :filter => ["password"] do
212
- FileHandler.all
213
- end
214
-
215
- register_action :dump do
216
- FileHandler.all
217
- end
218
-
219
- register_action :help do
220
- CLI.help
221
- []
222
- end
223
-
224
- register_action :exit, :short => :ex do
225
- exit
226
- end
227
-
228
- def initialize(namespace)
229
- FileHandler.configure do |handler|
230
- handler.namespace = namespace
231
- end
232
- line
233
- do_action
234
- end
235
-
236
- def line(message = nil, format = :bold)
237
- parts = []
238
- parts << "\nuberpass"
239
- parts << "#{VERSION}:"
240
- parts << send(format, message) unless message.nil?
241
- parts << "> "
242
- print parts.join(' ')
243
- end
244
-
245
- def self.help
246
- print "\nactions:\n"
247
- actions.each do |action|
248
- print " #{action.name}\n"
249
- end
250
- end
251
-
252
- def confirm_action
253
- line "are you sure you? [yn]", :green
254
- $stdin.gets.chomp == "y"
255
- end
256
-
257
- def do_action
258
- input = $stdin.gets.chomp
259
- do_action_with_rescue input
260
- end
261
-
262
- def do_action_with_rescue(input)
263
- args = input.split(/ /)
264
- begin
265
- action = fetch_action args.slice!(0)
266
- action.steps[args.size, action.steps.size].each do |instruction|
267
- line instruction, :green
268
- arg = $stdin.gets.chomp
269
- raise MissingArgumentError, instruction if arg == ""
270
- args << arg
271
- end
272
- if action.confirm
273
- pp(action.proc.call(*args), action.filter) if confirm_action
274
- else
275
- pp(action.proc.call(*args), action.filter)
276
- end
277
- print "\n"
278
- line
279
- do_action
280
- rescue MissingArgumentError => e
281
- line e, :red
282
- do_action
283
- rescue InvalidActionError => e
284
- line e, :red
285
- do_action
286
- rescue OpenSSL::PKey::RSAError => e
287
- line e, :red
288
- do_action
289
- end
290
- end
291
-
292
- def fetch_action(key)
293
- self.class.actions.each do |action|
294
- return action if action.name == key.to_sym || action.short == key
295
- end
296
- raise InvalidActionError, key
297
- end
4
+ require 'uberpass/version'
5
+ require 'uberpass/decrypt'
6
+ require 'uberpass/encrypt'
7
+ require 'uberpass/file_handler'
8
+ require 'uberpass/cli'
298
9
 
299
- def pp(entry, filter)
300
- if entry.is_a? Array
301
- entry.each do |entry|
302
- pp entry, filter
303
- end
304
- else
305
- key = entry.keys.first
306
- filter.each do |f|
307
- entry[key].delete f
308
- end
309
- print "\n#{gray entry[key]["created_at"].strftime("%d/%m/%Y")} #{bold key} "
310
- print "\n#{entry[key]["password"]}" unless entry[key]["password"].nil?
311
- end
312
- end
313
- end
10
+ module Uberpass
314
11
  end
@@ -0,0 +1,284 @@
1
+ require 'ostruct'
2
+ require "highline"
3
+
4
+ module Uberpass
5
+ class CLI
6
+ class InvalidActionError < StandardError
7
+ attr_reader :action
8
+
9
+ def initialize action
10
+ @action = action
11
+ super
12
+ end
13
+
14
+ def to_s
15
+ "\\'#{action}\\' is not a uberpass command"
16
+ end
17
+ end
18
+
19
+ class MissingArgumentError < StandardError; end
20
+
21
+ module Actions
22
+ class Register
23
+ attr_accessor :name, :short, :usage, :description, :confirm
24
+ attr_writer :proc
25
+
26
+ def call *args
27
+ @proc.call *args
28
+ end
29
+ end
30
+
31
+ attr_accessor :actions
32
+
33
+ def register_action
34
+ register = Register.new
35
+ yield register
36
+ (@actions ||= []) << register
37
+ end
38
+ end
39
+
40
+ HighLine.color_scheme = HighLine::ColorScheme.new do |cs|
41
+ cs[:error] = [:bold, :red]
42
+ cs[:confirm] = [:green]
43
+ cs[:date] = [:white]
44
+ cs[:name] = [:bold]
45
+ cs[:index] = [:magenta]
46
+ end
47
+
48
+ extend Actions
49
+
50
+ register_action do |action|
51
+ action.name = 'help'
52
+ action.short = 'help'
53
+ action.usage = 'help'
54
+ action.proc = ->(terminal) {
55
+ HelpDecorator.new(terminal, self.actions).output
56
+ }
57
+ action.description = "Lists all commands"
58
+ end
59
+
60
+ register_action do |action|
61
+ action.name = 'generate'
62
+ action.short = 'g'
63
+ action.usage = 'g google'
64
+ action.proc = ->(terminal, key) {
65
+ ShowDecorator.new(terminal, FileHandler.generate(key)).output
66
+ }
67
+ action.description = "Generates a random password for a given key"
68
+ end
69
+
70
+ register_action do |action|
71
+ action.name = 'generate_short'
72
+ action.short = 'gs'
73
+ action.usage = 'gs [name]'
74
+ action.proc = ->(terminal, key) {
75
+ ShowDecorator.new(terminal, FileHandler.generate_short(key)).output
76
+ }
77
+ action.description = "Generates a random password but smaller so its easier to type into a phone or a legacy system"
78
+ end
79
+
80
+ register_action do |action|
81
+ action.name = 'remove'
82
+ action.short = 'rm'
83
+ action.usage = 'rm [name]'
84
+ action.confirm = true
85
+ action.proc = ->(terminal, key) {
86
+ ShowDecorator.new(terminal, FileHandler.remove(key)).output
87
+ }
88
+ action.description = "Removes and entry"
89
+ end
90
+
91
+ register_action do |action|
92
+ action.name = 'show'
93
+ action.short = 's'
94
+ action.usage = 's [name|index]'
95
+ action.proc = ->(terminal, key) {
96
+ entry = if key =~ /^\d+$/
97
+ FileHandler.all[key.to_i]
98
+ else
99
+ FileHandler.show key
100
+ end
101
+ ShowDecorator.new(terminal, entry).output
102
+ }
103
+ action.description = "Shows an entry"
104
+ end
105
+
106
+ register_action do |action|
107
+ action.name = 'encrypt'
108
+ action.short = 'e'
109
+ action.usage = '[name] << [password]'
110
+ action.proc = ->(terminal, key, password) {
111
+ ShowDecorator.new(terminal, FileHandler.encrypt(key, password)).output
112
+ }
113
+ action.description = "Encrypts a value"
114
+ end
115
+
116
+ register_action do |action|
117
+ action.name = 'rename'
118
+ action.short = 'mv'
119
+ action.usage = 'mv [name] [new name]'
120
+ action.proc = ->(terminal, old, new) {
121
+ ShowDecorator.new(terminal, FileHandler.rename(old, new)).output
122
+ }
123
+ action.description = "Rename an entry"
124
+ end
125
+
126
+ register_action do |action|
127
+ action.name = 'list'
128
+ action.short = 'ls'
129
+ action.usage = 'ls'
130
+ action.proc = ->(terminal) {
131
+ ListDecorator.new(terminal, FileHandler.all).output
132
+ }
133
+ action.description = "Lists all entries"
134
+ end
135
+
136
+ register_action do |action|
137
+ action.name = 'dump'
138
+ action.short = 'dump'
139
+ action.usage = 'dump'
140
+ action.proc = ->(terminal) {
141
+ DumpDecorator.new(terminal, FileHandler.all).output
142
+ }
143
+ action.description = "Dumps all entries including passwords"
144
+ end
145
+
146
+ def initialize(namespace, input = $stdin, output = $stdout, run_loop = true)
147
+ @input = input
148
+ @output = output
149
+ @run_loop = run_loop
150
+ @terminal = HighLine.new @input, @output
151
+
152
+ pass = @terminal.ask("Enter PEM pass phrase: ") { |q| q.echo = '*' }
153
+ @output.print "\n"
154
+
155
+ FileHandler.configure do |handler|
156
+ handler.namespace = namespace
157
+ handler.pass_phrase = pass
158
+ end
159
+ do_action if @run_loop
160
+ end
161
+
162
+ def self.help
163
+ print "\nactions:\n"
164
+ actions.each do |action|
165
+ @output.print " #{action.name}\n"
166
+ end
167
+ end
168
+
169
+ def confirm_action
170
+ @terminal.agree("<%= color('are you sure?', :confirm) %> ") { |q| q.default = "n" }
171
+ end
172
+
173
+ def do_action
174
+ input = @terminal.ask "uberpass:#{VERSION}> "
175
+ return if input.strip == 'exit'
176
+ @output.print "\n"
177
+ do_action_with_rescue input
178
+ @output.print "\n"
179
+ do_action if @run_loop
180
+ end
181
+
182
+ def do_action_with_rescue(input)
183
+ args = input.split(/ /).compact
184
+ if args[1] == '<'
185
+ action = fetch_action 'encrypt'
186
+ args.slice!(1)
187
+ else
188
+ action = fetch_action args.slice!(0)
189
+ end
190
+
191
+ if action.confirm && @run_loop
192
+ action.call(@terminal, *args) if confirm_action
193
+ else
194
+ action.call(@terminal, *args)
195
+ end
196
+ rescue MissingArgumentError, InvalidActionError, OpenSSL::PKey::RSAError => e
197
+ @terminal.say "<%= color('#{e}', :error) %>"
198
+ rescue FileHandler::ExistingEntryError => key
199
+ @terminal.say "<%= color('#{key} is already defined, try removing it first', :error) %>"
200
+ end
201
+
202
+ def fetch_action(key)
203
+ self.class.actions.each do |action|
204
+ return action if action.name == key || action.short == key
205
+ end
206
+ raise InvalidActionError, key
207
+ end
208
+
209
+ class ListDecorator
210
+ def initialize terminal, entries
211
+ @terminal, @entries = terminal, entries
212
+ end
213
+
214
+ def output
215
+ @entries.each_with_index do |entry, index|
216
+ key = entry.keys.first
217
+ output_entry key, entry[key], index
218
+ end
219
+ end
220
+
221
+ def output_entry(key, values, index)
222
+ out = "<%= color('#{values["created_at"].strftime("%d/%m/%Y")}', :date) %>"
223
+ out << " <%= color('[#{index}]', :index) %>"
224
+ out << " <%= color('#{key}', :name) %>"
225
+ @terminal.say out
226
+ end
227
+ end
228
+
229
+ class DumpDecorator < ListDecorator
230
+ def initialize terminal, entries
231
+ @terminal, @entries = terminal, entries
232
+ end
233
+
234
+ def output
235
+ @entries.each do |entry|
236
+ key = entry.keys.first
237
+ output_entry key, entry[key]
238
+ end
239
+ end
240
+
241
+ def output_entry(key, value)
242
+ out = "<%= color('#{key}', :name) %>"
243
+ out << " #{value["password"]}"
244
+ @terminal.say out
245
+ end
246
+ end
247
+
248
+ class ShowDecorator
249
+ def initialize terminal, entry
250
+ @terminal, @entry = terminal, entry
251
+ end
252
+
253
+ def output
254
+ key = @entry.keys.first
255
+ output_entry key, @entry[key]
256
+ end
257
+
258
+ def output_entry(key, values)
259
+ out = "<%= color('#{values["created_at"].strftime("%d/%m/%Y")}', :date) %>"
260
+ out << " <%= color('#{key}', :name) %>\n"
261
+ out << "<%= color('#{values["password"]}', :name) %>"
262
+
263
+ @terminal.say out
264
+ end
265
+ end
266
+
267
+ class HelpDecorator
268
+ def initialize terminal, actions
269
+ @terminal, @actions = terminal, actions
270
+ end
271
+
272
+ def output
273
+ @actions.each do |action|
274
+ next if action.name == 'help'
275
+ @terminal.say <<HELP
276
+ <%= color('#{action.name} - #{action.description}', BOLD) %>
277
+ usage: #{action.usage}
278
+
279
+ HELP
280
+ end
281
+ end
282
+ end
283
+ end
284
+ end
@@ -0,0 +1,18 @@
1
+ require 'openssl'
2
+
3
+ module Uberpass
4
+ class Decrypt
5
+ attr_reader :decrypted_data
6
+
7
+ def initialize(private_key, encrypted_data, encrypted_key, encrypted_iv, pass_phrase = nil)
8
+ key = OpenSSL::PKey::RSA.new(private_key, pass_phrase)
9
+ cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
10
+ cipher.decrypt
11
+ cipher.key = key.private_decrypt(encrypted_key)
12
+ cipher.iv = key.private_decrypt(encrypted_iv)
13
+
14
+ @decrypted_data = cipher.update(encrypted_data)
15
+ @decrypted_data << cipher.final
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ require 'openssl'
2
+
3
+ module Uberpass
4
+ class Encrypt
5
+ attr_reader :encrypted_data, :encrypted_key, :encrypted_iv
6
+
7
+ def initialize(public_key, decrypted_data, pass_phrase = nil)
8
+ key = OpenSSL::PKey::RSA.new(public_key, pass_phrase)
9
+ cipher = OpenSSL::Cipher::Cipher.new('aes-256-cbc')
10
+ cipher.encrypt
11
+ cipher.key = random_key = cipher.random_key
12
+ cipher.iv = random_iv = cipher.random_iv
13
+
14
+ @encrypted_data = cipher.update(decrypted_data)
15
+ @encrypted_data << cipher.final
16
+
17
+ @encrypted_key = key.public_encrypt(random_key)
18
+ @encrypted_iv = key.public_encrypt(random_iv)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,115 @@
1
+ require 'securerandom'
2
+
3
+ module Uberpass
4
+ class FileHandler
5
+ class ExistingEntryError < StandardError; end
6
+
7
+ class << self
8
+ attr_accessor :namespace, :pass_phrase
9
+
10
+ def configure
11
+ yield self
12
+ end
13
+
14
+ def name_spaced_file(file_name)
15
+ @namespace.nil? ? file_name : "#{file_name}_#{@namespace}"
16
+ end
17
+
18
+ def private_key_file
19
+ File.expand_path("~/.uberpass/private.pem")
20
+ end
21
+
22
+ def public_key_file
23
+ File.expand_path("~/.uberpass/public.pem")
24
+ end
25
+
26
+ def passwords_file
27
+ File.expand_path("~/.uberpass/#{name_spaced_file("passwords")}")
28
+ end
29
+
30
+ def key_file
31
+ File.expand_path("~/.uberpass/#{name_spaced_file("key")}")
32
+ end
33
+
34
+ def iv_file
35
+ File.expand_path("~/.uberpass/#{name_spaced_file("iv")}")
36
+ end
37
+
38
+ def write(encryptor)
39
+ File.open(passwords_file, "w") { |file|
40
+ file.write(encryptor.encrypted_data)
41
+ }
42
+ File.open(key_file, "w") { |file|
43
+ file.write(encryptor.encrypted_key)
44
+ }
45
+ File.open(iv_file, "w") { |file|
46
+ file.write(encryptor.encrypted_iv)
47
+ }
48
+ end
49
+
50
+ def decrypted_passwords
51
+ if File.exists?(passwords_file)
52
+ YAML::load(
53
+ Decrypt.new(
54
+ File.read(private_key_file),
55
+ File.read(passwords_file),
56
+ File.read(key_file),
57
+ File.read(iv_file),
58
+ pass_phrase
59
+ ).decrypted_data
60
+ )
61
+ else
62
+ {}
63
+ end
64
+ end
65
+
66
+ def show(key)
67
+ Hash[*[key, decrypted_passwords[key]]]
68
+ end
69
+
70
+ def all
71
+ decrypted_passwords.map do |entry|
72
+ Hash[*entry]
73
+ end
74
+ end
75
+
76
+ def generate_short(key)
77
+ encrypt key, SecureRandom.urlsafe_base64(8)
78
+ end
79
+
80
+ def generate(key)
81
+ encrypt key, SecureRandom.urlsafe_base64(24)
82
+ end
83
+
84
+ def encrypt(key, password)
85
+ passwords = decrypted_passwords
86
+ raise ExistingEntryError, key unless passwords[key].nil?
87
+ entry = passwords[key] = {
88
+ "password" => password,
89
+ "created_at" => Time.now
90
+ }
91
+ encryptor = Encrypt.new(File.read(public_key_file), passwords.to_yaml, pass_phrase)
92
+ write(encryptor)
93
+ Hash[*[key, entry]]
94
+ end
95
+
96
+ def rename(old, new)
97
+ passwords = decrypted_passwords
98
+ raise ExistingEntryError, new unless passwords[new].nil?
99
+ entry = passwords.delete old
100
+ passwords[new] = entry
101
+ encryptor = Encrypt.new(File.read(public_key_file), passwords.to_yaml)
102
+ write(encryptor)
103
+ Hash[*[new, entry]]
104
+ end
105
+
106
+ def remove(key)
107
+ passwords = decrypted_passwords
108
+ entry = passwords.delete key
109
+ encryptor = Encrypt.new(File.read(public_key_file), passwords.to_yaml)
110
+ write(encryptor)
111
+ Hash[*[key, entry]]
112
+ end
113
+ end
114
+ end
115
+ end
@@ -1,3 +1,3 @@
1
1
  module Uberpass
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -0,0 +1,58 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $password = File.read(File.join(File.dirname(__FILE__), '..', 'password.txt')).strip
3
+ $password.freeze
4
+
5
+ require 'uberpass'
6
+
7
+ input = StringIO.new
8
+ output = StringIO.new
9
+
10
+ input << $password
11
+ input.rewind
12
+
13
+ uberpass = Uberpass::CLI.new 'test', input, output, false
14
+
15
+ input.truncate input.rewind
16
+
17
+ puts output.string
18
+ output.truncate output.rewind
19
+
20
+ input << 'ls'
21
+ input.rewind
22
+ uberpass.do_action
23
+ input.truncate input.rewind
24
+
25
+ puts output.string
26
+ output.truncate output.rewind
27
+
28
+ input << 'dump'
29
+ input.rewind
30
+ uberpass.do_action
31
+ input.truncate input.rewind
32
+
33
+ puts output.string
34
+ output.truncate output.rewind
35
+
36
+ input << 'g cia'
37
+ input.rewind
38
+ uberpass.do_action
39
+ input.truncate input.rewind
40
+
41
+ puts output.string
42
+ output.truncate output.rewind
43
+
44
+ input << 's cia'
45
+ input.rewind
46
+ uberpass.do_action
47
+ input.truncate input.rewind
48
+
49
+ puts output.string
50
+ output.truncate output.rewind
51
+
52
+ input << 'help'
53
+ input.rewind
54
+ uberpass.do_action
55
+ input.truncate input.rewind
56
+
57
+ puts output.string
58
+ output.truncate output.rewind
@@ -0,0 +1,119 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $password = File.read(File.join(File.dirname(__FILE__), '..', 'password.txt')).strip
3
+ $password.freeze
4
+
5
+ require 'minitest/spec'
6
+ require 'minitest/autorun'
7
+ require 'turn/autorun'
8
+ require 'uberpass'
9
+
10
+ describe Uberpass do
11
+ before do
12
+ @input = StringIO.new
13
+ @output = StringIO.new
14
+
15
+ @input << $password
16
+ @input.rewind
17
+
18
+ @uberpass = Uberpass::CLI.new 'test', @input, @output, false
19
+
20
+ @input.truncate(@input.rewind)
21
+
22
+ Uberpass::FileHandler.all.each do |entry|
23
+ Uberpass::FileHandler.remove entry.keys.first
24
+ end
25
+
26
+ Uberpass::FileHandler.generate 'twitter'
27
+ Uberpass::FileHandler.generate 'facebook'
28
+ end
29
+
30
+ it "should ask and memorise the password" do
31
+ prompt = "Enter PEM pass phrase: #{$password.gsub(/\w/, '*')}\n\n"
32
+
33
+ assert_equal prompt, @output.string
34
+ assert_equal $password, Uberpass::FileHandler.pass_phrase
35
+ end
36
+
37
+ it "should list entries" do
38
+ @output.truncate(@output.rewind)
39
+ @input << 'ls'
40
+ @input.rewind
41
+
42
+ @uberpass.do_action
43
+
44
+ assert_match /facebook/, @output.string
45
+ assert_match /twitter/, @output.string
46
+ assert_match Time.now.strftime("%d/%m/%Y"), @output.string
47
+ end
48
+
49
+ it "should raise and catch argument error" do
50
+ @output.truncate(@output.rewind)
51
+ @input << 'wadyawant'
52
+ @input.rewind
53
+
54
+ @uberpass.do_action
55
+
56
+ assert_match /is not a uberpass command/, @output.string
57
+ assert_match /'wadyawant'/, @output.string
58
+ end
59
+
60
+ it "should confirm deletion of password" do
61
+ Uberpass::FileHandler.generate 'linkedin'
62
+
63
+ @output.truncate(@output.rewind)
64
+ @input << 'rm linkedin'
65
+ @input.rewind
66
+
67
+ @uberpass.do_action
68
+
69
+ @input.truncate(@input.rewind)
70
+ @input << 'yes'
71
+ @input.rewind
72
+
73
+ @uberpass.confirm_action
74
+
75
+ assert_match /are you sure\?/, @output.string
76
+ assert_match /linkedin/, @output.string
77
+ assert_match Time.now.strftime("%d/%m/%Y"), @output.string
78
+ end
79
+
80
+ it "should encrypt an existing password with <" do
81
+ @output.truncate(@output.rewind)
82
+ @input << 'google < xxx'
83
+ @input.rewind
84
+
85
+ @uberpass.do_action
86
+
87
+ password = Uberpass::FileHandler.show 'google'
88
+
89
+ refute_nil password['google']['password']
90
+ end
91
+
92
+ it "should encrypt an existing password with <" do
93
+ @output.truncate(@output.rewind)
94
+ @input << 'e foursquare xxx'
95
+ @input.rewind
96
+
97
+ @uberpass.do_action
98
+
99
+ password = Uberpass::FileHandler.show 'foursquare'
100
+
101
+ refute_nil password['foursquare']['password']
102
+ end
103
+
104
+ it "should rename a key" do
105
+ Uberpass::FileHandler.generate 'tumbler'
106
+
107
+ @output.truncate(@output.rewind)
108
+ @input << 'mv tumbler tumblr'
109
+ @input.rewind
110
+
111
+ @uberpass.do_action
112
+
113
+ password = Uberpass::FileHandler.show 'tumbler'
114
+ assert_nil password['tumbler']
115
+
116
+ password = Uberpass::FileHandler.show 'tumblr'
117
+ refute_nil password['tumblr']
118
+ end
119
+ end
data/uberpass.gemspec CHANGED
@@ -13,7 +13,9 @@ Gem::Specification.new do |s|
13
13
 
14
14
  s.rubyforge_project = "uberpass"
15
15
 
16
+ s.add_runtime_dependency "highline", "1.6.15"
16
17
  s.add_development_dependency "rake"
18
+ s.add_development_dependency "turn", "0.9.6"
17
19
 
18
20
  s.files = `git ls-files`.split("\n")
19
21
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: uberpass
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,19 +9,56 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-09 00:00:00.000000000 Z
12
+ date: 2013-03-03 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: highline
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - '='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.6.15
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - '='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.6.15
14
30
  - !ruby/object:Gem::Dependency
15
31
  name: rake
16
- requirement: &70366937140340 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
17
41
  none: false
18
42
  requirements:
19
43
  - - ! '>='
20
44
  - !ruby/object:Gem::Version
21
45
  version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: turn
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - '='
52
+ - !ruby/object:Gem::Version
53
+ version: 0.9.6
22
54
  type: :development
23
55
  prerelease: false
24
- version_requirements: *70366937140340
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.9.6
25
62
  description: uses open ssl and a cli to generate and retrieve passwords
26
63
  email:
27
64
  - rufuspost@gmail.com
@@ -36,7 +73,13 @@ files:
36
73
  - Rakefile
37
74
  - bin/uberpass
38
75
  - lib/uberpass.rb
76
+ - lib/uberpass/cli.rb
77
+ - lib/uberpass/decrypt.rb
78
+ - lib/uberpass/encrypt.rb
79
+ - lib/uberpass/file_handler.rb
39
80
  - lib/uberpass/version.rb
81
+ - spec/uberpass_output.rb
82
+ - spec/uberpass_spec.rb
40
83
  - uberpass.gemspec
41
84
  homepage: ''
42
85
  licenses: []
@@ -50,22 +93,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
50
93
  - - ! '>='
51
94
  - !ruby/object:Gem::Version
52
95
  version: '0'
53
- segments:
54
- - 0
55
- hash: -4545846251252195404
56
96
  required_rubygems_version: !ruby/object:Gem::Requirement
57
97
  none: false
58
98
  requirements:
59
99
  - - ! '>='
60
100
  - !ruby/object:Gem::Version
61
101
  version: '0'
62
- segments:
63
- - 0
64
- hash: -4545846251252195404
65
102
  requirements: []
66
103
  rubyforge_project: uberpass
67
- rubygems_version: 1.8.11
104
+ rubygems_version: 1.8.23
68
105
  signing_key:
69
106
  specification_version: 3
70
107
  summary: command line key chain
71
- test_files: []
108
+ test_files:
109
+ - spec/uberpass_output.rb
110
+ - spec/uberpass_spec.rb
111
+ has_rdoc: