rubeepass 0.5.3 → 1.0.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 +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
|