ruby-pass-qt 2.0.0 → 2.0.1
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/README.md +3 -3
- data/lib/pass-qt/app/components/passinfowidget.rb +188 -190
- data/lib/pass-qt/app/components/passlistwidget/treewidget.rb +190 -192
- data/lib/pass-qt/app/components/passlistwidget.rb +68 -70
- data/lib/pass-qt/app/views/browsestoresdialog.rb +85 -87
- data/lib/pass-qt/app/views/mainwindow.rb +76 -78
- data/lib/pass-qt/app/views/newonetimepassworddialog.rb +108 -110
- data/lib/pass-qt/app/views/newpassworddialog.rb +141 -143
- data/lib/pass-qt/config.rb +0 -1
- data/lib/pass-qt/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 933031fe6c0ff54220bc6c2dbaab8eb575d52d001c2c560258c0fdc4faeb9262
|
|
4
|
+
data.tar.gz: 04d8b8dc1ab23584f7e796a9e1d19b742e917036e79d0aea2c76248246fa3464
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 49af5357e70d430f76470a0842fbbf443dee5398a89a5d05d0b135b8c56e8aea682c0bf1d7ce3e063e358073d25285f872cb32aba9f1083c8d679b6c286973ce
|
|
7
|
+
data.tar.gz: 4ed0728562a4918572aa75b009b5631277da658a82adfe28e4351695c63fac49b3abef4cac7f94f07cd154ab2a981ea65b99ada0d43e973eabdc46b5f6916bdd
|
data/README.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
#
|
|
1
|
+
# PassQt
|
|
2
2
|
|
|
3
3
|
A simple GUI for pass on Linux.
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
|
-
- [Ruby
|
|
8
|
-
- [Qt
|
|
7
|
+
- [Ruby](https://www.ruby-lang.org/)
|
|
8
|
+
- [Qt](https://www.qt.io/)
|
|
9
9
|
- **one of the following password managers**
|
|
10
10
|
- [pass](https://www.passwordstore.org/) & [pwgen](https://sourceforge.net/projects/pwgen/)
|
|
11
11
|
- [gopass](https://github.com/gopasspw/gopass)
|
|
@@ -1,235 +1,233 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
end
|
|
1
|
+
class PassInfoWidget < RubyQt6::Bando::QWidget
|
|
2
|
+
q_object do
|
|
3
|
+
slot "_on_copy_action_triggered()"
|
|
4
|
+
slot "_on_copy_action_triggered_otpcode()"
|
|
5
|
+
slot "_on_view_action_triggered()"
|
|
6
|
+
end
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
def initialize
|
|
9
|
+
super
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
@store = QString.new
|
|
12
|
+
@passname = QString.new
|
|
14
13
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
initialize_form
|
|
15
|
+
initialize_otpform
|
|
16
|
+
initialize_folderform
|
|
17
|
+
initialize_infoframe
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
19
|
+
@stackedlayout = QStackedLayout.new
|
|
20
|
+
@stackedlayout.add_widget(@form)
|
|
21
|
+
@stackedlayout.add_widget(@otpform)
|
|
22
|
+
@stackedlayout.add_widget(@folderform)
|
|
23
|
+
@stackedlayout.add_widget(@infoframe)
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
mainlayout = QVBoxLayout.new(self)
|
|
26
|
+
mainlayout.add_spacing(76)
|
|
27
|
+
mainlayout.add_layout(@stackedlayout)
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
use_infoframe
|
|
30
|
+
end
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
32
|
+
def reinitialize_passfile(store, passname)
|
|
33
|
+
@store = store
|
|
34
|
+
@passname = passname
|
|
35
|
+
use_infoframe
|
|
36
|
+
|
|
37
|
+
Pass.show(@store, @passname, on_success: ->(data) {
|
|
38
|
+
formdata = h_parse_passfile(data)
|
|
39
|
+
if formdata["password"].start_with?("otpauth:")
|
|
40
|
+
use_otpform(formdata)
|
|
41
|
+
else
|
|
42
|
+
use_form(formdata)
|
|
43
|
+
end
|
|
44
|
+
}, on_failure: ->(data) {
|
|
45
|
+
errinfo = data["stderr"]
|
|
46
|
+
use_infoframe_err(errinfo)
|
|
47
|
+
})
|
|
48
|
+
end
|
|
50
49
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
def reinitialize_passfolder(store, passname)
|
|
51
|
+
@store = store
|
|
52
|
+
@passname = passname
|
|
53
|
+
use_infoframe
|
|
54
|
+
use_folderform
|
|
55
|
+
end
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
def reinitialize_infoframe
|
|
58
|
+
@store = QString.new
|
|
59
|
+
@passname = QString.new
|
|
60
|
+
use_infoframe
|
|
61
|
+
end
|
|
63
62
|
|
|
64
|
-
|
|
63
|
+
private
|
|
65
64
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
def initialize_form
|
|
66
|
+
@passnameinput = initialize_form_inputfield
|
|
67
|
+
initialize_form_inputfield_copyaction(@passnameinput)
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
@passwordinput = initialize_form_inputfield
|
|
70
|
+
initialize_form_inputfield_copyaction(@passwordinput)
|
|
71
|
+
initialize_form_inputfield_viewaction(@passwordinput)
|
|
73
72
|
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
@usernameinput = initialize_form_inputfield
|
|
74
|
+
initialize_form_inputfield_copyaction(@usernameinput)
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
@websiteinput = initialize_form_inputfield
|
|
77
|
+
initialize_form_inputfield_copyaction(@websiteinput)
|
|
79
78
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
79
|
+
@form = QWidget.new
|
|
80
|
+
formlayout = QFormLayout.new(@form)
|
|
81
|
+
formlayout.add_row(initialize_form_label("File"), @passnameinput)
|
|
82
|
+
formlayout.add_row(initialize_form_label("Username"), @usernameinput)
|
|
83
|
+
formlayout.add_row(initialize_form_label("Password"), @passwordinput)
|
|
84
|
+
formlayout.add_row(initialize_form_label("Website"), @websiteinput)
|
|
85
|
+
end
|
|
87
86
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
def initialize_otpform
|
|
88
|
+
@otppassnameinput = initialize_form_inputfield
|
|
89
|
+
initialize_form_inputfield_copyaction(@otppassnameinput)
|
|
91
90
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
@otppasswordinput = initialize_form_inputfield
|
|
92
|
+
initialize_form_inputfield_copyaction(@otppasswordinput)
|
|
93
|
+
initialize_form_inputfield_viewaction(@otppasswordinput)
|
|
95
94
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
95
|
+
@otpcodeinput = initialize_form_inputfield
|
|
96
|
+
action = @otpcodeinput.add_action(QIcon.from_theme(QIcon::ThemeIcon::EditCopy), QLineEdit::LeadingPosition)
|
|
97
|
+
action.triggered.connect(self, :_on_copy_action_triggered_otpcode)
|
|
99
98
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
99
|
+
@otpform = QWidget.new
|
|
100
|
+
otpformlayout = QFormLayout.new(@otpform)
|
|
101
|
+
otpformlayout.add_row(initialize_form_label("File"), @otppassnameinput)
|
|
102
|
+
otpformlayout.add_row(initialize_form_label("OTP URI"), @otppasswordinput)
|
|
103
|
+
otpformlayout.add_row(initialize_form_label("OTP Code"), @otpcodeinput)
|
|
104
|
+
end
|
|
106
105
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
106
|
+
def initialize_folderform
|
|
107
|
+
@folderpassnameinput = initialize_form_inputfield
|
|
108
|
+
initialize_form_inputfield_copyaction(@folderpassnameinput)
|
|
110
109
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
@folderform = QWidget.new
|
|
111
|
+
folderformlayout = QFormLayout.new(@folderform)
|
|
112
|
+
folderformlayout.add_row(initialize_form_label("Folder"), @folderpassnameinput)
|
|
113
|
+
end
|
|
115
114
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
115
|
+
def initialize_form_label(text)
|
|
116
|
+
label = QLabel.new(text)
|
|
117
|
+
label.set_alignment(Qt::AlignRight)
|
|
118
|
+
label.set_style_sheet("min-width: 80px; padding-right: 4px;")
|
|
119
|
+
label
|
|
120
|
+
end
|
|
122
121
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
122
|
+
def initialize_form_inputfield
|
|
123
|
+
input = QLineEdit.new
|
|
124
|
+
input.set_read_only(true)
|
|
125
|
+
input.set_focus_policy(Qt::NoFocus)
|
|
126
|
+
input
|
|
127
|
+
end
|
|
129
128
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
129
|
+
def initialize_form_inputfield_copyaction(input)
|
|
130
|
+
action = input.add_action(QIcon.from_theme(QIcon::ThemeIcon::EditCopy), QLineEdit::LeadingPosition)
|
|
131
|
+
action.triggered.connect(self, :_on_copy_action_triggered)
|
|
132
|
+
end
|
|
134
133
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
134
|
+
def initialize_form_inputfield_viewaction(input)
|
|
135
|
+
action = input.add_action(QIcon.from_theme(QIcon::ThemeIcon::DocumentPrintPreview), QLineEdit::TrailingPosition)
|
|
136
|
+
action.triggered.connect(self, :_on_view_action_triggered)
|
|
137
|
+
end
|
|
139
138
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
139
|
+
def initialize_infoframe
|
|
140
|
+
@infolabel = QLabel.new
|
|
141
|
+
@infoframe = QWidget.new
|
|
142
|
+
infoframelayout = QVBoxLayout.new(@infoframe)
|
|
143
|
+
infoframelayout.add_widget(@infolabel)
|
|
144
|
+
infoframelayout.add_stretch
|
|
145
|
+
end
|
|
147
146
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
147
|
+
def use_form(formdata)
|
|
148
|
+
@passnameinput.set_text(@passname)
|
|
149
|
+
@passwordinput.set_text(formdata["password"])
|
|
150
|
+
@passwordinput.set_echo_mode(QLineEdit::Password)
|
|
152
151
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
152
|
+
@usernameinput.set_text(formdata["username"])
|
|
153
|
+
@websiteinput.set_text(formdata["website"])
|
|
154
|
+
@stackedlayout.set_current_widget(@form)
|
|
155
|
+
end
|
|
157
156
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
157
|
+
def use_otpform(formdata)
|
|
158
|
+
@otppassnameinput.set_text(@passname)
|
|
159
|
+
@otppasswordinput.set_text(formdata["password"])
|
|
160
|
+
@otppasswordinput.set_cursor_position(0)
|
|
161
|
+
@otppasswordinput.set_echo_mode(QLineEdit::Password)
|
|
163
162
|
|
|
164
|
-
|
|
165
|
-
|
|
163
|
+
@otpcodeinput.set_text("")
|
|
164
|
+
@stackedlayout.set_current_widget(@otpform)
|
|
166
165
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
166
|
+
Pass.otp(@store, @passname, on_success: ->(data) {
|
|
167
|
+
otpcode = data["stdout"].rstrip
|
|
168
|
+
@otpcodeinput.set_text(otpcode)
|
|
169
|
+
}, on_failure: ->(_) {})
|
|
170
|
+
end
|
|
172
171
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
172
|
+
def use_folderform
|
|
173
|
+
@folderpassnameinput.set_text(@passname)
|
|
174
|
+
@stackedlayout.set_current_widget(@folderform)
|
|
175
|
+
end
|
|
177
176
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
177
|
+
def use_infoframe(info = "")
|
|
178
|
+
@infolabel.set_style_sheet("color: black;")
|
|
179
|
+
@infolabel.set_text(info)
|
|
180
|
+
@stackedlayout.set_current_widget(@infoframe)
|
|
181
|
+
end
|
|
183
182
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
183
|
+
def use_infoframe_err(info)
|
|
184
|
+
@infolabel.set_style_sheet("color: red;")
|
|
185
|
+
@infolabel.set_text(info)
|
|
186
|
+
@stackedlayout.set_current_widget(@infoframe)
|
|
187
|
+
end
|
|
189
188
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
189
|
+
def h_parse_passfile(data)
|
|
190
|
+
lines = data["stdout"].lines
|
|
191
|
+
password = lines[0][..-2]
|
|
193
192
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
193
|
+
username = ""
|
|
194
|
+
website = ""
|
|
195
|
+
lines.each do |line|
|
|
196
|
+
matched = line.match(/\A(\w+:\s*)?(.*)\n/)
|
|
197
|
+
next if matched.nil?
|
|
199
198
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
end
|
|
199
|
+
case matched[1]&.rstrip&.downcase
|
|
200
|
+
when "username:" then username = matched[2]
|
|
201
|
+
when "website:" then website = matched[2]
|
|
204
202
|
end
|
|
205
|
-
|
|
206
|
-
{
|
|
207
|
-
"password" => password,
|
|
208
|
-
"username" => username,
|
|
209
|
-
"website" => website
|
|
210
|
-
}
|
|
211
203
|
end
|
|
212
204
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
205
|
+
{
|
|
206
|
+
"password" => password,
|
|
207
|
+
"username" => username,
|
|
208
|
+
"website" => website
|
|
209
|
+
}
|
|
210
|
+
end
|
|
217
211
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
QApplication.clipboard.set_text(otpcode)
|
|
223
|
-
}, on_failure: ->(_) {})
|
|
224
|
-
end
|
|
212
|
+
def _on_copy_action_triggered
|
|
213
|
+
input = sender.parent
|
|
214
|
+
QApplication.clipboard.set_text(input.text)
|
|
215
|
+
end
|
|
225
216
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
217
|
+
def _on_copy_action_triggered_otpcode
|
|
218
|
+
Pass.otp(@store, @passname, on_success: ->(data) {
|
|
219
|
+
otpcode = data["stdout"].rstrip
|
|
220
|
+
@otpcodeinput.set_text(otpcode)
|
|
221
|
+
QApplication.clipboard.set_text(otpcode)
|
|
222
|
+
}, on_failure: ->(_) {})
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def _on_view_action_triggered
|
|
226
|
+
input = sender.parent
|
|
227
|
+
case input.echo_mode
|
|
228
|
+
when QLineEdit::Normal then input.set_echo_mode(QLineEdit::Password)
|
|
229
|
+
when QLineEdit::Password then input.set_echo_mode(QLineEdit::Normal)
|
|
230
|
+
else raise "unreachable!"
|
|
233
231
|
end
|
|
234
232
|
end
|
|
235
233
|
end
|