rubeepass 0.5.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/rpass +1 -0
- data/lib/rubeepass/entry.rb +72 -16
- data/lib/rubeepass/error/invalid_gzip.rb +0 -2
- data/lib/rubeepass/error/invalid_header.rb +0 -2
- data/lib/rubeepass/error/invalid_magic.rb +0 -2
- data/lib/rubeepass/error/invalid_password.rb +0 -2
- data/lib/rubeepass/error/invalid_protected_data.rb +0 -2
- data/lib/rubeepass/error/invalid_protected_stream_key.rb +0 -2
- data/lib/rubeepass/error/invalid_version.rb +0 -2
- data/lib/rubeepass/error/invalid_xml.rb +0 -2
- data/lib/rubeepass/error/not_aes.rb +0 -2
- data/lib/rubeepass/error/not_salsa20.rb +0 -2
- data/lib/rubeepass/group.rb +18 -15
- data/lib/rubeepass/wish/cd_wish.rb +21 -31
- data/lib/rubeepass/wish/copy_wish.rb +67 -93
- data/lib/rubeepass/wish/echo_wish.rb +57 -77
- data/lib/rubeepass/wish/ls_wish.rb +23 -33
- data/lib/rubeepass/wish/pwd_wish.rb +4 -7
- data/lib/rubeepass/wish/show_wish.rb +41 -56
- data/lib/rubeepass.rb +7 -4
- data/lib/string.rb +0 -11
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6cd12a155f8a2bcbc5da07aee0406bcd4040ca4b
|
4
|
+
data.tar.gz: 506e2a4064b4ae4f0a2fb3d46eae776aea0a6265
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0f80638206bbc1e018eb631a219898620c15bc2ca7f6210960638c70a3276059a2749e9156a3ab7e0477ea4adc209b8236c5af1d9ae16e8fb149ce82b998693a
|
7
|
+
data.tar.gz: 6719b71656475fe4dabf4ac4e41db654f8baa3429decc2a62477335eaddb717c5931939b3e48d15f7a1da52ca494086231b4285876c5860c33f9d74d74af27d3
|
data/bin/rpass
CHANGED
@@ -277,6 +277,7 @@ rescue RubeePass::Error => e
|
|
277
277
|
puts e.message
|
278
278
|
exit RubeePassExit::EXCEPTION
|
279
279
|
rescue Exception => e
|
280
|
+
$stderr.puts
|
280
281
|
$stderr.puts "Oops! Looks like an error has occured! If the " \
|
281
282
|
"error persists, file a bug at:".word_wrap
|
282
283
|
$stderr.puts
|
data/lib/rubeepass/entry.rb
CHANGED
@@ -1,17 +1,12 @@
|
|
1
1
|
require "colorize"
|
2
2
|
require "rexml/document"
|
3
|
-
require "string"
|
4
3
|
|
5
4
|
class RubeePass::Entry
|
6
5
|
include Comparable
|
7
6
|
|
8
7
|
attr_accessor :group
|
9
8
|
attr_accessor :keepass
|
10
|
-
attr_accessor :notes
|
11
9
|
attr_accessor :path
|
12
|
-
attr_accessor :title
|
13
|
-
attr_accessor :url
|
14
|
-
attr_accessor :username
|
15
10
|
attr_accessor :uuid
|
16
11
|
|
17
12
|
def ==(other)
|
@@ -72,12 +67,16 @@ class RubeePass::Entry
|
|
72
67
|
uuid = "" if (uuid.nil?)
|
73
68
|
|
74
69
|
xml.elements.each("String") do |elem|
|
70
|
+
value = elem.elements["Value"]
|
75
71
|
case elem.elements["Key"].text
|
76
72
|
when "Notes"
|
77
|
-
|
78
|
-
|
73
|
+
if (value.attributes["Protected"] == "True")
|
74
|
+
notes = handle_protected(keepass, value.text)
|
75
|
+
else
|
76
|
+
notes = value.text
|
77
|
+
notes = "" if (notes.nil?)
|
78
|
+
end
|
79
79
|
when "Password"
|
80
|
-
value = elem.elements["Value"]
|
81
80
|
if (value.attributes["Protected"] == "True")
|
82
81
|
password = handle_protected(keepass, value.text)
|
83
82
|
else
|
@@ -85,14 +84,26 @@ class RubeePass::Entry
|
|
85
84
|
password = "" if (password.nil?)
|
86
85
|
end
|
87
86
|
when "Title"
|
88
|
-
|
89
|
-
|
87
|
+
if (value.attributes["Protected"] == "True")
|
88
|
+
title = handle_protected(keepass, value.text)
|
89
|
+
else
|
90
|
+
title = value.text
|
91
|
+
title = "" if (title.nil?)
|
92
|
+
end
|
90
93
|
when "URL"
|
91
|
-
|
92
|
-
|
94
|
+
if (value.attributes["Protected"] == "True")
|
95
|
+
url = handle_protected(keepass, value.text)
|
96
|
+
else
|
97
|
+
url = value.text
|
98
|
+
url = "" if (url.nil?)
|
99
|
+
end
|
93
100
|
when "UserName"
|
94
|
-
|
95
|
-
|
101
|
+
if (value.attributes["Protected"] == "True")
|
102
|
+
username = handle_protected(keepass, value.text)
|
103
|
+
else
|
104
|
+
username = value.text
|
105
|
+
username = "" if (username.nil?)
|
106
|
+
end
|
96
107
|
end
|
97
108
|
end
|
98
109
|
|
@@ -119,8 +130,11 @@ class RubeePass::Entry
|
|
119
130
|
data = nil
|
120
131
|
return nil if (base64.nil?)
|
121
132
|
begin
|
122
|
-
data = base64.unpack("m*")[0]
|
123
|
-
|
133
|
+
data = base64.unpack("m*")[0]
|
134
|
+
if (data.length != data.bytesize)
|
135
|
+
data = data.unpack("H*").pack("H*")
|
136
|
+
end
|
137
|
+
rescue ArgumentError
|
124
138
|
raise Error::InvalidProtectedData.new
|
125
139
|
end
|
126
140
|
raise Error::InvalidProtectedData.new if (data.nil?)
|
@@ -186,6 +200,16 @@ class RubeePass::Entry
|
|
186
200
|
end
|
187
201
|
end
|
188
202
|
|
203
|
+
def notes
|
204
|
+
return nil if (@keepass.nil?)
|
205
|
+
return "" if (@notes.nil?)
|
206
|
+
begin
|
207
|
+
return @keepass.protected_decryptor.get_password(@notes)
|
208
|
+
rescue
|
209
|
+
return @notes
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
189
213
|
def password
|
190
214
|
return nil if (@keepass.nil?)
|
191
215
|
return "" if (@password.nil?)
|
@@ -198,6 +222,38 @@ class RubeePass::Entry
|
|
198
222
|
end
|
199
223
|
end
|
200
224
|
|
225
|
+
def title
|
226
|
+
return nil if (@keepass.nil?)
|
227
|
+
return "" if (@title.nil?)
|
228
|
+
begin
|
229
|
+
return @keepass.protected_decryptor.get_password(@title)
|
230
|
+
rescue
|
231
|
+
return @title
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
def url
|
236
|
+
return nil if (@keepass.nil?)
|
237
|
+
return "" if (@url.nil?)
|
238
|
+
begin
|
239
|
+
return @keepass.protected_decryptor.get_password(@url)
|
240
|
+
rescue
|
241
|
+
return @url
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
def username
|
246
|
+
return nil if (@keepass.nil?)
|
247
|
+
return "" if (@username.nil?)
|
248
|
+
begin
|
249
|
+
return @keepass.protected_decryptor.get_password(
|
250
|
+
@username
|
251
|
+
)
|
252
|
+
rescue
|
253
|
+
return @username
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
201
257
|
def to_s
|
202
258
|
return details
|
203
259
|
end
|
data/lib/rubeepass/group.rb
CHANGED
@@ -49,7 +49,9 @@ class RubeePass::Group
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def entry_titles
|
52
|
-
return @entries.keys.sort
|
52
|
+
return @entries.keys.sort do |a, b|
|
53
|
+
a.downcase <=> b.downcase
|
54
|
+
end
|
53
55
|
end
|
54
56
|
|
55
57
|
def find_group(path)
|
@@ -116,41 +118,42 @@ class RubeePass::Group
|
|
116
118
|
return group
|
117
119
|
end
|
118
120
|
|
119
|
-
def fuzzy_find(
|
120
|
-
return [
|
121
|
+
def fuzzy_find(search)
|
122
|
+
return [[], []] if (@keepass.nil?)
|
121
123
|
|
122
|
-
|
123
|
-
|
124
|
-
path, target =
|
124
|
+
search = @path if (search.nil? || search.empty?)
|
125
|
+
search = @keepass.absolute_path(search, @path)
|
126
|
+
path, target = search.rsplit("/")
|
125
127
|
|
126
128
|
new_cwd = find_group(path)
|
127
|
-
return [
|
129
|
+
return [[], []] if (new_cwd.nil?)
|
128
130
|
|
129
131
|
if (new_cwd.has_group?(target))
|
130
132
|
new_cwd = new_cwd.groups[target]
|
131
133
|
target = ""
|
132
|
-
input += "/"
|
133
134
|
end
|
134
135
|
|
135
136
|
group_completions = new_cwd.group_names
|
136
137
|
entry_completions = new_cwd.entry_titles
|
137
138
|
|
138
139
|
if (target.empty?)
|
139
|
-
return [
|
140
|
+
return [group_completions, entry_completions]
|
140
141
|
end
|
141
142
|
|
142
|
-
group_completions.
|
143
|
-
|
143
|
+
group_completions.keep_if do |group|
|
144
|
+
group.downcase.start_with?(target.downcase)
|
144
145
|
end
|
145
|
-
entry_completions.
|
146
|
-
|
146
|
+
entry_completions.keep_if do |entry|
|
147
|
+
entry.downcase.start_with?(target.downcase)
|
147
148
|
end
|
148
149
|
|
149
|
-
return [
|
150
|
+
return [group_completions, entry_completions]
|
150
151
|
end
|
151
152
|
|
152
153
|
def group_names
|
153
|
-
return @groups.keys.sort
|
154
|
+
return @groups.keys.sort do |a, b|
|
155
|
+
a.downcase <=> b.downcase
|
156
|
+
end
|
154
157
|
end
|
155
158
|
|
156
159
|
def has_entry?(title)
|
@@ -3,7 +3,7 @@ require "djinni"
|
|
3
3
|
|
4
4
|
class CDWish < Djinni::Wish
|
5
5
|
def aliases
|
6
|
-
return [
|
6
|
+
return ["cd"]
|
7
7
|
end
|
8
8
|
|
9
9
|
def description
|
@@ -15,47 +15,37 @@ class CDWish < Djinni::Wish
|
|
15
15
|
cwd = djinni_env["cwd"]
|
16
16
|
prompt_color = djinni_env["prompt_color"]
|
17
17
|
|
18
|
-
|
19
|
-
new_cwd = keepass.find_group(
|
20
|
-
|
21
|
-
if (new_cwd)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
18
|
+
path = keepass.absolute_path(args, cwd.path)
|
19
|
+
new_cwd = keepass.find_group(path)
|
20
|
+
|
21
|
+
if (new_cwd.nil?)
|
22
|
+
puts "Group not found"
|
23
|
+
return
|
24
|
+
end
|
25
|
+
|
26
|
+
djinni_env["cwd"] = new_cwd
|
27
|
+
if (prompt_color)
|
28
|
+
prompt = "rpass:#{new_cwd.name}> ".send(prompt_color)
|
29
29
|
else
|
30
|
-
|
30
|
+
prompt = "rpass:#{new_cwd.name}> "
|
31
31
|
end
|
32
|
+
djinni_env["djinni_prompt"] = prompt
|
32
33
|
end
|
33
34
|
|
34
35
|
def tab_complete(input, djinni_env = {})
|
35
36
|
cwd = djinni_env["cwd"]
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
if (dest.empty?)
|
42
|
-
if (groups.length == 1)
|
43
|
-
input = "#{path}/#{groups.first}/"
|
44
|
-
return input.gsub(%r{^#{cwd.path}/?}, "")
|
45
|
-
end
|
46
|
-
puts
|
47
|
-
groups.each do |group|
|
48
|
-
puts "#{group}/"
|
49
|
-
end
|
50
|
-
return input.gsub(%r{^#{cwd.path}/?}, "")
|
37
|
+
groups, entries = cwd.fuzzy_find(input)
|
38
|
+
|
39
|
+
completions = Hash.new
|
40
|
+
groups.each do |group|
|
41
|
+
completions[group] = "Group"
|
51
42
|
end
|
52
43
|
|
53
|
-
|
54
|
-
return input.gsub(%r{^#{cwd.path}/?}, "")
|
44
|
+
return [completions, input.rsplit("/")[1], "/"]
|
55
45
|
end
|
56
46
|
|
57
47
|
def usage
|
58
48
|
puts "#{aliases.join(", ")} [group]"
|
59
|
-
puts "
|
49
|
+
puts " #{description}."
|
60
50
|
end
|
61
51
|
end
|
@@ -2,7 +2,7 @@ require "djinni"
|
|
2
2
|
|
3
3
|
class CopyWish < Djinni::Wish
|
4
4
|
def aliases
|
5
|
-
return [
|
5
|
+
return ["copy", "cp"]
|
6
6
|
end
|
7
7
|
|
8
8
|
def description
|
@@ -10,129 +10,103 @@ class CopyWish < Djinni::Wish
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def execute(args, djinni_env = {})
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
field,
|
19
|
-
if (
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
13
|
+
# "".split(" ", 2) => [] aka [nil, nil]
|
14
|
+
# " ".split(" ", 2) => [""] aka ["", nil]
|
15
|
+
# "pass".split(" ", 2) => ["pass"] aka ["pass", nil]
|
16
|
+
# "pass ".split(" ", 2) => ["pass", ""]
|
17
|
+
|
18
|
+
field, path = args.split(" ", 2)
|
19
|
+
if (
|
20
|
+
field.nil? ||
|
21
|
+
field.empty? ||
|
22
|
+
!@fields.include?(field) ||
|
23
|
+
path.nil? ||
|
24
|
+
path.empty?
|
25
|
+
)
|
26
|
+
usage
|
26
27
|
return
|
27
28
|
end
|
28
29
|
|
29
30
|
keepass = djinni_env["keepass"]
|
30
31
|
cwd = djinni_env["cwd"]
|
31
|
-
args = cwd.path if (args.nil? || args.empty?)
|
32
32
|
|
33
|
-
|
34
|
-
path, target =
|
33
|
+
path = keepass.absolute_path(path, cwd.path)
|
34
|
+
path, target = path.rsplit("/")
|
35
35
|
new_cwd = keepass.find_group(path)
|
36
|
+
timeout = djinni_env["clipboard_timeout"]
|
36
37
|
|
37
|
-
if (new_cwd)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
when "user"
|
59
|
-
new_cwd.entries[target].copy_username_to_clipboard
|
60
|
-
keepass.send(
|
61
|
-
"clear_clipboard_after_#{timeout}_seconds"
|
62
|
-
)
|
63
|
-
end
|
64
|
-
else
|
65
|
-
puts "Entry \"#{args}\" doesn't exist!"
|
66
|
-
end
|
67
|
-
else
|
68
|
-
puts "Entry \"#{args}\" doesn't exist!"
|
38
|
+
if (new_cwd.nil? || !new_cwd.has_entry?(target))
|
39
|
+
puts "Entry not found"
|
40
|
+
return
|
41
|
+
end
|
42
|
+
|
43
|
+
case field
|
44
|
+
when "pass"
|
45
|
+
new_cwd.entries[target].copy_password_to_clipboard
|
46
|
+
keepass.send(
|
47
|
+
"clear_clipboard_after_#{timeout}_seconds"
|
48
|
+
)
|
49
|
+
when "url"
|
50
|
+
new_cwd.entries[target].copy_url_to_clipboard
|
51
|
+
keepass.send(
|
52
|
+
"clear_clipboard_after_#{timeout}_seconds"
|
53
|
+
)
|
54
|
+
when "user"
|
55
|
+
new_cwd.entries[target].copy_username_to_clipboard
|
56
|
+
keepass.send(
|
57
|
+
"clear_clipboard_after_#{timeout}_seconds"
|
58
|
+
)
|
69
59
|
end
|
70
60
|
end
|
71
61
|
|
72
62
|
def initialize
|
73
|
-
@fields =
|
63
|
+
@fields = {
|
64
|
+
"pass" => "Password",
|
65
|
+
"url" => "URL",
|
66
|
+
"user" => "Username"
|
67
|
+
}
|
74
68
|
end
|
75
69
|
|
76
70
|
def tab_complete(input, djinni_env = {})
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
end
|
71
|
+
# "".split(" ", 2) => [] aka [nil, nil]
|
72
|
+
# " ".split(" ", 2) => [""] aka ["", nil]
|
73
|
+
# "pass".split(" ", 2) => ["pass"] aka ["pass", nil]
|
74
|
+
# "pass ".split(" ", 2) => ["pass", ""]
|
82
75
|
|
83
|
-
field,
|
76
|
+
field, path = input.split(" ", 2)
|
77
|
+
return [@fields, "", ""] if (field.nil? || field.empty?)
|
84
78
|
|
85
|
-
if (
|
86
|
-
@fields.
|
87
|
-
|
88
|
-
if (f.start_with?(field))
|
89
|
-
return "#{f} "
|
90
|
-
end
|
79
|
+
if (path.nil?)
|
80
|
+
completions = @fields.select do |f, d|
|
81
|
+
f.start_with?(field)
|
91
82
|
end
|
83
|
+
return [completions, field, " "]
|
92
84
|
end
|
93
85
|
|
94
|
-
input = "" if (input.nil?)
|
95
|
-
|
96
86
|
cwd = djinni_env["cwd"]
|
97
|
-
|
98
|
-
if (groups.empty? && entries.empty?)
|
99
|
-
return "#{field} #{input.gsub(%r{^#{cwd.path}/?}, "")}"
|
100
|
-
end
|
101
|
-
|
102
|
-
path, target = input.rsplit("/")
|
87
|
+
groups, entries = cwd.fuzzy_find(path)
|
103
88
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
return "#{field} #{input.gsub(%r{^#{cwd.path}/?}, "")}"
|
108
|
-
elsif (groups.empty? && (entries.length == 1))
|
109
|
-
input = "#{path}/#{entries.first}"
|
110
|
-
return "#{field} #{input.gsub(%r{^#{cwd.path}/?}, "")}"
|
111
|
-
end
|
112
|
-
puts
|
113
|
-
groups.each do |group|
|
114
|
-
puts "#{group}/"
|
115
|
-
end
|
116
|
-
puts entries
|
117
|
-
return "#{field} #{input.gsub(%r{^#{cwd.path}/?}, "")}"
|
89
|
+
completions = Hash.new
|
90
|
+
groups.each do |group|
|
91
|
+
completions[group] = "Group"
|
118
92
|
end
|
119
|
-
|
120
|
-
|
121
|
-
input = "#{path}/#{groups.first}/"
|
122
|
-
elsif (!entries.empty?)
|
123
|
-
input = "#{path}/#{entries.first}"
|
93
|
+
entries.each do |entry|
|
94
|
+
completions[entry] = "Entry"
|
124
95
|
end
|
125
96
|
|
126
|
-
|
97
|
+
append = "/"
|
98
|
+
append = "" if (groups.empty?)
|
99
|
+
|
100
|
+
return [completions, path.rsplit("/")[1], append]
|
127
101
|
end
|
128
102
|
|
129
103
|
def usage
|
130
104
|
puts "#{aliases.join(", ")} <field> <entry>"
|
131
|
-
puts "
|
105
|
+
puts " #{description}."
|
132
106
|
puts
|
133
107
|
puts "FIELDS"
|
134
|
-
@fields.each do |field|
|
135
|
-
puts "
|
108
|
+
@fields.each do |field, desc|
|
109
|
+
puts " #{field}"
|
136
110
|
end
|
137
111
|
end
|
138
112
|
end
|
@@ -2,7 +2,7 @@ require "djinni"
|
|
2
2
|
|
3
3
|
class EchoWish < Djinni::Wish
|
4
4
|
def aliases
|
5
|
-
return [
|
5
|
+
return ["echo"]
|
6
6
|
end
|
7
7
|
|
8
8
|
def description
|
@@ -10,113 +10,93 @@ class EchoWish < Djinni::Wish
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def execute(args, djinni_env = {})
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
field,
|
19
|
-
if (
|
20
|
-
|
13
|
+
# "".split(" ", 2) => [] aka [nil, nil]
|
14
|
+
# " ".split(" ", 2) => [""] aka ["", nil]
|
15
|
+
# "pass".split(" ", 2) => ["pass"] aka ["pass", nil]
|
16
|
+
# "pass ".split(" ", 2) => ["pass", ""]
|
17
|
+
|
18
|
+
field, path = args.split(" ", 2)
|
19
|
+
if (
|
20
|
+
field.nil? ||
|
21
|
+
field.empty? ||
|
22
|
+
!@fields.include?(field) ||
|
23
|
+
path.nil? ||
|
24
|
+
path.empty?
|
25
|
+
)
|
26
|
+
usage
|
21
27
|
return
|
22
28
|
end
|
23
29
|
|
24
30
|
keepass = djinni_env["keepass"]
|
25
31
|
cwd = djinni_env["cwd"]
|
26
|
-
args = cwd.path if (args.nil? || args.empty?)
|
27
32
|
|
28
|
-
|
29
|
-
path, target =
|
33
|
+
path = keepass.absolute_path(path, cwd.path)
|
34
|
+
path, target = path.rsplit("/")
|
30
35
|
new_cwd = keepass.find_group(path)
|
31
36
|
|
32
|
-
if (new_cwd)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
new_cwd.entries[target].echo_url
|
45
|
-
when "user"
|
46
|
-
new_cwd.entries[target].echo_username
|
47
|
-
end
|
48
|
-
else
|
49
|
-
puts "Entry \"#{args}\" doesn't exist!"
|
50
|
-
end
|
51
|
-
else
|
52
|
-
puts "Entry \"#{args}\" doesn't exist!"
|
37
|
+
if (new_cwd.nil? || !new_cwd.has_entry?(target))
|
38
|
+
puts "Entry not found"
|
39
|
+
return
|
40
|
+
end
|
41
|
+
|
42
|
+
case field
|
43
|
+
when "pass"
|
44
|
+
new_cwd.entries[target].echo_password
|
45
|
+
when "url"
|
46
|
+
new_cwd.entries[target].echo_url
|
47
|
+
when "user"
|
48
|
+
new_cwd.entries[target].echo_username
|
53
49
|
end
|
54
50
|
end
|
55
51
|
|
56
52
|
def initialize
|
57
|
-
@fields =
|
53
|
+
@fields = {
|
54
|
+
"pass" => "Password",
|
55
|
+
"url" => "URL",
|
56
|
+
"user" => "Username"
|
57
|
+
}
|
58
58
|
end
|
59
59
|
|
60
60
|
def tab_complete(input, djinni_env = {})
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
61
|
+
# "".split(" ", 2) => [] aka [nil, nil]
|
62
|
+
# " ".split(" ", 2) => [""] aka ["", nil]
|
63
|
+
# "pass".split(" ", 2) => ["pass"] aka ["pass", nil]
|
64
|
+
# "pass ".split(" ", 2) => ["pass", ""]
|
66
65
|
|
67
|
-
field,
|
66
|
+
field, path = input.split(" ", 2)
|
67
|
+
return [@fields, "", ""] if (field.nil? || field.empty?)
|
68
68
|
|
69
|
-
if (
|
70
|
-
@fields.
|
71
|
-
|
72
|
-
if (f.start_with?(field))
|
73
|
-
return "#{f} "
|
74
|
-
end
|
69
|
+
if (path.nil?)
|
70
|
+
completions = @fields.select do |f, d|
|
71
|
+
f.start_with?(field)
|
75
72
|
end
|
73
|
+
return [completions, field, " "]
|
76
74
|
end
|
77
75
|
|
78
|
-
input = "" if (input.nil?)
|
79
|
-
|
80
76
|
cwd = djinni_env["cwd"]
|
81
|
-
|
82
|
-
if (groups.empty? && entries.empty?)
|
83
|
-
return "#{field} #{input.gsub(%r{^#{cwd.path}/?}, "")}"
|
84
|
-
end
|
77
|
+
groups, entries = cwd.fuzzy_find(path)
|
85
78
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
if ((groups.length == 1) && entries.empty?)
|
90
|
-
input = "#{path}/#{groups.first}/"
|
91
|
-
return "#{field} #{input.gsub(%r{^#{cwd.path}/?}, "")}"
|
92
|
-
elsif (groups.empty? && (entries.length == 1))
|
93
|
-
input = "#{path}/#{entries.first}"
|
94
|
-
return "#{field} #{input.gsub(%r{^#{cwd.path}/?}, "")}"
|
95
|
-
end
|
96
|
-
puts
|
97
|
-
groups.each do |group|
|
98
|
-
puts "#{group}/"
|
99
|
-
end
|
100
|
-
puts entries
|
101
|
-
return "#{field} #{input.gsub(%r{^#{cwd.path}/?}, "")}"
|
79
|
+
completions = Hash.new
|
80
|
+
groups.each do |group|
|
81
|
+
completions[group] = "Group"
|
102
82
|
end
|
103
|
-
|
104
|
-
|
105
|
-
input = "#{path}/#{groups.first}/"
|
106
|
-
elsif (!entries.empty?)
|
107
|
-
input = "#{path}/#{entries.first}"
|
83
|
+
entries.each do |entry|
|
84
|
+
completions[entry] = "Entry"
|
108
85
|
end
|
109
86
|
|
110
|
-
|
87
|
+
append = "/"
|
88
|
+
append = "" if (groups.empty?)
|
89
|
+
|
90
|
+
return [completions, path.rsplit("/")[1], append]
|
111
91
|
end
|
112
92
|
|
113
93
|
def usage
|
114
94
|
puts "#{aliases.join(", ")} <field> <entry>"
|
115
|
-
puts "
|
95
|
+
puts " #{description}."
|
116
96
|
puts
|
117
97
|
puts "FIELDS"
|
118
|
-
@fields.each do |field|
|
119
|
-
puts "
|
98
|
+
@fields.each do |field, desc|
|
99
|
+
puts " #{field}"
|
120
100
|
end
|
121
101
|
end
|
122
102
|
end
|
@@ -2,7 +2,7 @@ require "djinni"
|
|
2
2
|
|
3
3
|
class LSWish < Djinni::Wish
|
4
4
|
def aliases
|
5
|
-
return [
|
5
|
+
return ["ls", "dir"]
|
6
6
|
end
|
7
7
|
|
8
8
|
def description
|
@@ -12,48 +12,38 @@ class LSWish < Djinni::Wish
|
|
12
12
|
def execute(args, djinni_env = {})
|
13
13
|
keepass = djinni_env["keepass"]
|
14
14
|
cwd = djinni_env["cwd"]
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
new_cwd = keepass.find_group(
|
19
|
-
|
20
|
-
if (new_cwd)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
15
|
+
|
16
|
+
args = cwd.path if (args.empty?)
|
17
|
+
path = keepass.absolute_path(args, cwd.path)
|
18
|
+
new_cwd = keepass.find_group(path)
|
19
|
+
|
20
|
+
if (new_cwd.nil?)
|
21
|
+
puts "Group not found"
|
22
|
+
return
|
23
|
+
end
|
24
|
+
|
25
|
+
new_cwd.group_names.each do |group|
|
26
|
+
puts "#{group}/"
|
27
|
+
end
|
28
|
+
new_cwd.entry_titles.each do |entry|
|
29
|
+
puts "#{entry}"
|
29
30
|
end
|
30
31
|
end
|
31
32
|
|
32
33
|
def tab_complete(input, djinni_env = {})
|
33
34
|
cwd = djinni_env["cwd"]
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
if (dest.empty?)
|
40
|
-
if (groups.length == 1)
|
41
|
-
input = "#{path}/#{groups.first}/"
|
42
|
-
return input.gsub(%r{^#{cwd.path}/?}, "")
|
43
|
-
end
|
44
|
-
puts
|
45
|
-
groups.each do |group|
|
46
|
-
puts "#{group}/"
|
47
|
-
end
|
48
|
-
return input.gsub(%r{^#{cwd.path}/?}, "")
|
35
|
+
groups, entries = cwd.fuzzy_find(input)
|
36
|
+
|
37
|
+
completions = Hash.new
|
38
|
+
groups.each do |group|
|
39
|
+
completions[group] = "Group"
|
49
40
|
end
|
50
41
|
|
51
|
-
|
52
|
-
return input.gsub(%r{^#{cwd.path}/?}, "")
|
42
|
+
return [completions, input.rsplit("/")[1], "/"]
|
53
43
|
end
|
54
44
|
|
55
45
|
def usage
|
56
46
|
puts "#{aliases.join(", ")} [group]"
|
57
|
-
puts "
|
47
|
+
puts " #{description}."
|
58
48
|
end
|
59
49
|
end
|
@@ -2,7 +2,7 @@ require "djinni"
|
|
2
2
|
|
3
3
|
class PwdWish < Djinni::Wish
|
4
4
|
def aliases
|
5
|
-
return [
|
5
|
+
return ["pwd"]
|
6
6
|
end
|
7
7
|
|
8
8
|
def description
|
@@ -10,15 +10,12 @@ class PwdWish < Djinni::Wish
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def execute(args, djinni_env = {})
|
13
|
-
|
14
|
-
|
15
|
-
else
|
16
|
-
usage
|
17
|
-
end
|
13
|
+
puts djinni_env["cwd"].path if (args.empty?)
|
14
|
+
usage if (!args.empty?)
|
18
15
|
end
|
19
16
|
|
20
17
|
def usage
|
21
18
|
puts aliases.join(", ")
|
22
|
-
puts "
|
19
|
+
puts " #{description}."
|
23
20
|
end
|
24
21
|
end
|
@@ -2,7 +2,7 @@ require "djinni"
|
|
2
2
|
|
3
3
|
class ShowWish < Djinni::Wish
|
4
4
|
def aliases
|
5
|
-
return [
|
5
|
+
return ["cat", "show", "showall"]
|
6
6
|
end
|
7
7
|
|
8
8
|
def description
|
@@ -12,82 +12,67 @@ class ShowWish < Djinni::Wish
|
|
12
12
|
def execute(args, djinni_env = {})
|
13
13
|
keepass = djinni_env["keepass"]
|
14
14
|
cwd = djinni_env["cwd"]
|
15
|
-
args = cwd.path if (args.nil? || args.empty?)
|
16
15
|
|
17
|
-
args =
|
18
|
-
path
|
16
|
+
args = cwd.path if (args.empty?)
|
17
|
+
path = keepass.absolute_path(args, cwd.path)
|
18
|
+
path, target = path.rsplit("/")
|
19
19
|
new_cwd = keepass.find_group(path)
|
20
20
|
|
21
|
-
if (new_cwd)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
21
|
+
if (new_cwd.nil?)
|
22
|
+
puts "Group not found"
|
23
|
+
return
|
24
|
+
end
|
25
|
+
|
26
|
+
if (target.empty?)
|
27
|
+
case djinni_env["djinni_input"]
|
28
|
+
when "showall"
|
29
|
+
puts new_cwd.details(0, true)
|
30
|
+
else
|
31
|
+
puts new_cwd
|
32
|
+
end
|
33
|
+
elsif (new_cwd.has_group?(target))
|
34
|
+
case djinni_env["djinni_input"]
|
35
|
+
when "showall"
|
36
|
+
puts new_cwd.groups[target].details(0, true)
|
37
|
+
else
|
38
|
+
puts new_cwd.groups[target]
|
39
|
+
end
|
40
|
+
elsif (new_cwd.has_entry?(target))
|
41
|
+
new_cwd.entry_titles.select do |entry|
|
42
|
+
target.downcase == entry.downcase
|
43
|
+
end.each do |entry|
|
30
44
|
case djinni_env["djinni_input"]
|
31
45
|
when "showall"
|
32
|
-
puts new_cwd.
|
46
|
+
puts new_cwd.entries[entry].details(0, true)
|
33
47
|
else
|
34
|
-
puts new_cwd.
|
35
|
-
end
|
36
|
-
elsif (new_cwd.has_entry?(target))
|
37
|
-
new_cwd.entry_titles.select do |entry|
|
38
|
-
target.downcase == entry.downcase
|
39
|
-
end.each do |entry|
|
40
|
-
case djinni_env["djinni_input"]
|
41
|
-
when "showall"
|
42
|
-
puts new_cwd.entries[entry].details(0, true)
|
43
|
-
else
|
44
|
-
puts new_cwd.entries[entry]
|
45
|
-
end
|
48
|
+
puts new_cwd.entries[entry]
|
46
49
|
end
|
47
|
-
else
|
48
|
-
puts "Group/entry \"#{args}\" doesn't exist!"
|
49
50
|
end
|
50
51
|
else
|
51
|
-
puts "Group/
|
52
|
+
puts "Group/Entry not found"
|
52
53
|
end
|
53
54
|
end
|
54
55
|
|
55
56
|
def tab_complete(input, djinni_env = {})
|
56
57
|
cwd = djinni_env["cwd"]
|
57
|
-
|
58
|
-
if (groups.empty? && entries.empty?)
|
59
|
-
return input.gsub(%r{^#{cwd.path}/?}, "")
|
60
|
-
end
|
61
|
-
|
62
|
-
path, target = input.rsplit("/")
|
58
|
+
groups, entries = cwd.fuzzy_find(input)
|
63
59
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
return input.gsub(%r{^#{cwd.path}/?}, "")
|
68
|
-
elsif (groups.empty? && (entries.length == 1))
|
69
|
-
input = "#{path}/#{entries.first}"
|
70
|
-
return input.gsub(%r{^#{cwd.path}/?}, "")
|
71
|
-
end
|
72
|
-
puts
|
73
|
-
groups.each do |group|
|
74
|
-
puts "#{group}/"
|
75
|
-
end
|
76
|
-
puts entries
|
77
|
-
return input.gsub(%r{^#{cwd.path}/?}, "")
|
60
|
+
completions = Hash.new
|
61
|
+
groups.each do |group|
|
62
|
+
completions[group] = "Group"
|
78
63
|
end
|
79
|
-
|
80
|
-
|
81
|
-
input = "#{path}/#{groups.first}/"
|
82
|
-
elsif (!entries.empty?)
|
83
|
-
input = "#{path}/#{entries.first}"
|
64
|
+
entries.each do |entry|
|
65
|
+
completions[entry] = "Entry"
|
84
66
|
end
|
85
67
|
|
86
|
-
|
68
|
+
append = "/"
|
69
|
+
append = "" if (groups.empty?)
|
70
|
+
|
71
|
+
return [completions, input.rsplit("/")[1], append]
|
87
72
|
end
|
88
73
|
|
89
74
|
def usage
|
90
75
|
puts "#{aliases.join(", ")} [group|entry]"
|
91
|
-
puts "
|
76
|
+
puts " #{description}."
|
92
77
|
end
|
93
78
|
end
|
data/lib/rubeepass.rb
CHANGED
@@ -6,7 +6,6 @@ require "pathname"
|
|
6
6
|
require "rexml/document"
|
7
7
|
require "scoobydoo"
|
8
8
|
require "shellwords"
|
9
|
-
require "string"
|
10
9
|
require "uri"
|
11
10
|
require "zlib"
|
12
11
|
|
@@ -208,7 +207,11 @@ class RubeePass
|
|
208
207
|
|
209
208
|
filehash = ""
|
210
209
|
if (@keyfile)
|
211
|
-
|
210
|
+
require "string"
|
211
|
+
contents = File.readlines(@keyfile).join
|
212
|
+
if (contents.length != contents.bytesize)
|
213
|
+
contents = contents.unpack("H*").pack("H*")
|
214
|
+
end
|
212
215
|
if (contents[0..4] == "<?xml")
|
213
216
|
# XML Key file
|
214
217
|
# My ugly attempt to parse a small XML Key file with a
|
@@ -352,7 +355,7 @@ class RubeePass
|
|
352
355
|
data = StringIO.new(
|
353
356
|
cipher.update(encrypted) + cipher.final
|
354
357
|
)
|
355
|
-
rescue OpenSSL::Cipher::CipherError
|
358
|
+
rescue OpenSSL::Cipher::CipherError
|
356
359
|
raise Error::InvalidPassword.new
|
357
360
|
end
|
358
361
|
|
@@ -455,7 +458,7 @@ class RubeePass
|
|
455
458
|
return if (@thread.nil?)
|
456
459
|
begin
|
457
460
|
@thread.join
|
458
|
-
rescue Interrupt
|
461
|
+
rescue Interrupt
|
459
462
|
puts
|
460
463
|
end
|
461
464
|
end
|
data/lib/string.rb
CHANGED
@@ -1,16 +1,5 @@
|
|
1
1
|
# Modify String class to allow for rsplit and word wrap
|
2
2
|
class String
|
3
|
-
def fix
|
4
|
-
# Fix unicode (I think???)
|
5
|
-
# Apparently sometimes length and bytesize don't always agree.
|
6
|
-
# When this happens, there are "invisible" bytes, which I need
|
7
|
-
# to be "visible". Converting to hex and back fixes this.
|
8
|
-
if (length != bytesize)
|
9
|
-
return self.unpack("H*").pack("H*")
|
10
|
-
end
|
11
|
-
return self
|
12
|
-
end
|
13
|
-
|
14
3
|
def rsplit(pattern)
|
15
4
|
ret = rpartition(pattern)
|
16
5
|
ret.delete_at(1)
|
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: 1.0.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-03-
|
11
|
+
date: 2016-03-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -76,20 +76,20 @@ dependencies:
|
|
76
76
|
requirements:
|
77
77
|
- - "~>"
|
78
78
|
- !ruby/object:Gem::Version
|
79
|
-
version: '
|
79
|
+
version: '2.0'
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version:
|
82
|
+
version: 2.0.0
|
83
83
|
type: :runtime
|
84
84
|
prerelease: false
|
85
85
|
version_requirements: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
89
|
+
version: '2.0'
|
90
90
|
- - ">="
|
91
91
|
- !ruby/object:Gem::Version
|
92
|
-
version:
|
92
|
+
version: 2.0.0
|
93
93
|
- !ruby/object:Gem::Dependency
|
94
94
|
name: json_config
|
95
95
|
requirement: !ruby/object:Gem::Requirement
|