rubeepass 0.3.9 → 0.4.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/lib/rubeepass/entry.rb +88 -10
- data/lib/rubeepass/error/invalid_xml_error.rb +7 -0
- data/lib/rubeepass/error.rb +1 -0
- data/lib/rubeepass/group.rb +55 -7
- data/lib/rubeepass.rb +6 -108
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 198fd42f6442a724c48c2e9fed48dde20d381ce6
|
4
|
+
data.tar.gz: 632b3d39273d942925b56139da529b35a08ec2f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f1dc4135f2c8d9de6cc409ea99c44f0b2c4d78a2001c63ca2047639c7613bb9e458939604d1e3af6b2bab151b4a2fba329f799dde7c3a344ae1aa1f408791eb
|
7
|
+
data.tar.gz: 510391ec34652bfea7b32895d3d3b82c8727d9077c12cac06bd09875fe257e505fcb216870290ded1f3d083210cbc9f0a77e3045ed59c0bc374030016b11c08d
|
data/lib/rubeepass/entry.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "rexml/document"
|
1
2
|
require "string"
|
2
3
|
|
3
4
|
class RubeePass::Entry
|
@@ -43,15 +44,90 @@ class RubeePass::Entry
|
|
43
44
|
return ret.join("\n")
|
44
45
|
end
|
45
46
|
|
46
|
-
def
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
47
|
+
def self.from_xml(keepass, parent, xml)
|
48
|
+
notes = ""
|
49
|
+
password = ""
|
50
|
+
title = ""
|
51
|
+
url = ""
|
52
|
+
username = ""
|
53
|
+
|
54
|
+
uuid = xml.elements["UUID"].text
|
55
|
+
uuid = "" if (uuid.nil?)
|
56
|
+
|
57
|
+
xml.elements.each("String") do |elem|
|
58
|
+
case elem.elements["Key"].text
|
59
|
+
when "Notes"
|
60
|
+
notes = elem.elements["Value"].text
|
61
|
+
notes = "" if (notes.nil?)
|
62
|
+
when "Password"
|
63
|
+
value = elem.elements["Value"]
|
64
|
+
if (value.attributes["Protected"] == "True")
|
65
|
+
password = handle_protected(keepass, value.text)
|
66
|
+
else
|
67
|
+
password = value.text
|
68
|
+
password = "" if (password.nil?)
|
69
|
+
end
|
70
|
+
when "Title"
|
71
|
+
title = elem.elements["Value"].text
|
72
|
+
title = "" if (title.nil?)
|
73
|
+
when "URL"
|
74
|
+
url = elem.elements["Value"].text
|
75
|
+
url = "" if (url.nil?)
|
76
|
+
when "UserName"
|
77
|
+
username = elem.elements["Value"].text
|
78
|
+
username = "" if (username.nil?)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Handle protected data from history
|
83
|
+
xml.elements.each("History/Entry/String/Value") do |value|
|
84
|
+
if (value.attributes["Protected"] == "True")
|
85
|
+
handle_protected(keepass, value.text)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
return RubeePass::Entry.new(
|
90
|
+
parent,
|
91
|
+
keepass,
|
92
|
+
notes,
|
93
|
+
password,
|
94
|
+
title,
|
95
|
+
url,
|
96
|
+
username,
|
97
|
+
uuid
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.handle_protected(keepass, base64)
|
102
|
+
data = nil
|
103
|
+
begin
|
104
|
+
data = base64.unpack("m*")[0].fix
|
105
|
+
rescue ArgumentError => e
|
106
|
+
raise Error::InvalidProtectedDataError.new
|
107
|
+
end
|
108
|
+
raise Error::InvalidProtectedDataError.new if (data.nil?)
|
109
|
+
|
110
|
+
return keepass.protected_decryptor.add_to_stream(data)
|
111
|
+
end
|
112
|
+
|
113
|
+
def initialize(
|
114
|
+
group,
|
115
|
+
keepass,
|
116
|
+
notes,
|
117
|
+
password,
|
118
|
+
title,
|
119
|
+
url,
|
120
|
+
username,
|
121
|
+
uuid
|
122
|
+
)
|
123
|
+
@group = group
|
124
|
+
@keepass = keepass
|
125
|
+
@notes = notes
|
126
|
+
@password = password
|
127
|
+
@title = title
|
128
|
+
@url = url
|
129
|
+
@username = username
|
130
|
+
@uuid = uuid
|
55
131
|
|
56
132
|
@path = @title
|
57
133
|
@path = "#{@group.path}/#{@title}" if (@group)
|
@@ -95,7 +171,9 @@ class RubeePass::Entry
|
|
95
171
|
def password
|
96
172
|
return nil if (@keepass.nil?)
|
97
173
|
begin
|
98
|
-
return @keepass.protected_decryptor.get_password(
|
174
|
+
return @keepass.protected_decryptor.get_password(
|
175
|
+
@password
|
176
|
+
)
|
99
177
|
rescue
|
100
178
|
return @password
|
101
179
|
end
|
data/lib/rubeepass/error.rb
CHANGED
@@ -8,5 +8,6 @@ require "rubeepass/error/invalid_password_error"
|
|
8
8
|
require "rubeepass/error/invalid_protected_data_error"
|
9
9
|
require "rubeepass/error/invalid_protected_stream_key_error"
|
10
10
|
require "rubeepass/error/invalid_version_error"
|
11
|
+
require "rubeepass/error/invalid_xml_error"
|
11
12
|
require "rubeepass/error/not_aes_error"
|
12
13
|
require "rubeepass/error/not_salsa20_error"
|
data/lib/rubeepass/group.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "rexml/document"
|
1
2
|
require "string"
|
2
3
|
|
3
4
|
class RubeePass::Group
|
@@ -23,8 +24,8 @@ class RubeePass::Group
|
|
23
24
|
out = Array.new
|
24
25
|
lvl = Array.new(level, " ").join
|
25
26
|
|
26
|
-
group_details = [ "#{@
|
27
|
-
group_details
|
27
|
+
group_details = [ "#{@path}".blue ] if (level == 0)
|
28
|
+
group_details = [ "#{@name}".blue ] if (level != 0)
|
28
29
|
|
29
30
|
group_details.each do |line|
|
30
31
|
out.push("#{lvl}#{line}")
|
@@ -63,6 +64,52 @@ class RubeePass::Group
|
|
63
64
|
return cwd
|
64
65
|
end
|
65
66
|
|
67
|
+
def self.from_xml(keepass, parent, xml)
|
68
|
+
name = xml.elements["Name"].text if (parent)
|
69
|
+
name = "" if (name.nil?)
|
70
|
+
name = "/" if (parent.nil?)
|
71
|
+
|
72
|
+
notes = xml.elements["Notes"].text if (parent)
|
73
|
+
notes = "" if (notes.nil?)
|
74
|
+
notes = "" if (parent.nil?)
|
75
|
+
|
76
|
+
uuid = xml.elements["UUID"].text if (parent)
|
77
|
+
uuid = "" if (uuid.nil?)
|
78
|
+
uuid = "" if (parent.nil?)
|
79
|
+
|
80
|
+
group = RubeePass::Group.new(
|
81
|
+
parent,
|
82
|
+
keepass,
|
83
|
+
name,
|
84
|
+
notes,
|
85
|
+
uuid
|
86
|
+
)
|
87
|
+
|
88
|
+
if (xml.elements["Entry"])
|
89
|
+
xml.elements.each("Entry") do |entry_xml|
|
90
|
+
entry = RubeePass::Entry.from_xml(
|
91
|
+
keepass,
|
92
|
+
group,
|
93
|
+
entry_xml
|
94
|
+
)
|
95
|
+
group.entries[entry.title] = entry
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
if (xml.elements["Group"])
|
100
|
+
xml.elements.each("Group") do |group_xml|
|
101
|
+
child = RubeePass::Group.from_xml(
|
102
|
+
keepass,
|
103
|
+
group,
|
104
|
+
group_xml
|
105
|
+
)
|
106
|
+
group.groups[child.name] = child
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
return group
|
111
|
+
end
|
112
|
+
|
66
113
|
def fuzzy_find(input)
|
67
114
|
return [ [], [], [] ] if (@keepass.nil?)
|
68
115
|
|
@@ -114,13 +161,14 @@ class RubeePass::Group
|
|
114
161
|
return false
|
115
162
|
end
|
116
163
|
|
117
|
-
def initialize(
|
164
|
+
def initialize(group, keepass, name, notes, uuid)
|
118
165
|
@entries = Hash.new
|
119
|
-
@group =
|
166
|
+
@group = group
|
120
167
|
@groups = Hash.new
|
121
|
-
@keepass =
|
122
|
-
@name =
|
123
|
-
@
|
168
|
+
@keepass = keepass
|
169
|
+
@name = name
|
170
|
+
@notes = notes
|
171
|
+
@uuid = uuid
|
124
172
|
|
125
173
|
@path = @name
|
126
174
|
@path = "#{@group.path}/#{@name}" if (@group)
|
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 "rexml/document"
|
5
6
|
require "scoobydoo"
|
6
7
|
require "shellwords"
|
7
8
|
require "uri"
|
@@ -169,19 +170,6 @@ class RubeePass
|
|
169
170
|
return @db.fuzzy_find(input)
|
170
171
|
end
|
171
172
|
|
172
|
-
def handle_protected(base64)
|
173
|
-
data = nil
|
174
|
-
begin
|
175
|
-
data = base64.unpack("m*")[0].fix
|
176
|
-
rescue ArgumentError => e
|
177
|
-
raise Error::InvalidProtectedDataError.new
|
178
|
-
end
|
179
|
-
raise Error::InvalidProtectedDataError.new if (data.nil?)
|
180
|
-
|
181
|
-
return @protected_decryptor.add_to_stream(data)
|
182
|
-
end
|
183
|
-
private :handle_protected
|
184
|
-
|
185
173
|
def initialize(kdbx, password, keyfile = nil)
|
186
174
|
@kdbx = kdbx
|
187
175
|
@keyfile = keyfile
|
@@ -316,104 +304,14 @@ class RubeePass
|
|
316
304
|
end
|
317
305
|
private :parse_gzip
|
318
306
|
|
319
|
-
# Horrible attempt at parsing xml. Someday I might use a library.
|
320
307
|
def parse_xml
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
ignore = true
|
325
|
-
inside_value = false
|
326
|
-
status = nil
|
327
|
-
|
328
|
-
@xml.gsub("<", "\n<").each_line do |line|
|
329
|
-
line.strip!
|
330
|
-
|
331
|
-
case line
|
332
|
-
when "<History>"
|
333
|
-
ignore = true
|
334
|
-
next
|
335
|
-
when "</History>"
|
336
|
-
ignore = false
|
337
|
-
next
|
338
|
-
when "<Root>"
|
339
|
-
ignore = false
|
340
|
-
next
|
341
|
-
when "</Root>"
|
342
|
-
break
|
343
|
-
when "</Value>"
|
344
|
-
status = nil
|
345
|
-
inside_value = false
|
346
|
-
next
|
347
|
-
when ""
|
348
|
-
next if (!inside_value)
|
349
|
-
end
|
350
|
-
|
351
|
-
line = CGI::unescapeHTML(line)
|
352
|
-
line = URI::unescape(line)
|
353
|
-
if (!line.valid_encoding?)
|
354
|
-
line = line.encode(
|
355
|
-
"UTF-16be",
|
356
|
-
:invalid=>:replace,
|
357
|
-
:replace=>"?"
|
358
|
-
).encode('UTF-8')
|
359
|
-
end
|
360
|
-
|
361
|
-
# Handle values with newlines
|
362
|
-
if (inside_value && !ignore)
|
363
|
-
entry_params[status] += "\n#{line}"
|
364
|
-
next
|
365
|
-
end
|
366
|
-
|
367
|
-
# Always handle protected data
|
368
|
-
case line
|
369
|
-
when %r{^<Value Protected="True">.+}
|
370
|
-
line.gsub!(%r{^<Value Protected="True">}, "")
|
371
|
-
if (ignore)
|
372
|
-
handle_protected(line)
|
373
|
-
else
|
374
|
-
entry_params[status] = handle_protected(line)
|
375
|
-
end
|
376
|
-
next
|
377
|
-
else
|
378
|
-
next if (ignore)
|
379
|
-
end
|
380
|
-
|
381
|
-
case line
|
382
|
-
when "<Entry>"
|
383
|
-
entry_params = { "Keepass" => self, "Group" => curr }
|
384
|
-
when "</Entry>"
|
385
|
-
entry = Entry.new(entry_params)
|
386
|
-
curr.entries[entry.title] = entry
|
387
|
-
when "<Group>"
|
388
|
-
group_params = { "Keepass" => self, "Group" => curr }
|
389
|
-
when "</Group>"
|
390
|
-
curr = curr.group
|
391
|
-
break if (curr.nil?)
|
392
|
-
when %r{^<Key>.+}
|
393
|
-
status = line.gsub(%r{^<Key>}, "")
|
394
|
-
when %r{^<Name>.+}
|
395
|
-
line.gsub!(%r{^<Name>}, "")
|
396
|
-
group_params["Name"] = line
|
397
|
-
|
398
|
-
group = Group.new(group_params)
|
399
|
-
curr.groups[group.name] = group
|
400
|
-
curr = group
|
401
|
-
when %r{^<UUID>.+}
|
402
|
-
uuid = line.gsub(%r{^<UUID>}, "")
|
403
|
-
if (group_params["UUID"].nil?)
|
404
|
-
group_params["UUID"] = uuid
|
405
|
-
else
|
406
|
-
entry_params["UUID"] = uuid
|
407
|
-
end
|
408
|
-
when %r{^<Value>.*}
|
409
|
-
line.gsub!(%r{^<Value>}, "")
|
410
|
-
line = "" if (line.nil?)
|
411
|
-
entry_params[status] = line
|
412
|
-
inside_value = true
|
413
|
-
end
|
308
|
+
doc = REXML::Document.new(@xml)
|
309
|
+
if (doc.elements["KeePassFile/Root"].nil?)
|
310
|
+
raise Error::InvalidXMLError.new
|
414
311
|
end
|
415
312
|
|
416
|
-
|
313
|
+
root = doc.elements["KeePassFile/Root"]
|
314
|
+
@db = Group.from_xml(self, nil, root)
|
417
315
|
end
|
418
316
|
private :parse_xml
|
419
317
|
|
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.4.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-01-
|
11
|
+
date: 2016-01-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -148,6 +148,7 @@ files:
|
|
148
148
|
- lib/rubeepass/error/invalid_protected_data_error.rb
|
149
149
|
- lib/rubeepass/error/invalid_protected_stream_key_error.rb
|
150
150
|
- lib/rubeepass/error/invalid_version_error.rb
|
151
|
+
- lib/rubeepass/error/invalid_xml_error.rb
|
151
152
|
- lib/rubeepass/error/not_aes_error.rb
|
152
153
|
- lib/rubeepass/error/not_salsa20_error.rb
|
153
154
|
- lib/rubeepass/group.rb
|