rubeepass 0.4.2 → 0.5.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/bin/rpass +140 -121
- data/lib/rubeepass/entry.rb +26 -7
- data/lib/rubeepass/error/file_not_found.rb +5 -0
- data/lib/rubeepass/error/file_not_readable.rb +5 -0
- data/lib/rubeepass/error/{invalid_gzip_error.rb → invalid_gzip.rb} +1 -1
- data/lib/rubeepass/error/{invalid_header_error.rb → invalid_header.rb} +1 -1
- data/lib/rubeepass/error/{invalid_magic_error.rb → invalid_magic.rb} +1 -1
- data/lib/rubeepass/error/{invalid_password_error.rb → invalid_password.rb} +1 -1
- data/lib/rubeepass/error/{invalid_protected_data_error.rb → invalid_protected_data.rb} +1 -1
- data/lib/rubeepass/error/{invalid_protected_stream_key_error.rb → invalid_protected_stream_key.rb} +1 -1
- data/lib/rubeepass/error/{invalid_version_error.rb → invalid_version.rb} +1 -1
- data/lib/rubeepass/error/{invalid_xml_error.rb → invalid_xml.rb} +1 -1
- data/lib/rubeepass/error/{not_aes_error.rb → not_aes.rb} +1 -1
- data/lib/rubeepass/error/{not_salsa20_error.rb → not_salsa20.rb} +1 -1
- data/lib/rubeepass/error.rb +12 -10
- data/lib/rubeepass/group.rb +24 -7
- data/lib/rubeepass/wish/cd_wish.rb +6 -1
- data/lib/rubeepass/wish/copy_wish.rb +0 -1
- data/lib/rubeepass/wish/echo_wish.rb +0 -1
- data/lib/rubeepass/wish/ls_wish.rb +0 -1
- data/lib/rubeepass/wish/show_all_wish.rb +0 -1
- data/lib/rubeepass/wish/show_wish.rb +0 -1
- data/lib/rubeepass.rb +43 -30
- metadata +44 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27da21673c45cfb2ab29bb1c984f477ea16036d6
|
4
|
+
data.tar.gz: 3785cf861668b77aea2d275248f4747e85425c2a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 301723a1764cb1f6698e912069e39fb65f1577dd94ad0dbe3e4ed329c495f6bb3110ceea15e0ce6c1ac56bc91ef1758a642742c9d35ce8857d9368f29b79890e
|
7
|
+
data.tar.gz: 9edb83c2c117297bd7d731fd610fb81c7606fa9ded5d0deefe046f24408d6652bc99547aa560c41fb027225707f912bd610c72f84c187901e9c19e3bdac4b71a
|
data/bin/rpass
CHANGED
@@ -3,37 +3,57 @@
|
|
3
3
|
require "colorize"
|
4
4
|
require "djinni"
|
5
5
|
require "io/console"
|
6
|
-
require "
|
6
|
+
require "json_config"
|
7
7
|
require "optparse"
|
8
|
-
require "pathname"
|
9
8
|
require "rubeepass"
|
10
9
|
|
11
|
-
class
|
10
|
+
class RubeePassExit
|
12
11
|
GOOD = 0
|
13
12
|
INVALID_OPTION = 1
|
14
13
|
INVALID_ARGUMENT = 2
|
15
14
|
MISSING_ARGUMENT = 3
|
16
15
|
EXTRA_ARGUMENTS = 4
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
EXCEPTION = 5
|
17
|
+
end
|
18
|
+
|
19
|
+
class RubeePassConfig < JSONConfig
|
20
|
+
def default_config
|
21
|
+
set("last_kdbx", nil)
|
22
|
+
set("last_keyfile", nil)
|
23
|
+
set("timeout", 10)
|
24
|
+
end
|
25
|
+
|
26
|
+
def last_kdbx(kdbx = nil)
|
27
|
+
set("last_kdbx", kdbx.to_s) if (kdbx)
|
28
|
+
kdbx = get("last_kdbx")
|
29
|
+
return nil if (kdbx.nil? || kdbx.empty?)
|
30
|
+
return kdbx
|
31
|
+
end
|
32
|
+
|
33
|
+
def last_keyfile(keyfile = nil)
|
34
|
+
set("last_keyfile", keyfile.to_s) if (keyfile)
|
35
|
+
keyfile = get("last_keyfile")
|
36
|
+
return nil if (keyfile.nil? || keyfile.empty?)
|
37
|
+
return keyfile
|
38
|
+
end
|
39
|
+
|
40
|
+
def timeout(t = nil)
|
41
|
+
set("timeout", t) if (t)
|
42
|
+
t = get("timeout")
|
43
|
+
case t
|
44
|
+
when /[0-9]+/
|
45
|
+
return t.to_i
|
46
|
+
else
|
47
|
+
return nil
|
48
|
+
end
|
49
|
+
end
|
22
50
|
end
|
23
51
|
|
24
52
|
def get_password
|
25
53
|
print "Enter password: "
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
return passwd.chomp
|
30
|
-
rescue Interrupt => e
|
31
|
-
puts
|
32
|
-
exit RPassExit::GOOD
|
33
|
-
rescue
|
34
|
-
puts
|
35
|
-
exit RPassExit::KDBX_NOT_OPENED
|
36
|
-
end
|
54
|
+
passwd = STDIN.noecho(&:gets)
|
55
|
+
puts
|
56
|
+
return passwd.chomp
|
37
57
|
end
|
38
58
|
|
39
59
|
def parse(args)
|
@@ -44,6 +64,7 @@ def parse(args)
|
|
44
64
|
options["password"] = nil
|
45
65
|
options["keyfile"] = nil
|
46
66
|
options["timeout"] = nil
|
67
|
+
options["verbose"] = false
|
47
68
|
|
48
69
|
parser = OptionParser.new do |opts|
|
49
70
|
opts.banner = "Usage: #{File.basename($0)} [OPTIONS] [kdbx]"
|
@@ -75,7 +96,7 @@ def parse(args)
|
|
75
96
|
|
76
97
|
opts.on("-h", "--help", "Display this help message") do
|
77
98
|
puts opts
|
78
|
-
exit
|
99
|
+
exit RubeePassExit::GOOD
|
79
100
|
end
|
80
101
|
|
81
102
|
opts.on(
|
@@ -83,7 +104,11 @@ def parse(args)
|
|
83
104
|
"--keyfile=KEYFILE",
|
84
105
|
"Use specified keyfile"
|
85
106
|
) do |keyfile|
|
86
|
-
options["keyfile"] =
|
107
|
+
options["keyfile"] = keyfile
|
108
|
+
end
|
109
|
+
|
110
|
+
opts.on("--nocolor", "Disable colorized output") do
|
111
|
+
String.disable_colorization = true
|
87
112
|
end
|
88
113
|
|
89
114
|
opts.on(
|
@@ -98,11 +123,19 @@ def parse(args)
|
|
98
123
|
options["timeout"] = t.to_i
|
99
124
|
end
|
100
125
|
|
126
|
+
opts.on(
|
127
|
+
"-v",
|
128
|
+
"--verbose",
|
129
|
+
"Show backtrace when error occurs"
|
130
|
+
) do
|
131
|
+
options["verbose"] = true
|
132
|
+
end
|
133
|
+
|
101
134
|
opts.on(
|
102
135
|
"",
|
103
136
|
"FORMATS",
|
104
|
-
"
|
105
|
-
"
|
137
|
+
" gzip",
|
138
|
+
" xml"
|
106
139
|
)
|
107
140
|
end
|
108
141
|
|
@@ -111,109 +144,63 @@ def parse(args)
|
|
111
144
|
rescue OptionParser::InvalidOption => e
|
112
145
|
puts e.message
|
113
146
|
puts parser
|
114
|
-
exit
|
147
|
+
exit RubeePassExit::INVALID_OPTION
|
115
148
|
rescue OptionParser::InvalidArgument => e
|
116
149
|
puts e.message
|
117
150
|
puts parser
|
118
|
-
exit
|
151
|
+
exit RubeePassExit::INVALID_ARGUMENT
|
119
152
|
rescue OptionParser::MissingArgument => e
|
120
153
|
puts e.message
|
121
154
|
puts parser
|
122
|
-
exit
|
155
|
+
exit RubeePassExit::MISSING_ARGUMENT
|
123
156
|
end
|
124
157
|
|
125
158
|
if (args.length > 1)
|
126
159
|
puts parser
|
127
|
-
exit
|
160
|
+
exit RubeePassExit::EXTRA_ARGUMENTS
|
128
161
|
end
|
129
162
|
|
130
163
|
# Read config
|
131
|
-
rc =
|
164
|
+
rc = RubeePassConfig.new("~/.rpassrc")
|
132
165
|
|
133
166
|
# Determine kdbx and keyfile
|
134
167
|
if (args.length == 1)
|
135
168
|
# Use specified kdbx (and keyfile if specified)
|
136
|
-
options["kdbx"] =
|
169
|
+
options["kdbx"] = args[0]
|
137
170
|
else
|
138
171
|
# Use kdbx from config if stored
|
139
|
-
if (rc
|
140
|
-
options["kdbx"] =
|
141
|
-
rc["last_kdbx"]
|
142
|
-
).expand_path
|
172
|
+
if (rc.last_kdbx)
|
173
|
+
options["kdbx"] = rc.last_kdbx
|
143
174
|
end
|
144
175
|
|
145
176
|
# Use keyfile from config if stored and not specified already
|
146
177
|
if (options["keyfile"].nil?)
|
147
|
-
if (rc
|
148
|
-
options["keyfile"] =
|
149
|
-
rc["last_keyfile"]
|
150
|
-
).expand_path
|
178
|
+
if (rc.last_keyfile)
|
179
|
+
options["keyfile"] = rc.last_keyfile
|
151
180
|
end
|
152
181
|
end
|
153
182
|
end
|
154
183
|
|
155
184
|
# Determine timeout
|
156
185
|
if (options["timeout"].nil?)
|
157
|
-
|
158
|
-
|
159
|
-
else
|
160
|
-
options["timeout"] = 7
|
161
|
-
end
|
186
|
+
options["timeout"] = 10
|
187
|
+
options["timeout"] = rc.timeout if (rc.timeout)
|
162
188
|
end
|
163
189
|
|
164
190
|
# Throw error if kdbx not specified or in config
|
165
191
|
if (options["kdbx"].nil?)
|
166
192
|
puts parser
|
167
|
-
exit
|
168
|
-
end
|
169
|
-
|
170
|
-
# Throw error if kdbx does not exist or is not readable
|
171
|
-
if (!options["kdbx"].exist?)
|
172
|
-
puts parser
|
173
|
-
exit RPassExit::KDBX_NOT_FOUND
|
174
|
-
elsif (!options["kdbx"].readable?)
|
175
|
-
puts parser
|
176
|
-
exit RPassExit::KDBX_NOT_READABLE
|
177
|
-
end
|
178
|
-
|
179
|
-
# Throw error if keyfile does not exist or is not readable
|
180
|
-
if (options["keyfile"])
|
181
|
-
if (!options["keyfile"].exist?)
|
182
|
-
puts parser
|
183
|
-
exit RPassExit::KEYFILE_NOT_FOUND
|
184
|
-
elsif (!options["keyfile"].readable?)
|
185
|
-
puts parser
|
186
|
-
exit RPassExit::KEYFILE_NOT_READABLE
|
187
|
-
end
|
193
|
+
exit RubeePassExit::MISSING_ARGUMENT
|
188
194
|
end
|
189
195
|
|
190
196
|
# Store data in config
|
191
|
-
rc
|
192
|
-
rc
|
193
|
-
rc
|
194
|
-
write_rpassrc(rc)
|
197
|
+
rc.last_kdbx(options["kdbx"])
|
198
|
+
rc.last_keyfile(options["keyfile"])
|
199
|
+
rc.timeout(options["timeout"])
|
195
200
|
|
196
201
|
return options
|
197
202
|
end
|
198
203
|
|
199
|
-
def read_rpassrc
|
200
|
-
default = Hash.new
|
201
|
-
default["last_kdbx"] = nil
|
202
|
-
default["last_keyfile"] = nil
|
203
|
-
default["timeout"] = 7
|
204
|
-
|
205
|
-
rc_file = Pathname.new("~/.rpassrc").expand_path
|
206
|
-
return default if (!rc_file.exist? && !rc_file.symlink?)
|
207
|
-
return JSON.parse(File.read(rc_file))
|
208
|
-
end
|
209
|
-
|
210
|
-
def write_rpassrc(rc)
|
211
|
-
rc_file = Pathname.new("~/.rpassrc").expand_path
|
212
|
-
File.open(rc_file, "w") do |f|
|
213
|
-
f.write(JSON.pretty_generate(rc))
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
204
|
options = parse(ARGV)
|
218
205
|
|
219
206
|
kdbx = options["kdbx"]
|
@@ -221,39 +208,41 @@ password = options["password"] if (options["password"])
|
|
221
208
|
password = get_password if (options["password"].nil?)
|
222
209
|
keyfile = options["keyfile"]
|
223
210
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
211
|
+
begin
|
212
|
+
keepass = RubeePass.new(
|
213
|
+
kdbx,
|
214
|
+
password,
|
215
|
+
keyfile,
|
216
|
+
!String.disable_colorization
|
217
|
+
)
|
218
|
+
|
219
|
+
loop do
|
220
|
+
begin
|
221
|
+
if (options["export_file"])
|
222
|
+
keepass.export(
|
223
|
+
options["export_file"],
|
224
|
+
options["export_format"]
|
225
|
+
)
|
226
|
+
exit RubeePassExit::GOOD
|
227
|
+
else
|
228
|
+
keepass.open
|
229
|
+
end
|
230
|
+
break
|
231
|
+
rescue RubeePass::Error::InvalidPassword => e
|
232
|
+
puts e.message
|
233
|
+
password = get_password
|
234
|
+
keepass = RubeePass.new(
|
235
|
+
kdbx,
|
236
|
+
password,
|
237
|
+
keyfile,
|
238
|
+
!String.disable_colorization
|
239
|
+
)
|
240
|
+
end
|
236
241
|
end
|
237
|
-
exit RPassExit::GOOD
|
238
|
-
end
|
239
242
|
|
240
|
-
|
241
|
-
|
242
|
-
keepass.open
|
243
|
-
break
|
244
|
-
rescue RubeePass::Error::InvalidPasswordError => e
|
245
|
-
puts e.message
|
246
|
-
password = get_password
|
247
|
-
keepass = RubeePass.new(kdbx, password, keyfile)
|
248
|
-
rescue RubeePass::Error => e
|
249
|
-
puts e.message
|
250
|
-
exit RPassExit::KDBX_NOT_OPENED
|
251
|
-
end
|
252
|
-
end
|
243
|
+
djinni = Djinni.new
|
244
|
+
djinni.load_wishes("#{File.dirname(__FILE__)}/../lib/rubeepass/wish")
|
253
245
|
|
254
|
-
djinni = Djinni.new
|
255
|
-
djinni.load_wishes("#{File.dirname(__FILE__)}/../lib/rubeepass/wish")
|
256
|
-
begin
|
257
246
|
if (options["command"])
|
258
247
|
djinni.grant_wish(
|
259
248
|
"#{options["command"].chomp}\n",
|
@@ -269,14 +258,44 @@ begin
|
|
269
258
|
{
|
270
259
|
"keepass" => keepass,
|
271
260
|
"cwd" => keepass.db,
|
272
|
-
"clipboard_timeout" => options["timeout"]
|
261
|
+
"clipboard_timeout" => options["timeout"],
|
262
|
+
"prompt_color" => "light_white"
|
273
263
|
},
|
274
|
-
"rpass:/> ".
|
264
|
+
"rpass:/> ".light_white
|
275
265
|
)
|
276
266
|
end
|
277
|
-
|
267
|
+
rescue SystemExit
|
268
|
+
# Quit from djinni
|
269
|
+
# Exit gracefully
|
270
|
+
rescue Interrupt
|
271
|
+
# ^C
|
272
|
+
# Exit gracefully
|
273
|
+
rescue Errno::EPIPE
|
274
|
+
# Do nothing. This can happen if piping to another program such as
|
275
|
+
# less. Usually if less is closed before we're done with STDOUT.
|
276
|
+
rescue RubeePass::Error => e
|
277
|
+
puts e.message
|
278
|
+
exit RubeePassExit::EXCEPTION
|
279
|
+
rescue Exception => e
|
280
|
+
$stderr.puts "Oops! Looks like an error has occured! If the " \
|
281
|
+
"error persists, file a bug at:".word_wrap
|
282
|
+
$stderr.puts
|
283
|
+
$stderr.puts " https://gitlab.com/mjwhitta/rubeepass/issues"
|
284
|
+
$stderr.puts
|
285
|
+
$stderr.puts "Maybe the message below will help. If not, you " \
|
286
|
+
"can use the --verbose flag to get a backtrace.".word_wrap
|
287
|
+
|
288
|
+
$stderr.puts e.message.white.on_red
|
289
|
+
if (options["verbose"])
|
290
|
+
e.backtrace.each do |line|
|
291
|
+
$stderr.puts line.light_yellow
|
292
|
+
end
|
293
|
+
end
|
294
|
+
exit RubeePassExit::EXCEPTION
|
278
295
|
ensure
|
279
|
-
keepass
|
280
|
-
|
296
|
+
if (keepass)
|
297
|
+
keepass.clear_clipboard
|
298
|
+
keepass.wait_to_exit
|
299
|
+
end
|
281
300
|
end
|
282
|
-
exit
|
301
|
+
exit RubeePassExit::GOOD
|
data/lib/rubeepass/entry.rb
CHANGED
@@ -22,14 +22,30 @@ class RubeePass::Entry
|
|
22
22
|
return (self.title.downcase <=> other.title.downcase)
|
23
23
|
end
|
24
24
|
|
25
|
+
def colorize_password(passwd)
|
26
|
+
return passwd if (!@colorize)
|
27
|
+
return passwd.light_red
|
28
|
+
end
|
29
|
+
private :colorize_password
|
30
|
+
|
31
|
+
def colorize_title(title)
|
32
|
+
return title if (!@colorize)
|
33
|
+
return title.light_green
|
34
|
+
end
|
35
|
+
private :colorize_title
|
36
|
+
|
25
37
|
def details(level = 0, show_passwd = false)
|
26
38
|
lvl = Array.new(level, " ").join
|
27
39
|
|
28
40
|
ret = Array.new
|
29
|
-
ret.push("#{lvl}Title : #{@title}"
|
41
|
+
ret.push(colorize_title("#{lvl}Title : #{@title}"))
|
30
42
|
# ret.push("#{lvl}UUID : #{@uuid}")
|
31
43
|
ret.push("#{lvl}Username : #{@username}")
|
32
|
-
|
44
|
+
if (show_passwd)
|
45
|
+
ret.push(
|
46
|
+
colorize_password("#{lvl}Password : #{password}")
|
47
|
+
)
|
48
|
+
end
|
33
49
|
ret.push("#{lvl}Url : #{@url}")
|
34
50
|
|
35
51
|
first = true
|
@@ -45,7 +61,7 @@ class RubeePass::Entry
|
|
45
61
|
return ret.join("\n")
|
46
62
|
end
|
47
63
|
|
48
|
-
def self.from_xml(keepass, parent, xml)
|
64
|
+
def self.from_xml(keepass, parent, xml, colorize = false)
|
49
65
|
notes = ""
|
50
66
|
password = ""
|
51
67
|
title = ""
|
@@ -95,7 +111,8 @@ class RubeePass::Entry
|
|
95
111
|
title,
|
96
112
|
url,
|
97
113
|
username,
|
98
|
-
uuid
|
114
|
+
uuid,
|
115
|
+
colorize
|
99
116
|
)
|
100
117
|
end
|
101
118
|
|
@@ -105,9 +122,9 @@ class RubeePass::Entry
|
|
105
122
|
begin
|
106
123
|
data = base64.unpack("m*")[0].fix
|
107
124
|
rescue ArgumentError => e
|
108
|
-
raise Error::
|
125
|
+
raise Error::InvalidProtectedData.new
|
109
126
|
end
|
110
|
-
raise Error::
|
127
|
+
raise Error::InvalidProtectedData.new if (data.nil?)
|
111
128
|
|
112
129
|
return keepass.protected_decryptor.add_to_stream(data)
|
113
130
|
end
|
@@ -120,8 +137,10 @@ class RubeePass::Entry
|
|
120
137
|
title,
|
121
138
|
url,
|
122
139
|
username,
|
123
|
-
uuid
|
140
|
+
uuid,
|
141
|
+
colorize = false
|
124
142
|
)
|
143
|
+
@colorize = colorize
|
125
144
|
@group = group
|
126
145
|
@keepass = keepass
|
127
146
|
@notes = notes
|
data/lib/rubeepass/error.rb
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
class RubeePass::Error < RuntimeError
|
2
2
|
end
|
3
3
|
|
4
|
-
require "rubeepass/error/
|
5
|
-
require "rubeepass/error/
|
6
|
-
require "rubeepass/error/
|
7
|
-
require "rubeepass/error/
|
8
|
-
require "rubeepass/error/
|
9
|
-
require "rubeepass/error/
|
10
|
-
require "rubeepass/error/
|
11
|
-
require "rubeepass/error/
|
12
|
-
require "rubeepass/error/
|
13
|
-
require "rubeepass/error/
|
4
|
+
require "rubeepass/error/file_not_found"
|
5
|
+
require "rubeepass/error/file_not_readable"
|
6
|
+
require "rubeepass/error/invalid_gzip"
|
7
|
+
require "rubeepass/error/invalid_header"
|
8
|
+
require "rubeepass/error/invalid_magic"
|
9
|
+
require "rubeepass/error/invalid_password"
|
10
|
+
require "rubeepass/error/invalid_protected_data"
|
11
|
+
require "rubeepass/error/invalid_protected_stream_key"
|
12
|
+
require "rubeepass/error/invalid_version"
|
13
|
+
require "rubeepass/error/invalid_xml"
|
14
|
+
require "rubeepass/error/not_aes"
|
15
|
+
require "rubeepass/error/not_salsa20"
|
data/lib/rubeepass/group.rb
CHANGED
@@ -20,12 +20,18 @@ class RubeePass::Group
|
|
20
20
|
return (self.name.downcase <=> other.name.downcase)
|
21
21
|
end
|
22
22
|
|
23
|
+
def colorize_header(header)
|
24
|
+
return header if (!@colorize)
|
25
|
+
return header.light_blue
|
26
|
+
end
|
27
|
+
private :colorize_header
|
28
|
+
|
23
29
|
def details(level = 0, show_passwd = false)
|
24
30
|
out = Array.new
|
25
31
|
lvl = Array.new(level, " ").join
|
26
32
|
|
27
|
-
group_details = [
|
28
|
-
group_details = [
|
33
|
+
group_details = [ colorize_header(@path) ] if (level == 0)
|
34
|
+
group_details = [ colorize_header(@name) ] if (level != 0)
|
29
35
|
|
30
36
|
group_details.each do |line|
|
31
37
|
out.push("#{lvl}#{line}")
|
@@ -64,7 +70,7 @@ class RubeePass::Group
|
|
64
70
|
return cwd
|
65
71
|
end
|
66
72
|
|
67
|
-
def self.from_xml(keepass, parent, xml)
|
73
|
+
def self.from_xml(keepass, parent, xml, colorize = false)
|
68
74
|
name = xml.elements["Name"].text if (parent)
|
69
75
|
name = "" if (name.nil?)
|
70
76
|
name = "/" if (parent.nil?)
|
@@ -82,7 +88,8 @@ class RubeePass::Group
|
|
82
88
|
keepass,
|
83
89
|
name,
|
84
90
|
notes,
|
85
|
-
uuid
|
91
|
+
uuid,
|
92
|
+
colorize
|
86
93
|
)
|
87
94
|
|
88
95
|
if (xml.elements["Entry"])
|
@@ -90,7 +97,8 @@ class RubeePass::Group
|
|
90
97
|
entry = RubeePass::Entry.from_xml(
|
91
98
|
keepass,
|
92
99
|
group,
|
93
|
-
entry_xml
|
100
|
+
entry_xml,
|
101
|
+
colorize
|
94
102
|
)
|
95
103
|
group.entries[entry.title] = entry
|
96
104
|
end
|
@@ -101,7 +109,8 @@ class RubeePass::Group
|
|
101
109
|
child = RubeePass::Group.from_xml(
|
102
110
|
keepass,
|
103
111
|
group,
|
104
|
-
group_xml
|
112
|
+
group_xml,
|
113
|
+
colorize
|
105
114
|
)
|
106
115
|
group.groups[child.name] = child
|
107
116
|
end
|
@@ -161,7 +170,15 @@ class RubeePass::Group
|
|
161
170
|
return false
|
162
171
|
end
|
163
172
|
|
164
|
-
def initialize(
|
173
|
+
def initialize(
|
174
|
+
group,
|
175
|
+
keepass,
|
176
|
+
name,
|
177
|
+
notes,
|
178
|
+
uuid,
|
179
|
+
colorize = false
|
180
|
+
)
|
181
|
+
@colorize = colorize
|
165
182
|
@entries = Hash.new
|
166
183
|
@group = group
|
167
184
|
@groups = Hash.new
|
@@ -13,13 +13,18 @@ class CDWish < Djinni::Wish
|
|
13
13
|
def execute(args, djinni_env = {})
|
14
14
|
keepass = djinni_env["keepass"]
|
15
15
|
cwd = djinni_env["cwd"]
|
16
|
+
prompt_color = djinni_env["prompt_color"]
|
16
17
|
|
17
18
|
args = keepass.absolute_path(args, cwd.path)
|
18
19
|
new_cwd = keepass.find_group(args)
|
19
20
|
|
20
21
|
if (new_cwd)
|
21
22
|
djinni_env["cwd"] = new_cwd
|
22
|
-
|
23
|
+
if (prompt_color)
|
24
|
+
prompt = "rpass:#{new_cwd.name}> ".send(prompt_color)
|
25
|
+
else
|
26
|
+
prompt = "rpass:#{new_cwd.name}> "
|
27
|
+
end
|
23
28
|
djinni_env["djinni_prompt"] = prompt
|
24
29
|
else
|
25
30
|
puts "Group \"#{args}\" doesn't exist!"
|
data/lib/rubeepass.rb
CHANGED
@@ -2,6 +2,7 @@ require "cgi"
|
|
2
2
|
require "digest"
|
3
3
|
require "openssl"
|
4
4
|
require "os"
|
5
|
+
require "pathname"
|
5
6
|
require "rexml/document"
|
6
7
|
require "scoobydoo"
|
7
8
|
require "shellwords"
|
@@ -173,10 +174,28 @@ class RubeePass
|
|
173
174
|
return @db.fuzzy_find(input)
|
174
175
|
end
|
175
176
|
|
176
|
-
def initialize(kdbx, password, keyfile = nil)
|
177
|
-
@
|
178
|
-
@
|
177
|
+
def initialize(kdbx, password, keyfile = nil, colorize = false)
|
178
|
+
@colorize = colorize
|
179
|
+
@kdbx = Pathname.new(kdbx).expand_path
|
180
|
+
@keyfile = nil
|
181
|
+
@keyfile = Pathname.new(keyfile).expand_path if (keyfile)
|
179
182
|
@password = password
|
183
|
+
|
184
|
+
if (@kdbx.nil?)
|
185
|
+
# TODO
|
186
|
+
elsif (!@kdbx.exist?)
|
187
|
+
raise RubeePass::Error::FileNotFound.new(@kdbx)
|
188
|
+
elsif (!@kdbx.readable?)
|
189
|
+
raise RubeePass::Error::FileNotReadable.new(@kdbx)
|
190
|
+
end
|
191
|
+
|
192
|
+
if (@keyfile)
|
193
|
+
if (!@keyfile.exist?)
|
194
|
+
raise RubeePass::Error::FileNotFound.new(@keyfile)
|
195
|
+
elsif (!@keyfile.readable?)
|
196
|
+
raise RubeePass::Error::FileNotReadable.new(@keyfile)
|
197
|
+
end
|
198
|
+
end
|
180
199
|
end
|
181
200
|
|
182
201
|
def join_key_and_keyfile
|
@@ -264,28 +283,26 @@ class RubeePass
|
|
264
283
|
loop do
|
265
284
|
# Read block ID
|
266
285
|
data = file.read(4)
|
267
|
-
raise Error::
|
286
|
+
raise Error::InvalidGzip.new if (data.nil?)
|
268
287
|
id = data.unpack("L*")[0]
|
269
|
-
raise Error::
|
288
|
+
raise Error::InvalidGzip.new if (block_id != id)
|
270
289
|
|
271
290
|
block_id += 1
|
272
291
|
|
273
292
|
# Read expected hash
|
274
293
|
data = file.read(32)
|
275
|
-
raise Error::
|
294
|
+
raise Error::InvalidGzip.new if (data.nil?)
|
276
295
|
expected_hash = data
|
277
296
|
|
278
297
|
# Read size
|
279
298
|
data = file.read(4)
|
280
|
-
raise Error::
|
299
|
+
raise Error::InvalidGzip.new if (data.nil?)
|
281
300
|
size = data.unpack("L*")[0]
|
282
301
|
|
283
302
|
# Break is size is 0 and expected hash is all 0's
|
284
303
|
if (size == 0)
|
285
304
|
expected_hash.each_byte do |byte|
|
286
|
-
if (byte != 0)
|
287
|
-
raise Error::InvalidGzipError.new
|
288
|
-
end
|
305
|
+
raise Error::InvalidGzip.new if (byte != 0)
|
289
306
|
end
|
290
307
|
break
|
291
308
|
end
|
@@ -296,7 +313,7 @@ class RubeePass
|
|
296
313
|
|
297
314
|
# Check that actual hash is same as expected hash
|
298
315
|
if (actual_hash != expected_hash)
|
299
|
-
raise Error::
|
316
|
+
raise Error::InvalidGzip.new
|
300
317
|
end
|
301
318
|
|
302
319
|
# Append data
|
@@ -310,11 +327,11 @@ class RubeePass
|
|
310
327
|
def parse_xml
|
311
328
|
doc = REXML::Document.new(@xml)
|
312
329
|
if (doc.elements["KeePassFile/Root"].nil?)
|
313
|
-
raise Error::
|
330
|
+
raise Error::InvalidXML.new
|
314
331
|
end
|
315
332
|
|
316
333
|
root = doc.elements["KeePassFile/Root"]
|
317
|
-
@db = Group.from_xml(self, nil, root)
|
334
|
+
@db = Group.from_xml(self, nil, root, @colorize)
|
318
335
|
end
|
319
336
|
private :parse_xml
|
320
337
|
|
@@ -331,11 +348,11 @@ class RubeePass
|
|
331
348
|
cipher.update(encrypted) + cipher.final
|
332
349
|
)
|
333
350
|
rescue OpenSSL::Cipher::CipherError => e
|
334
|
-
raise Error::
|
351
|
+
raise Error::InvalidPassword.new
|
335
352
|
end
|
336
353
|
|
337
354
|
if (data.read(32) != @header[@@STREAM_START_BYTES])
|
338
|
-
raise Error::
|
355
|
+
raise Error::InvalidPassword.new
|
339
356
|
end
|
340
357
|
|
341
358
|
@gzip = parse_gzip(data)
|
@@ -346,11 +363,11 @@ class RubeePass
|
|
346
363
|
header = Hash.new
|
347
364
|
loop do
|
348
365
|
data = file.read(1)
|
349
|
-
raise Error::
|
366
|
+
raise Error::InvalidHeader.new if (data.nil?)
|
350
367
|
id = data.unpack("C*")[0]
|
351
368
|
|
352
369
|
data = file.read(2)
|
353
|
-
raise Error::
|
370
|
+
raise Error::InvalidHeader.new if (data.nil?)
|
354
371
|
size = data.unpack("S*")[0]
|
355
372
|
|
356
373
|
data = file.read(size)
|
@@ -371,11 +388,11 @@ class RubeePass
|
|
371
388
|
(header[@@MASTER_SEED].length != 32) ||
|
372
389
|
(header[@@TRANSFORM_SEED].length != 32)
|
373
390
|
)
|
374
|
-
raise Error::
|
391
|
+
raise Error::InvalidHeader.new
|
375
392
|
elsif (header[@@INNER_RANDOM_STREAM_ID] != irsi)
|
376
|
-
raise Error::
|
393
|
+
raise Error::NotSalsa.new
|
377
394
|
elsif (header[@@CIPHER_ID].unpack("H*")[0] != aes)
|
378
|
-
raise Error::
|
395
|
+
raise Error::NotAES.new
|
379
396
|
end
|
380
397
|
|
381
398
|
@header = header
|
@@ -384,24 +401,20 @@ class RubeePass
|
|
384
401
|
|
385
402
|
def read_magic_and_version(file)
|
386
403
|
data = file.read(4)
|
387
|
-
raise Error::
|
404
|
+
raise Error::InvalidMagic.new if (data.nil?)
|
388
405
|
sig1 = data.unpack("L*")[0]
|
389
|
-
if (sig1 != @@MAGIC_SIG1)
|
390
|
-
raise Error::InvalidMagicError.new
|
391
|
-
end
|
406
|
+
raise Error::InvalidMagic.new if (sig1 != @@MAGIC_SIG1)
|
392
407
|
|
393
408
|
data = file.read(4)
|
394
|
-
raise Error::
|
409
|
+
raise Error::InvalidMagic.new if (data.nil?)
|
395
410
|
sig2 = data.unpack("L*")[0]
|
396
|
-
if (sig2 != @@MAGIC_SIG2)
|
397
|
-
raise Error::InvalidMagicError.new
|
398
|
-
end
|
411
|
+
raise Error::InvalidMagic.new if (sig2 != @@MAGIC_SIG2)
|
399
412
|
|
400
413
|
data = file.read(4)
|
401
|
-
raise Error::
|
414
|
+
raise Error::InvalidVersion.new if (data.nil?)
|
402
415
|
ver = data.unpack("L*")[0]
|
403
416
|
if ((ver & 0xffff0000) != @@VERSION)
|
404
|
-
raise Error::
|
417
|
+
raise Error::InvalidVersion.new if (data.nil?)
|
405
418
|
end
|
406
419
|
end
|
407
420
|
private :read_magic_and_version
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubeepass
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Miles Whittaker
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-03-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: '5.8'
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 5.8.
|
22
|
+
version: 5.8.4
|
23
23
|
type: :development
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,27 +29,27 @@ dependencies:
|
|
29
29
|
version: '5.8'
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 5.8.
|
32
|
+
version: 5.8.4
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: rake
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '10.
|
39
|
+
version: '10.5'
|
40
40
|
- - ">="
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: 10.
|
42
|
+
version: 10.5.0
|
43
43
|
type: :development
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
46
46
|
requirements:
|
47
47
|
- - "~>"
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version: '10.
|
49
|
+
version: '10.5'
|
50
50
|
- - ">="
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: 10.
|
52
|
+
version: 10.5.0
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: colorize
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -79,7 +79,7 @@ dependencies:
|
|
79
79
|
version: '1.3'
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 1.3.
|
82
|
+
version: 1.3.3
|
83
83
|
type: :runtime
|
84
84
|
prerelease: false
|
85
85
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -89,7 +89,27 @@ dependencies:
|
|
89
89
|
version: '1.3'
|
90
90
|
- - ">="
|
91
91
|
- !ruby/object:Gem::Version
|
92
|
-
version: 1.3.
|
92
|
+
version: 1.3.3
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: json_config
|
95
|
+
requirement: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - "~>"
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '0.1'
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 0.1.1
|
103
|
+
type: :runtime
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0.1'
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: 0.1.1
|
93
113
|
- !ruby/object:Gem::Dependency
|
94
114
|
name: os
|
95
115
|
requirement: !ruby/object:Gem::Requirement
|
@@ -139,7 +159,7 @@ dependencies:
|
|
139
159
|
version: '0.1'
|
140
160
|
- - ">="
|
141
161
|
- !ruby/object:Gem::Version
|
142
|
-
version: 0.1.
|
162
|
+
version: 0.1.3
|
143
163
|
type: :runtime
|
144
164
|
prerelease: false
|
145
165
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -149,7 +169,7 @@ dependencies:
|
|
149
169
|
version: '0.1'
|
150
170
|
- - ">="
|
151
171
|
- !ruby/object:Gem::Version
|
152
|
-
version: 0.1.
|
172
|
+
version: 0.1.3
|
153
173
|
description: Ruby KeePass 2.x implementation. Currently it is read-only.
|
154
174
|
email: mjwhitta@gmail.com
|
155
175
|
executables:
|
@@ -161,16 +181,18 @@ files:
|
|
161
181
|
- lib/rubeepass.rb
|
162
182
|
- lib/rubeepass/entry.rb
|
163
183
|
- lib/rubeepass/error.rb
|
164
|
-
- lib/rubeepass/error/
|
165
|
-
- lib/rubeepass/error/
|
166
|
-
- lib/rubeepass/error/
|
167
|
-
- lib/rubeepass/error/
|
168
|
-
- lib/rubeepass/error/
|
169
|
-
- lib/rubeepass/error/
|
170
|
-
- lib/rubeepass/error/
|
171
|
-
- lib/rubeepass/error/
|
172
|
-
- lib/rubeepass/error/
|
173
|
-
- lib/rubeepass/error/
|
184
|
+
- lib/rubeepass/error/file_not_found.rb
|
185
|
+
- lib/rubeepass/error/file_not_readable.rb
|
186
|
+
- lib/rubeepass/error/invalid_gzip.rb
|
187
|
+
- lib/rubeepass/error/invalid_header.rb
|
188
|
+
- lib/rubeepass/error/invalid_magic.rb
|
189
|
+
- lib/rubeepass/error/invalid_password.rb
|
190
|
+
- lib/rubeepass/error/invalid_protected_data.rb
|
191
|
+
- lib/rubeepass/error/invalid_protected_stream_key.rb
|
192
|
+
- lib/rubeepass/error/invalid_version.rb
|
193
|
+
- lib/rubeepass/error/invalid_xml.rb
|
194
|
+
- lib/rubeepass/error/not_aes.rb
|
195
|
+
- lib/rubeepass/error/not_salsa20.rb
|
174
196
|
- lib/rubeepass/group.rb
|
175
197
|
- lib/rubeepass/protected_decryptor.rb
|
176
198
|
- lib/rubeepass/wish/cd_wish.rb
|