uberpass 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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: