ruby-pass-qt 2.0.3 → 2.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a101e18a3f8a4c03a9996efadf2cbe3a09d393605e57d49a86fe401726d6c7b8
4
- data.tar.gz: 99390447b2bde56c07063127b4fa899490fe22197ab37f0b08153d3ce581b938
3
+ metadata.gz: 1816007968467bc6ee9d3fcd9a69bb648a10cde931ebc809a09e76b82bd15109
4
+ data.tar.gz: 752af79c37a068739aa9751a8015da3c7e08901f8b39442441e502cdb3495149
5
5
  SHA512:
6
- metadata.gz: 79213aedb87e6432955fffd25377e21f108e35bbb1a9c5914939620f76fdd9041dad166f78a4c10fa82987404bbd15eabbc178d3084867494a56441a899e31cd
7
- data.tar.gz: b3297f156132a566b6cd40454f543ce0c42a0d9b15eca7196d69628c465e6e64b2fc3d8d63d41a0204ffa876c9c2503088decb618cd15bc47c8df551cb41903b
6
+ metadata.gz: 727ccfc09d7df169abdf1b6512d27fe82f0931a0c2f6e43deadcf6eb9c2ec829c8e36cd5a09acfc46d5ac568866710ae386963685b0dbab0c676431bb0a946ca
7
+ data.tar.gz: 6400d7a320dfb687a6e1ba0a8b1cdf819e3bb42b966f3161073e081202f2bae428f4c3cc28883e24a37c93a3b760e0605c01708adeefc1d739b9e52f858a5cea
data/README.md CHANGED
@@ -12,22 +12,22 @@ A simple GUI for pass on Linux.
12
12
 
13
13
  ## Installation
14
14
 
15
- ```console
16
- $ gem install ruby-pass-qt
15
+ ```sh
16
+ gem install ruby-pass-qt
17
17
  ```
18
18
 
19
19
  ## Usage
20
20
 
21
21
  To initialize the password store:
22
22
 
23
- ```console
24
- $ pass init new_gpg-id_or_email
23
+ ```sh
24
+ pass init new_gpg-id_or_email
25
25
  ```
26
26
 
27
27
  To launch the GUI:
28
28
 
29
- ```console
30
- $ pass-qt
29
+ ```sh
30
+ pass-qt
31
31
  ```
32
32
 
33
33
  ## Screenshot
@@ -0,0 +1,26 @@
1
+ class PassInfoWidget < RubyQt6::Bando::QWidget
2
+ module Helpers
3
+ def self.parse_passfile(data)
4
+ lines = data["stdout"].lines
5
+ password = lines[0][..-2]
6
+
7
+ username = ""
8
+ website = ""
9
+ lines.each do |line|
10
+ matched = line.match(/\A(\w+:\s*)?(.*)\n/)
11
+ next if matched.nil?
12
+
13
+ case matched[1]&.rstrip&.downcase
14
+ when "username:" then username = matched[2]
15
+ when "website:" then website = matched[2]
16
+ end
17
+ end
18
+
19
+ {
20
+ "password" => password,
21
+ "username" => username,
22
+ "website" => website
23
+ }
24
+ end
25
+ end
26
+ end
@@ -1,3 +1,5 @@
1
+ require_relative "passinfowidget/helpers"
2
+
1
3
  class PassInfoWidget < RubyQt6::Bando::QWidget
2
4
  q_object do
3
5
  slot "_on_copy_action_triggered()"
@@ -29,13 +31,13 @@ class PassInfoWidget < RubyQt6::Bando::QWidget
29
31
  use_infoframe
30
32
  end
31
33
 
32
- def reinitialize_passfile(store, passname)
34
+ def use_passfilecard(store, passname)
33
35
  @store = store
34
36
  @passname = passname
35
37
  use_infoframe
36
38
 
37
39
  Pass.show(@store, @passname, on_success: ->(data) {
38
- formdata = h_parse_passfile(data)
40
+ formdata = Helpers.parse_passfile(data)
39
41
  if formdata["password"].start_with?("otpauth:")
40
42
  use_otpform(formdata)
41
43
  else
@@ -47,14 +49,14 @@ class PassInfoWidget < RubyQt6::Bando::QWidget
47
49
  })
48
50
  end
49
51
 
50
- def reinitialize_passfolder(store, passname)
52
+ def use_passfoldercard(store, passname)
51
53
  @store = store
52
54
  @passname = passname
53
55
  use_infoframe
54
56
  use_folderform
55
57
  end
56
58
 
57
- def reinitialize_infoframe
59
+ def use_infocard
58
60
  @store = QString.new
59
61
  @passname = QString.new
60
62
  use_infoframe
@@ -186,29 +188,6 @@ class PassInfoWidget < RubyQt6::Bando::QWidget
186
188
  @stackedlayout.set_current_widget(@infoframe)
187
189
  end
188
190
 
189
- def h_parse_passfile(data)
190
- lines = data["stdout"].lines
191
- password = lines[0][..-2]
192
-
193
- username = ""
194
- website = ""
195
- lines.each do |line|
196
- matched = line.match(/\A(\w+:\s*)?(.*)\n/)
197
- next if matched.nil?
198
-
199
- case matched[1]&.rstrip&.downcase
200
- when "username:" then username = matched[2]
201
- when "website:" then website = matched[2]
202
- end
203
- end
204
-
205
- {
206
- "password" => password,
207
- "username" => username,
208
- "website" => website
209
- }
210
- end
211
-
212
191
  def _on_copy_action_triggered
213
192
  input = sender.parent
214
193
  QApplication.clipboard.set_text(input.text)
@@ -0,0 +1,18 @@
1
+ class PassListWidget < RubyQt6::Bando::QWidget
2
+ class TreeWidget < RubyQt6::Bando::QTreeWidget
3
+ module Helpers
4
+ def self.passfile?(fileinfo)
5
+ case fileinfo
6
+ when QFileInfo then fileinfo.suffix.downcase == "gpg"
7
+ when QString then fileinfo.ends_with(".gpg", Qt::CaseInsensitive)
8
+ else raise "unreachable!"
9
+ end
10
+ end
11
+
12
+ def self.folderpath(store, fileinfo)
13
+ folder = fileinfo.dir? ? fileinfo.absolute_file_path : fileinfo.absolute_path
14
+ QDir.new(store).relative_file_path(folder)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,46 @@
1
+ class PassListWidget < RubyQt6::Bando::QWidget
2
+ class TreeWidget < RubyQt6::Bando::QTreeWidget
3
+ DataItem = Struct.new(:passname, :treewidgetitem)
4
+
5
+ class TreeBuilder
6
+ def initialize
7
+ @fileiconprovider = QFileIconProvider.new
8
+ end
9
+
10
+ def perform(treewidget, store, dataitems)
11
+ treewidget.clear
12
+
13
+ store_root_path = QDir.new(store)
14
+ dirs = [store]
15
+ until dirs.empty?
16
+ dir = dirs.shift
17
+ diritem = dataitems[dir]&.treewidgetitem || treewidget.invisible_root_item
18
+
19
+ entry_list = QDir.new(dir).entry_info_list(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)
20
+ entry_list.each do |entry|
21
+ next if entry.hidden?
22
+ next if entry.file_name.starts_with(".")
23
+
24
+ filepath = entry.absolute_file_path
25
+ next if dataitems.key?(filepath)
26
+
27
+ if entry.dir?
28
+ dirs << filepath
29
+ passname = store_root_path.relative_file_path(filepath)
30
+ elsif entry.file?
31
+ next unless Helpers.passfile?(entry)
32
+ passname = store_root_path.relative_file_path(filepath)
33
+ passname = passname[0, passname.size - entry.suffix.size - 1]
34
+ else
35
+ next
36
+ end
37
+
38
+ item = QTreeWidgetItem.new(diritem, QStringList.new << entry.complete_base_name << filepath)
39
+ item.set_icon(0, @fileiconprovider.icon(entry))
40
+ dataitems[filepath] = DataItem.new(passname, item)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,43 @@
1
+ class PassListWidget < RubyQt6::Bando::QWidget
2
+ class TreeWidget < RubyQt6::Bando::QTreeWidget
3
+ class TreeFilter
4
+ def perform(_treewidget, dataitems, text)
5
+ if text.empty?
6
+ dataitems.each do |_, item|
7
+ item.treewidgetitem.set_hidden(false)
8
+ item.treewidgetitem.set_selected(false)
9
+ end
10
+ return
11
+ end
12
+
13
+ re_options = QRegularExpression::UnanchoredWildcardConversion | QRegularExpression::NonPathWildcardConversion
14
+ re = QRegularExpression.from_wildcard(text, nil, re_options)
15
+
16
+ filepath_matched = Set.new
17
+ filepath_matched_1st = nil
18
+ dataitems.each do |filepath, item|
19
+ has_match = re.match(item.passname).has_match
20
+ next unless has_match
21
+
22
+ if filepath_matched_1st.nil?
23
+ filepath_matched_1st = filepath if Helpers.passfile?(filepath)
24
+ end
25
+
26
+ loop do
27
+ filepath_matched << filepath
28
+ filepath = QFileInfo.new(filepath).absolute_path
29
+ break unless dataitems.key?(filepath)
30
+ end
31
+ end
32
+
33
+ dataitems.each do |filepath, item|
34
+ visible = filepath_matched.include?(filepath)
35
+ item.treewidgetitem.set_hidden(!visible)
36
+
37
+ selected = filepath_matched_1st == filepath
38
+ item.treewidgetitem.set_selected(selected)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,9 +1,10 @@
1
+ require_relative "treewidget/helpers"
2
+ require_relative "treewidget/treebuilder"
3
+ require_relative "treewidget/treefilter"
4
+
1
5
  class PassListWidget < RubyQt6::Bando::QWidget
2
6
  class TreeWidget < RubyQt6::Bando::QTreeWidget
3
- DataItem = Struct.new(:passname, :treewidgetitem)
4
-
5
7
  q_object do
6
- signal "store_changed(QString)"
7
8
  signal "passfile_selected(QString,QString)"
8
9
  signal "passfolder_selected(QString,QString)"
9
10
  slot "_on_item_clicked(QTreeWidgetItem*,int)"
@@ -21,7 +22,6 @@ class PassListWidget < RubyQt6::Bando::QWidget
21
22
  @dataitems = {}
22
23
 
23
24
  initialize_actions
24
- initialize_fileiconprovider
25
25
 
26
26
  item_clicked.connect(self, :_on_item_clicked)
27
27
  end
@@ -44,83 +44,25 @@ class PassListWidget < RubyQt6::Bando::QWidget
44
44
  menu.exec(evt.global_pos)
45
45
  end
46
46
 
47
- def reinitialize_store(store)
48
- clear
49
-
47
+ def refresh(store, selected_passname: nil)
50
48
  @store = store
51
49
  @dataitems = {}
52
50
 
53
- store_root_path = QDir.new(@store)
54
- dirs = [store]
55
- until dirs.empty?
56
- dir = dirs.shift
57
- diritem = @dataitems[dir]&.treewidgetitem || invisible_root_item
58
-
59
- entry_list = QDir.new(dir).entry_info_list(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)
60
- entry_list.each do |entry|
61
- next if entry.hidden?
62
- next if entry.file_name.starts_with(".")
63
-
64
- filepath = entry.absolute_file_path
65
- next if @dataitems.key?(filepath)
66
-
67
- if entry.dir?
68
- dirs << filepath
69
- passname = store_root_path.relative_file_path(filepath)
70
- elsif entry.file?
71
- next unless h_passfile?(entry)
72
- passname = store_root_path.relative_file_path(filepath)
73
- passname = passname[0, passname.size - entry.suffix.size - 1]
74
- else
75
- next
76
- end
77
-
78
- item = QTreeWidgetItem.new(diritem, QStringList.new << entry.complete_base_name << filepath)
79
- item.set_icon(0, @fileiconprovider.icon(entry))
80
- @dataitems[filepath] = DataItem.new(passname, item)
81
- end
82
- end
51
+ builder = TreeBuilder.new
52
+ builder.perform(self, @store, @dataitems)
83
53
 
84
54
  expand_all
85
- store_changed.emit(@store)
86
- end
87
-
88
- def update_passname_filter(text)
89
- if text.empty?
90
- @dataitems.each do |_, item|
91
- item.treewidgetitem.set_hidden(false)
92
- item.treewidgetitem.set_selected(false)
93
- end
94
- return
95
- end
96
-
97
- re_options = QRegularExpression::UnanchoredWildcardConversion | QRegularExpression::NonPathWildcardConversion
98
- re = QRegularExpression.from_wildcard(text, nil, re_options)
99
-
100
- filepath_matched = Set.new
101
- filepath_matched_1st = nil
102
- @dataitems.each do |filepath, item|
103
- has_match = re.match(item.passname).has_match
104
- next unless has_match
105
-
106
- if filepath_matched_1st.nil?
107
- filepath_matched_1st = filepath if h_passfile?(filepath)
108
- end
109
-
110
- loop do
111
- filepath_matched << filepath
112
- filepath = QFileInfo.new(filepath).absolute_path
113
- break unless @dataitems.key?(filepath)
55
+ @dataitems.each do |_, item|
56
+ if item.passname == selected_passname
57
+ item.treewidgetitem.set_selected(true)
58
+ break
114
59
  end
115
60
  end
61
+ end
116
62
 
117
- @dataitems.each do |filepath, item|
118
- visible = filepath_matched.include?(filepath)
119
- item.treewidgetitem.set_hidden(!visible)
120
-
121
- selected = filepath_matched_1st == filepath
122
- item.treewidgetitem.set_selected(selected)
123
- end
63
+ def update_passname_filter(text)
64
+ filter = TreeFilter.new
65
+ filter.perform(self, @dataitems, text)
124
66
  end
125
67
 
126
68
  private
@@ -139,38 +81,10 @@ class PassListWidget < RubyQt6::Bando::QWidget
139
81
  action
140
82
  end
141
83
 
142
- def initialize_fileiconprovider
143
- @fileiconprovider = QFileIconProvider.new
144
- end
145
-
146
- def reinitialize(selected_passname: "")
147
- reinitialize_store(@store)
148
-
149
- @dataitems.each do |_, item|
150
- if item.passname == selected_passname
151
- item.treewidgetitem.set_selected(true)
152
- break
153
- end
154
- end
155
- end
156
-
157
- def h_passfile?(fileinfo)
158
- case fileinfo
159
- when QFileInfo then fileinfo.suffix.downcase == "gpg"
160
- when QString then fileinfo.ends_with(".gpg", Qt::CaseInsensitive)
161
- else raise "unreachable!"
162
- end
163
- end
164
-
165
- def h_folderpath(fileinfo)
166
- folder = fileinfo.dir? ? fileinfo.absolute_file_path : fileinfo.absolute_path
167
- QDir.new(@store).relative_file_path(folder)
168
- end
169
-
170
84
  def _on_item_clicked(item, _column)
171
85
  filepath = item.data(1, Qt::DisplayRole).value
172
86
  dataitem = @dataitems[filepath]
173
- h_passfile?(filepath) ?
87
+ Helpers.passfile?(filepath) ?
174
88
  passfile_selected.emit(@store, dataitem.passname) :
175
89
  passfolder_selected.emit(@store, dataitem.passname)
176
90
  end
@@ -179,14 +93,14 @@ class PassListWidget < RubyQt6::Bando::QWidget
179
93
  item = selected_items[0]
180
94
  if item
181
95
  filepath = item.data(1, Qt::DisplayRole).value
182
- folder = h_folderpath(QFileInfo.new(filepath))
96
+ folder = Helpers.folderpath(@store, QFileInfo.new(filepath))
183
97
  folder = "" if folder == "."
184
98
  else
185
99
  folder = ""
186
100
  end
187
101
 
188
102
  dialog = NewPasswordDialog.new(@store, folder, on_success: ->(passname) {
189
- reinitialize(selected_passname: passname)
103
+ refresh(@store, selected_passname: passname)
190
104
  })
191
105
  dialog.show
192
106
  end
@@ -195,14 +109,14 @@ class PassListWidget < RubyQt6::Bando::QWidget
195
109
  item = selected_items[0]
196
110
  if item
197
111
  filepath = item.data(1, Qt::DisplayRole).value
198
- folder = h_folderpath(QFileInfo.new(filepath))
112
+ folder = Helpers.folderpath(@store, QFileInfo.new(filepath))
199
113
  folder = "" if folder == "."
200
114
  else
201
115
  folder = ""
202
116
  end
203
117
 
204
118
  dialog = NewOneTimePasswordDialog.new(@store, folder, on_success: ->(passname) {
205
- reinitialize(selected_passname: passname)
119
+ refresh(@store, selected_passname: passname)
206
120
  })
207
121
  dialog.show
208
122
  end
@@ -218,7 +132,7 @@ class PassListWidget < RubyQt6::Bando::QWidget
218
132
 
219
133
  file = QFile.new(filepath)
220
134
  file.move_to_trash
221
- reinitialize
135
+ refresh(@store)
222
136
  end
223
137
 
224
138
  def _on_refresh_action_triggered
@@ -231,7 +145,7 @@ class PassListWidget < RubyQt6::Bando::QWidget
231
145
  passname = ""
232
146
  end
233
147
 
234
- reinitialize(selected_passname: passname)
148
+ refresh(@store, selected_passname: passname)
235
149
  end
236
150
 
237
151
  def _on_open_action_triggered
@@ -7,7 +7,6 @@ class PassListWidget < RubyQt6::Bando::QWidget
7
7
  signal "passfolder_selected(QString,QString)"
8
8
  slot "_on_combobox_current_text_changed(QString)"
9
9
  slot "_on_searchbar_text_changed(QString)"
10
- slot "_on_treewidget_store_changed(QString)"
11
10
  end
12
11
 
13
12
  def initialize
@@ -25,7 +24,7 @@ class PassListWidget < RubyQt6::Bando::QWidget
25
24
  update_combobox
26
25
  end
27
26
 
28
- def reinitialize_stores
27
+ def refresh
29
28
  @combobox.block_signals(true).tap do |blocked|
30
29
  @combobox.clear
31
30
  ensure
@@ -58,7 +57,6 @@ class PassListWidget < RubyQt6::Bando::QWidget
58
57
  def initialize_treewidget
59
58
  @treewidget = TreeWidget.new
60
59
  @treewidget.set_header_hidden(true)
61
- @treewidget.store_changed.connect(self, :_on_treewidget_store_changed)
62
60
  @treewidget.passfile_selected.connect(self, :passfile_selected)
63
61
  @treewidget.passfolder_selected.connect(self, :passfolder_selected)
64
62
  end
@@ -72,18 +70,15 @@ class PassListWidget < RubyQt6::Bando::QWidget
72
70
 
73
71
  def _on_combobox_current_text_changed(_text)
74
72
  store = @combobox.current_data.value
75
- @treewidget.reinitialize_store(store)
73
+ store_changed.emit(store)
76
74
 
77
75
  @searchbar.clear
78
76
  QTimer.single_shot(0, @searchbar, :set_focus)
77
+
78
+ @treewidget.refresh(store)
79
79
  end
80
80
 
81
81
  def _on_searchbar_text_changed(text)
82
82
  @treewidget.update_passname_filter(text)
83
83
  end
84
-
85
- def _on_treewidget_store_changed(store)
86
- @searchbar.clear
87
- store_changed.emit(store)
88
- end
89
84
  end
@@ -76,7 +76,7 @@ class BrowseStoresDialog < RubyQt6::Bando::QDialog
76
76
  tableitem.delete_now
77
77
  end
78
78
 
79
- def h_put_stores
79
+ def update_settings_stores
80
80
  stores = @dataitems.map { |fullpath, _| {"fullpath" => fullpath} }
81
81
  PassQt.settings.PUT_stores(stores)
82
82
  stores_changed.emit
@@ -99,11 +99,11 @@ class BrowseStoresDialog < RubyQt6::Bando::QDialog
99
99
  end
100
100
 
101
101
  update_tablewidget_addtableitem(dir)
102
- h_put_stores
102
+ update_settings_stores
103
103
  end
104
104
 
105
105
  def _on_list_remove_button_clicked
106
106
  update_tablewidget_removetableitem(sender.parent)
107
- h_put_stores
107
+ update_settings_stores
108
108
  end
109
109
  end
@@ -61,18 +61,18 @@ class MainWindow < RubyQt6::Bando::QMainWindow
61
61
  end
62
62
 
63
63
  def _on_browsestoresdialog_stores_changed
64
- @passlistwidget.reinitialize_stores
64
+ @passlistwidget.refresh
65
65
  end
66
66
 
67
67
  def _on_passlistwidget_store_changed(store)
68
- @passinfowidget.reinitialize_infoframe
68
+ @passinfowidget.use_infocard
69
69
  end
70
70
 
71
71
  def _on_passlistwidget_passfile_selected(store, passname)
72
- @passinfowidget.reinitialize_passfile(store, passname)
72
+ @passinfowidget.use_passfilecard(store, passname)
73
73
  end
74
74
 
75
75
  def _on_passlistwidget_passfolder_selected(store, passname)
76
- @passinfowidget.reinitialize_passfolder(store, passname)
76
+ @passinfowidget.use_passfoldercard(store, passname)
77
77
  end
78
78
  end
@@ -1,3 +1,3 @@
1
1
  module PassQt
2
- VERSION = "2.0.3"
2
+ VERSION = "2.0.4"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-pass-qt
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Doe
@@ -43,8 +43,12 @@ files:
43
43
  - lib/pass-qt/app/assets/app.svg
44
44
  - lib/pass-qt/app/components.rb
45
45
  - lib/pass-qt/app/components/passinfowidget.rb
46
+ - lib/pass-qt/app/components/passinfowidget/helpers.rb
46
47
  - lib/pass-qt/app/components/passlistwidget.rb
47
48
  - lib/pass-qt/app/components/passlistwidget/treewidget.rb
49
+ - lib/pass-qt/app/components/passlistwidget/treewidget/helpers.rb
50
+ - lib/pass-qt/app/components/passlistwidget/treewidget/treebuilder.rb
51
+ - lib/pass-qt/app/components/passlistwidget/treewidget/treefilter.rb
48
52
  - lib/pass-qt/app/views.rb
49
53
  - lib/pass-qt/app/views/browsestoresdialog.rb
50
54
  - lib/pass-qt/app/views/mainwindow.rb