1 #include "configdialog.h"
2 #include "keygendialog.h"
3 #include "mainwindow.h"
4 #include "qtpasssettings.h"
5 #include "ui_configdialog.h"
6 #include <QClipboard>
7 #include <QDir>
8 #include <QFileDialog>
9 #include <QMessageBox>
10 #include <QPushButton>
11 #include <QSystemTrayIcon>
12 #include <QTableWidgetItem>
13 #ifdef Q_OS_WIN
14 #include <windows.h>
15 #endif
16
17 #ifdef QT_DEBUG
18 #include "debughelper.h"
19 #endif
20
21 /**
22 * @brief ConfigDialog::ConfigDialog this sets up the configuration screen.
23 * @param parent
24 */
ConfigDialog(MainWindow * parent)25 ConfigDialog::ConfigDialog(MainWindow *parent)
26 : QDialog(parent), ui(new Ui::ConfigDialog) {
27 mainWindow = parent;
28 ui->setupUi(this);
29
30 ui->passPath->setText(QtPassSettings::getPassExecutable());
31 setGitPath(QtPassSettings::getGitExecutable());
32 ui->gpgPath->setText(QtPassSettings::getGpgExecutable());
33 ui->storePath->setText(QtPassSettings::getPassStore());
34
35 ui->spinBoxAutoclearSeconds->setValue(QtPassSettings::getAutoclearSeconds());
36 ui->spinBoxAutoclearPanelSeconds->setValue(
37 QtPassSettings::getAutoclearPanelSeconds());
38 ui->checkBoxHidePassword->setChecked(QtPassSettings::isHidePassword());
39 ui->checkBoxHideContent->setChecked(QtPassSettings::isHideContent());
40 ui->checkBoxAddGPGId->setChecked(QtPassSettings::isAddGPGId(true));
41
42 if (QSystemTrayIcon::isSystemTrayAvailable()) {
43 ui->checkBoxHideOnClose->setChecked(QtPassSettings::isHideOnClose());
44 ui->checkBoxStartMinimized->setChecked(QtPassSettings::isStartMinimized());
45 } else {
46 ui->checkBoxUseTrayIcon->setEnabled(false);
47 ui->checkBoxUseTrayIcon->setToolTip(tr("System tray is not available"));
48 ui->checkBoxHideOnClose->setEnabled(false);
49 ui->checkBoxStartMinimized->setEnabled(false);
50 }
51
52 ui->checkBoxAvoidCapitals->setChecked(QtPassSettings::isAvoidCapitals());
53 ui->checkBoxAvoidNumbers->setChecked(QtPassSettings::isAvoidNumbers());
54 ui->checkBoxLessRandom->setChecked(QtPassSettings::isLessRandom());
55 ui->checkBoxUseSymbols->setChecked(QtPassSettings::isUseSymbols());
56 ui->plainTextEditTemplate->setPlainText(QtPassSettings::getPassTemplate());
57 ui->checkBoxTemplateAllFields->setChecked(
58 QtPassSettings::isTemplateAllFields());
59 ui->checkBoxAutoPull->setChecked(QtPassSettings::isAutoPull());
60 ui->checkBoxAutoPush->setChecked(QtPassSettings::isAutoPush());
61 ui->checkBoxAlwaysOnTop->setChecked(QtPassSettings::isAlwaysOnTop());
62
63 #if defined(Q_OS_WIN) || defined(__APPLE__)
64 ui->checkBoxUseOtp->hide();
65 ui->checkBoxUseQrencode->hide();
66 ui->label_10->hide();
67 #endif
68
69 if (!isPassOtpAvailable()) {
70 ui->checkBoxUseOtp->setEnabled(false);
71 ui->checkBoxUseOtp->setToolTip(
72 tr("Pass OTP extension needs to be installed"));
73 }
74
75 if (!isQrencodeAvailable()) {
76 ui->checkBoxUseQrencode->setEnabled(false);
77 ui->checkBoxUseQrencode->setToolTip(tr("qrencode needs to be installed"));
78 }
79
80 setProfiles(QtPassSettings::getProfiles(), QtPassSettings::getProfile());
81 setPwgenPath(QtPassSettings::getPwgenExecutable());
82 setPasswordConfiguration(QtPassSettings::getPasswordConfiguration());
83
84 usePass(QtPassSettings::isUsePass());
85 useAutoclear(QtPassSettings::isUseAutoclear());
86 useAutoclearPanel(QtPassSettings::isUseAutoclearPanel());
87 useTrayIcon(QtPassSettings::isUseTrayIcon());
88 useGit(QtPassSettings::isUseGit());
89
90 useOtp(QtPassSettings::isUseOtp());
91 useQrencode(QtPassSettings::isUseQrencode());
92
93 usePwgen(QtPassSettings::isUsePwgen());
94 useTemplate(QtPassSettings::isUseTemplate());
95
96 ui->profileTable->verticalHeader()->hide();
97 ui->profileTable->horizontalHeader()->setStretchLastSection(true);
98 ui->label->setText(ui->label->text() + VERSION);
99 ui->comboBoxClipboard->clear();
100
101 ui->comboBoxClipboard->addItem(tr("No Clipboard"));
102 ui->comboBoxClipboard->addItem(tr("Always copy to clipboard"));
103 ui->comboBoxClipboard->addItem(tr("On-demand copy to clipboard"));
104
105 int currentIndex = QtPassSettings::getClipBoardTypeRaw();
106 ui->comboBoxClipboard->setCurrentIndex(currentIndex);
107 on_comboBoxClipboard_activated(currentIndex);
108
109 QClipboard *clip = QApplication::clipboard();
110 if (!clip->supportsSelection()) {
111 useSelection(false);
112 ui->checkBoxSelection->setVisible(false);
113 } else {
114 useSelection(QtPassSettings::isUseSelection());
115 }
116
117 if (Util::checkConfig()) {
118 // Show Programs tab, which is likely
119 // what the user needs to fix now.
120 ui->tabWidget->setCurrentIndex(1);
121 }
122
123 connect(ui->profileTable, &QTableWidget::itemChanged, this,
124 &ConfigDialog::onProfileTableItemChanged);
125 connect(this, &ConfigDialog::accepted, this, &ConfigDialog::on_accepted);
126 }
127
128 /**
129 * @brief ConfigDialog::~ConfigDialog config destructor, makes sure the
130 * mainWindow knows about git, gpg and pass executables.
131 */
~ConfigDialog()132 ConfigDialog::~ConfigDialog() {
133 QtPassSettings::setGitExecutable(ui->gitPath->text());
134 QtPassSettings::setGpgExecutable(ui->gpgPath->text());
135 QtPassSettings::setPassExecutable(ui->passPath->text());
136 }
137
138 /**
139 * @brief ConfigDialog::setGitPath set the git executable path.
140 * Make sure the checkBoxUseGit is updated.
141 * @param path
142 */
setGitPath(QString path)143 void ConfigDialog::setGitPath(QString path) {
144 ui->gitPath->setText(path);
145 ui->checkBoxUseGit->setEnabled(!path.isEmpty());
146 if (path.isEmpty()) {
147 useGit(false);
148 }
149 }
150
151 /**
152 * @brief ConfigDialog::usePass set wether or not we want to use pass.
153 * Update radio buttons accordingly.
154 * @param usePass
155 */
usePass(bool usePass)156 void ConfigDialog::usePass(bool usePass) {
157 ui->radioButtonNative->setChecked(!usePass);
158 ui->radioButtonPass->setChecked(usePass);
159 setGroupBoxState();
160 }
161
validate(QTableWidgetItem * item)162 void ConfigDialog::validate(QTableWidgetItem *item) {
163 bool status = true;
164
165 if (item == nullptr) {
166 for (int i = 0; i < ui->profileTable->rowCount(); i++) {
167 for (int j = 0; j < ui->profileTable->columnCount(); j++) {
168 QTableWidgetItem *_item = ui->profileTable->item(i, j);
169
170 if (_item->text().isEmpty()) {
171 _item->setBackground(Qt::red);
172 status = false;
173 break;
174 }
175 }
176
177 if (!status)
178 break;
179 }
180 } else {
181 if (item->text().isEmpty()) {
182 item->setBackground(Qt::red);
183 status = false;
184 }
185 }
186
187 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status);
188 }
189
on_accepted()190 void ConfigDialog::on_accepted() {
191 QtPassSettings::setPassExecutable(ui->passPath->text());
192 QtPassSettings::setGitExecutable(ui->gitPath->text());
193 QtPassSettings::setGpgExecutable(ui->gpgPath->text());
194 QtPassSettings::setPassStore(
195 Util::normalizeFolderPath(ui->storePath->text()));
196 QtPassSettings::setUsePass(ui->radioButtonPass->isChecked());
197 QtPassSettings::setClipBoardType(ui->comboBoxClipboard->currentIndex());
198 QtPassSettings::setUseSelection(ui->checkBoxSelection->isChecked());
199 QtPassSettings::setUseAutoclear(ui->checkBoxAutoclear->isChecked());
200 QtPassSettings::setAutoclearSeconds(ui->spinBoxAutoclearSeconds->value());
201 QtPassSettings::setUseAutoclearPanel(ui->checkBoxAutoclearPanel->isChecked());
202 QtPassSettings::setAutoclearPanelSeconds(
203 ui->spinBoxAutoclearPanelSeconds->value());
204 QtPassSettings::setHidePassword(ui->checkBoxHidePassword->isChecked());
205 QtPassSettings::setHideContent(ui->checkBoxHideContent->isChecked());
206 QtPassSettings::setAddGPGId(ui->checkBoxAddGPGId->isChecked());
207 QtPassSettings::setUseTrayIcon(ui->checkBoxUseTrayIcon->isEnabled() &&
208 ui->checkBoxUseTrayIcon->isChecked());
209 QtPassSettings::setHideOnClose(ui->checkBoxHideOnClose->isEnabled() &&
210 ui->checkBoxHideOnClose->isChecked());
211 QtPassSettings::setStartMinimized(ui->checkBoxStartMinimized->isEnabled() &&
212 ui->checkBoxStartMinimized->isChecked());
213 QtPassSettings::setProfiles(getProfiles());
214 QtPassSettings::setUseGit(ui->checkBoxUseGit->isChecked());
215 QtPassSettings::setUseOtp(ui->checkBoxUseOtp->isChecked());
216 QtPassSettings::setUseQrencode(ui->checkBoxUseQrencode->isChecked());
217 QtPassSettings::setPwgenExecutable(ui->pwgenPath->text());
218 QtPassSettings::setUsePwgen(ui->checkBoxUsePwgen->isChecked());
219 QtPassSettings::setAvoidCapitals(ui->checkBoxAvoidCapitals->isChecked());
220 QtPassSettings::setAvoidNumbers(ui->checkBoxAvoidNumbers->isChecked());
221 QtPassSettings::setLessRandom(ui->checkBoxLessRandom->isChecked());
222 QtPassSettings::setUseSymbols(ui->checkBoxUseSymbols->isChecked());
223 QtPassSettings::setPasswordConfiguration(getPasswordConfiguration());
224 QtPassSettings::setUseTemplate(ui->checkBoxUseTemplate->isChecked());
225 QtPassSettings::setPassTemplate(ui->plainTextEditTemplate->toPlainText());
226 QtPassSettings::setTemplateAllFields(
227 ui->checkBoxTemplateAllFields->isChecked());
228 QtPassSettings::setAutoPush(ui->checkBoxAutoPush->isChecked());
229 QtPassSettings::setAutoPull(ui->checkBoxAutoPull->isChecked());
230 QtPassSettings::setAlwaysOnTop(ui->checkBoxAlwaysOnTop->isChecked());
231
232 QtPassSettings::setVersion(VERSION);
233 }
234
on_autodetectButton_clicked()235 void ConfigDialog::on_autodetectButton_clicked() {
236 QString pass = Util::findBinaryInPath("pass");
237 if (!pass.isEmpty())
238 ui->passPath->setText(pass);
239 usePass(!pass.isEmpty());
240 QString gpg = Util::findBinaryInPath("gpg2");
241 if (gpg.isEmpty())
242 gpg = Util::findBinaryInPath("gpg");
243 if (!gpg.isEmpty())
244 ui->gpgPath->setText(gpg);
245 QString git = Util::findBinaryInPath("git");
246 if (!git.isEmpty())
247 ui->gitPath->setText(git);
248 QString pwgen = Util::findBinaryInPath("pwgen");
249 if (!pwgen.isEmpty())
250 ui->pwgenPath->setText(pwgen);
251 }
252
253 /**
254 * @brief ConfigDialog::on_radioButtonNative_clicked wrapper for
255 * ConfigDialog::setGroupBoxState()
256 */
on_radioButtonNative_clicked()257 void ConfigDialog::on_radioButtonNative_clicked() { setGroupBoxState(); }
258
259 /**
260 * @brief ConfigDialog::on_radioButtonPass_clicked wrapper for
261 * ConfigDialog::setGroupBoxState()
262 */
on_radioButtonPass_clicked()263 void ConfigDialog::on_radioButtonPass_clicked() { setGroupBoxState(); }
264
265 /**
266 * @brief ConfigDialog::getSecretKeys get list of secret/private keys
267 * @return QStringList keys
268 */
getSecretKeys()269 QStringList ConfigDialog::getSecretKeys() {
270 QList<UserInfo> keys = QtPassSettings::getPass()->listKeys("", true);
271 QStringList names;
272
273 if (keys.empty())
274 return names;
275
276 foreach (const UserInfo &sec, keys)
277 names << sec.name;
278
279 return names;
280 }
281
282 /**
283 * @brief ConfigDialog::setGroupBoxState update checkboxes.
284 */
setGroupBoxState()285 void ConfigDialog::setGroupBoxState() {
286 bool state = ui->radioButtonPass->isChecked();
287 ui->groupBoxNative->setEnabled(!state);
288 ui->groupBoxPass->setEnabled(state);
289 }
290
291 /**
292 * @brief ConfigDialog::selectExecutable pop-up to choose an executable.
293 * @return
294 */
selectExecutable()295 QString ConfigDialog::selectExecutable() {
296 QFileDialog dialog(this);
297 dialog.setFileMode(QFileDialog::ExistingFile);
298 dialog.setOption(QFileDialog::ReadOnly);
299 if (dialog.exec())
300 return dialog.selectedFiles().first();
301
302 return QString();
303 }
304
305 /**
306 * @brief ConfigDialog::selectFolder pop-up to choose a folder.
307 * @return
308 */
selectFolder()309 QString ConfigDialog::selectFolder() {
310 QFileDialog dialog(this);
311 dialog.setFileMode(QFileDialog::Directory);
312 dialog.setFilter(QDir::NoFilter);
313 dialog.setOption(QFileDialog::ShowDirsOnly);
314 if (dialog.exec())
315 return dialog.selectedFiles().first();
316
317 return QString();
318 }
319
320 /**
321 * @brief ConfigDialog::on_toolButtonGit_clicked get git application.
322 * Enable checkboxes if found.
323 */
on_toolButtonGit_clicked()324 void ConfigDialog::on_toolButtonGit_clicked() {
325 QString git = selectExecutable();
326 bool state = !git.isEmpty();
327 if (state) {
328 ui->gitPath->setText(git);
329 } else {
330 useGit(false);
331 }
332
333 ui->checkBoxUseGit->setEnabled(state);
334 }
335
336 /**
337 * @brief ConfigDialog::on_toolButtonGpg_clicked get gpg application.
338 */
on_toolButtonGpg_clicked()339 void ConfigDialog::on_toolButtonGpg_clicked() {
340 QString gpg = selectExecutable();
341 if (!gpg.isEmpty())
342 ui->gpgPath->setText(gpg);
343 }
344
345 /**
346 * @brief ConfigDialog::on_toolButtonPass_clicked get pass application.
347 */
on_toolButtonPass_clicked()348 void ConfigDialog::on_toolButtonPass_clicked() {
349 QString pass = selectExecutable();
350 if (!pass.isEmpty())
351 ui->passPath->setText(pass);
352 }
353
354 /**
355 * @brief ConfigDialog::on_toolButtonStore_clicked get .password-store
356 * location.s
357 */
on_toolButtonStore_clicked()358 void ConfigDialog::on_toolButtonStore_clicked() {
359 QString store = selectFolder();
360 if (!store.isEmpty()) // TODO(annejan) call check
361 ui->storePath->setText(store);
362 }
363
364 /**
365 * @brief ConfigDialog::on_comboBoxClipboard_activated show and hide options.
366 * @param index of selectbox (0 = no clipboard).
367 */
on_comboBoxClipboard_activated(int index)368 void ConfigDialog::on_comboBoxClipboard_activated(int index) {
369 bool state = index > 0;
370
371 ui->checkBoxSelection->setEnabled(state);
372 ui->checkBoxAutoclear->setEnabled(state);
373 ui->checkBoxHidePassword->setEnabled(state);
374 ui->checkBoxHideContent->setEnabled(state);
375 if (state) {
376 ui->spinBoxAutoclearSeconds->setEnabled(ui->checkBoxAutoclear->isChecked());
377 ui->labelSeconds->setEnabled(ui->checkBoxAutoclear->isChecked());
378 } else {
379 ui->spinBoxAutoclearSeconds->setEnabled(false);
380 ui->labelSeconds->setEnabled(false);
381 }
382 }
383
384 /**
385 * @brief ConfigDialog::on_checkBoxAutoclearPanel_clicked enable and disable
386 * options based on autoclear use.
387 */
on_checkBoxAutoclearPanel_clicked()388 void ConfigDialog::on_checkBoxAutoclearPanel_clicked() {
389 bool state = ui->checkBoxAutoclearPanel->isChecked();
390 ui->spinBoxAutoclearPanelSeconds->setEnabled(state);
391 ui->labelPanelSeconds->setEnabled(state);
392 }
393
394 /**
395 * @brief ConfigDialog::useSelection set the clipboard type use from
396 * MainWindow.
397 * @param useSelection
398 */
useSelection(bool useSelection)399 void ConfigDialog::useSelection(bool useSelection) {
400 ui->checkBoxSelection->setChecked(useSelection);
401 on_checkBoxSelection_clicked();
402 }
403
404 /**
405 * @brief ConfigDialog::useAutoclear set the clipboard autoclear use from
406 * MainWindow.
407 * @param useAutoclear
408 */
useAutoclear(bool useAutoclear)409 void ConfigDialog::useAutoclear(bool useAutoclear) {
410 ui->checkBoxAutoclear->setChecked(useAutoclear);
411 on_checkBoxAutoclear_clicked();
412 }
413
414 /**
415 * @brief ConfigDialog::useAutoclearPanel set the panel autoclear use from
416 * MainWindow.
417 * @param useAutoclearPanel
418 */
useAutoclearPanel(bool useAutoclearPanel)419 void ConfigDialog::useAutoclearPanel(bool useAutoclearPanel) {
420 ui->checkBoxAutoclearPanel->setChecked(useAutoclearPanel);
421 on_checkBoxAutoclearPanel_clicked();
422 }
423
424 /**
425 * @brief ConfigDialog::on_checkBoxSelection_clicked checkbox clicked, update
426 * state via ConfigDialog::on_comboBoxClipboard_activated
427 */
on_checkBoxSelection_clicked()428 void ConfigDialog::on_checkBoxSelection_clicked() {
429 on_comboBoxClipboard_activated(ui->comboBoxClipboard->currentIndex());
430 }
431
432 /**
433 * @brief ConfigDialog::on_checkBoxAutoclear_clicked checkbox clicked, update
434 * state via ConfigDialog::on_comboBoxClipboard_activated
435 */
on_checkBoxAutoclear_clicked()436 void ConfigDialog::on_checkBoxAutoclear_clicked() {
437 on_comboBoxClipboard_activated(ui->comboBoxClipboard->currentIndex());
438 }
439
440 /**
441 * @brief ConfigDialog::genKey tunnel function to make MainWindow generate a
442 * gpg key pair.
443 * @todo refactor the process to not be entangled so much.
444 * @param batch
445 * @param dialog
446 */
genKey(QString batch,QDialog * dialog)447 void ConfigDialog::genKey(QString batch, QDialog *dialog) {
448 mainWindow->generateKeyPair(batch, dialog);
449 }
450
451 /**
452 * @brief ConfigDialog::setProfiles set the profiles and chosen profile from
453 * MainWindow.
454 * @param profiles
455 * @param profile
456 */
setProfiles(QHash<QString,QString> profiles,QString profile)457 void ConfigDialog::setProfiles(QHash<QString, QString> profiles,
458 QString profile) {
459 // dbg()<< profiles;
460 if (profiles.contains("")) {
461 profiles.remove("");
462 // remove weird "" key value pairs
463 }
464
465 ui->profileTable->setRowCount(profiles.count());
466 QHashIterator<QString, QString> i(profiles);
467 int n = 0;
468 while (i.hasNext()) {
469 i.next();
470 if (!i.value().isEmpty() && !i.key().isEmpty()) {
471 ui->profileTable->setItem(n, 0, new QTableWidgetItem(i.key()));
472 ui->profileTable->setItem(n, 1, new QTableWidgetItem(i.value()));
473 // dbg()<< "naam:" + i.key();
474 if (i.key() == profile)
475 ui->profileTable->selectRow(n);
476 }
477 ++n;
478 }
479 }
480
481 /**
482 * @brief ConfigDialog::getProfiles return profile list.
483 * @return
484 */
getProfiles()485 QHash<QString, QString> ConfigDialog::getProfiles() {
486 QHash<QString, QString> profiles;
487 // Check?
488 for (int i = 0; i < ui->profileTable->rowCount(); ++i) {
489 QTableWidgetItem *pathItem = ui->profileTable->item(i, 1);
490 if (nullptr != pathItem) {
491 QTableWidgetItem *item = ui->profileTable->item(i, 0);
492 if (item == nullptr) {
493 continue;
494 }
495 profiles.insert(item->text(), pathItem->text());
496 }
497 }
498 return profiles;
499 }
500
501 /**
502 * @brief ConfigDialog::on_addButton_clicked add a profile row.
503 */
on_addButton_clicked()504 void ConfigDialog::on_addButton_clicked() {
505 int n = ui->profileTable->rowCount();
506 ui->profileTable->insertRow(n);
507 ui->profileTable->setItem(n, 0, new QTableWidgetItem());
508 ui->profileTable->setItem(n, 1, new QTableWidgetItem(ui->storePath->text()));
509 ui->profileTable->selectRow(n);
510 ui->deleteButton->setEnabled(true);
511
512 validate();
513 }
514
515 /**
516 * @brief ConfigDialog::on_deleteButton_clicked remove a profile row.
517 */
on_deleteButton_clicked()518 void ConfigDialog::on_deleteButton_clicked() {
519 QSet<int> selectedRows; // we use a set to prevent doubles
520 QList<QTableWidgetItem *> itemList = ui->profileTable->selectedItems();
521 if (itemList.count() == 0) {
522 QMessageBox::warning(this, tr("No profile selected"),
523 tr("No profile selected to delete"));
524 return;
525 }
526 QTableWidgetItem *item;
527 foreach (item, itemList)
528 selectedRows.insert(item->row());
529 // get a list, and sort it big to small
530 QList<int> rows = selectedRows.toList();
531 std::sort(rows.begin(), rows.end());
532 // now actually do the removing:
533 foreach (int row, rows)
534 ui->profileTable->removeRow(row);
535 if (ui->profileTable->rowCount() < 1)
536 ui->deleteButton->setEnabled(false);
537
538 validate();
539 }
540
541 /**
542 * @brief ConfigDialog::criticalMessage weapper for showing critical messages
543 * in a popup.
544 * @param title
545 * @param text
546 */
criticalMessage(const QString & title,const QString & text)547 void ConfigDialog::criticalMessage(const QString &title, const QString &text) {
548 QMessageBox::critical(this, title, text, QMessageBox::Ok, QMessageBox::Ok);
549 }
550
isQrencodeAvailable()551 bool ConfigDialog::isQrencodeAvailable() {
552 #ifdef Q_OS_WIN
553 return false;
554 #elif defined(__APPLE__)
555 return false;
556 #else
557 QProcess which;
558 which.start("which", QStringList() << "qrencode");
559 which.waitForFinished();
560 return which.exitCode() == 0;
561 #endif
562 }
563
isPassOtpAvailable()564 bool ConfigDialog::isPassOtpAvailable() {
565 #ifdef Q_OS_WIN
566 return false;
567 #elif defined(__APPLE__)
568 return false;
569 #else
570 QFileInfo file("/usr/lib/password-store/extensions/otp.bash");
571
572 return file.exists();
573 #endif
574 }
575
576 /**
577 * @brief ConfigDialog::wizard first-time use wizard.
578 * @todo make this thing more reliable.
579 */
wizard()580 void ConfigDialog::wizard() {
581 // mainWindow->checkConfig();
582 bool clean = false;
583
584 QString gpg = ui->gpgPath->text();
585 // QString gpg = mainWindow->getGpgExecutable();
586 if (!gpg.startsWith("wsl ") && !QFile(gpg).exists()) {
587 criticalMessage(
588 tr("GnuPG not found"),
589 #ifdef Q_OS_WIN
590 #ifdef WINSTORE
591 tr("Please install GnuPG on your system.<br>Install "
592 "<strong>Ubuntu</strong> from the Microsoft Store to get it.<br>"
593 "If you already did so, make sure you started it once and<br>"
594 "click \"Autodetect\" in the next dialog.")
595 #else
596 tr("Please install GnuPG on your system.<br>Install "
597 "<strong>Ubuntu</strong> from the Microsoft Store<br>or <a "
598 "href=\"https://www.gnupg.org/download/#sec-1-2\">download</a> it "
599 "from GnuPG.org")
600 #endif
601 #else
602 tr("Please install GnuPG on your system.<br>Install "
603 "<strong>gpg</strong> using your favorite package manager<br>or "
604 "<a "
605 "href=\"https://www.gnupg.org/download/#sec-1-2\">download</a> it "
606 "from GnuPG.org")
607 #endif
608 );
609 clean = true;
610 }
611
612 QStringList names = getSecretKeys();
613
614 #ifdef QT_DEBUG
615 dbg() << names;
616 #endif
617
618 if ((gpg.startsWith("wsl ") || QFile(gpg).exists()) && names.empty()) {
619 KeygenDialog d(this);
620 if (!d.exec())
621 return;
622 }
623
624 QString passStore = ui->storePath->text();
625
626 if (!QFile(passStore).exists()) {
627 // TODO(annejan) pass version?
628 if (QMessageBox::question(
629 this, tr("Create password-store?"),
630 tr("Would you like to create a password-store at %1?")
631 .arg(passStore),
632 QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
633 QDir().mkdir(passStore);
634 #ifdef Q_OS_WIN
635 SetFileAttributes(passStore.toStdWString().c_str(),
636 FILE_ATTRIBUTE_HIDDEN);
637 #endif
638 if (ui->checkBoxUseGit->isChecked())
639 emit mainWindow->passGitInitNeeded();
640 mainWindow->userDialog(passStore);
641 }
642 }
643
644 if (!QFile(QDir(passStore).filePath(".gpg-id")).exists()) {
645 #ifdef QT_DEBUG
646 dbg() << ".gpg-id file does not exist";
647 #endif
648 if (!clean) {
649 criticalMessage(tr("Password store not initialised"),
650 tr("The folder %1 doesn't seem to be a password store or "
651 "is not yet initialised.")
652 .arg(passStore));
653 }
654 while (!QFile(passStore).exists()) {
655 on_toolButtonStore_clicked();
656 // allow user to cancel
657 if (passStore == ui->storePath->text())
658 return;
659 passStore = ui->storePath->text();
660 }
661 if (!QFile(passStore + ".gpg-id").exists()) {
662 #ifdef QT_DEBUG
663 dbg() << ".gpg-id file still does not exist :/";
664 #endif
665 // appears not to be store
666 // init yes / no ?
667 mainWindow->userDialog(passStore);
668 }
669 }
670 }
671
672 /**
673 * @brief ConfigDialog::useTrayIcon set preference for using trayicon.
674 * Enable or disable related checkboxes accordingly.
675 * @param useSystray
676 */
useTrayIcon(bool useSystray)677 void ConfigDialog::useTrayIcon(bool useSystray) {
678 if (QSystemTrayIcon::isSystemTrayAvailable()) {
679 ui->checkBoxUseTrayIcon->setChecked(useSystray);
680 ui->checkBoxHideOnClose->setEnabled(useSystray);
681 ui->checkBoxStartMinimized->setEnabled(useSystray);
682
683 if (!useSystray) {
684 ui->checkBoxHideOnClose->setChecked(false);
685 ui->checkBoxStartMinimized->setChecked(false);
686 }
687 }
688 }
689
690 /**
691 * @brief ConfigDialog::on_checkBoxUseTrayIcon_clicked enable and disable
692 * related checkboxes.
693 */
on_checkBoxUseTrayIcon_clicked()694 void ConfigDialog::on_checkBoxUseTrayIcon_clicked() {
695 bool state = ui->checkBoxUseTrayIcon->isChecked();
696 ui->checkBoxHideOnClose->setEnabled(state);
697 ui->checkBoxStartMinimized->setEnabled(state);
698 }
699
700 /**
701 * @brief ConfigDialog::closeEvent close this window.
702 * @param event
703 */
closeEvent(QCloseEvent * event)704 void ConfigDialog::closeEvent(QCloseEvent *event) {
705 // TODO(annejan) save window size or something?
706 event->accept();
707 }
708
709 /**
710 * @brief ConfigDialog::useGit set preference for using git.
711 * @param useGit
712 */
useGit(bool useGit)713 void ConfigDialog::useGit(bool useGit) {
714 ui->checkBoxUseGit->setChecked(useGit);
715 on_checkBoxUseGit_clicked();
716 }
717
718 /**
719 * @brief ConfigDialog::useOtp set preference for using otp plugin.
720 * @param useOtp
721 */
useOtp(bool useOtp)722 void ConfigDialog::useOtp(bool useOtp) {
723 ui->checkBoxUseOtp->setChecked(useOtp);
724 }
725
726 /**
727 * @brief ConfigDialog::useOtp set preference for using otp plugin.
728 * @param useOtp
729 */
useQrencode(bool useQrencode)730 void ConfigDialog::useQrencode(bool useQrencode) {
731 ui->checkBoxUseQrencode->setChecked(useQrencode);
732 }
733
734 /**
735 * @brief ConfigDialog::on_checkBoxUseGit_clicked enable or disable related
736 * checkboxes.
737 */
on_checkBoxUseGit_clicked()738 void ConfigDialog::on_checkBoxUseGit_clicked() {
739 ui->checkBoxAddGPGId->setEnabled(ui->checkBoxUseGit->isChecked());
740 ui->checkBoxAutoPull->setEnabled(ui->checkBoxUseGit->isChecked());
741 ui->checkBoxAutoPush->setEnabled(ui->checkBoxUseGit->isChecked());
742 }
743
744 /**
745 * @brief ConfigDialog::on_toolButtonPwgen_clicked enable or disable related
746 * options in the interface.
747 */
on_toolButtonPwgen_clicked()748 void ConfigDialog::on_toolButtonPwgen_clicked() {
749 QString pwgen = selectExecutable();
750 if (!pwgen.isEmpty()) {
751 ui->pwgenPath->setText(pwgen);
752 ui->checkBoxUsePwgen->setEnabled(true);
753 } else {
754 ui->checkBoxUsePwgen->setEnabled(false);
755 ui->checkBoxUsePwgen->setChecked(false);
756 }
757 }
758
759 /**
760 * @brief ConfigDialog::setPwgenPath set pwgen executable path.
761 * Enable or disable related options in the interface.
762 * @param pwgen
763 */
setPwgenPath(QString pwgen)764 void ConfigDialog::setPwgenPath(QString pwgen) {
765 ui->pwgenPath->setText(pwgen);
766 if (pwgen.isEmpty()) {
767 ui->checkBoxUsePwgen->setChecked(false);
768 ui->checkBoxUsePwgen->setEnabled(false);
769 }
770 on_checkBoxUsePwgen_clicked();
771 }
772
773 /**
774 * @brief ConfigDialog::on_checkBoxUsPwgen_clicked enable or disable related
775 * options in the interface.
776 */
on_checkBoxUsePwgen_clicked()777 void ConfigDialog::on_checkBoxUsePwgen_clicked() {
778 bool usePwgen = ui->checkBoxUsePwgen->isChecked();
779 ui->checkBoxAvoidCapitals->setEnabled(usePwgen);
780 ui->checkBoxAvoidNumbers->setEnabled(usePwgen);
781 ui->checkBoxLessRandom->setEnabled(usePwgen);
782 ui->checkBoxUseSymbols->setEnabled(usePwgen);
783 ui->lineEditPasswordChars->setEnabled(!usePwgen);
784 ui->labelPasswordChars->setEnabled(!usePwgen);
785 ui->passwordCharTemplateSelector->setEnabled(!usePwgen);
786 }
787
788 /**
789 * @brief ConfigDialog::usePwgen set preference for using pwgen (can be
790 * overruled buy empty pwgenPath).
791 * enable or disable related options in the interface via
792 * ConfigDialog::on_checkBoxUsePwgen_clicked
793 * @param usePwgen
794 */
usePwgen(bool usePwgen)795 void ConfigDialog::usePwgen(bool usePwgen) {
796 if (ui->pwgenPath->text().isEmpty())
797 usePwgen = false;
798 ui->checkBoxUsePwgen->setChecked(usePwgen);
799 on_checkBoxUsePwgen_clicked();
800 }
801
setPasswordConfiguration(const PasswordConfiguration & config)802 void ConfigDialog::setPasswordConfiguration(
803 const PasswordConfiguration &config) {
804 ui->spinBoxPasswordLength->setValue(config.length);
805 ui->passwordCharTemplateSelector->setCurrentIndex(config.selected);
806 if (config.selected != PasswordConfiguration::CUSTOM)
807 ui->lineEditPasswordChars->setEnabled(false);
808 ui->lineEditPasswordChars->setText(config.Characters[config.selected]);
809 }
810
getPasswordConfiguration()811 PasswordConfiguration ConfigDialog::getPasswordConfiguration() {
812 PasswordConfiguration config;
813 config.length = ui->spinBoxPasswordLength->value();
814 config.selected = static_cast<PasswordConfiguration::characterSet>(
815 ui->passwordCharTemplateSelector->currentIndex());
816 config.Characters[PasswordConfiguration::CUSTOM] =
817 ui->lineEditPasswordChars->text();
818 return config;
819 }
820
821 /**
822 * @brief ConfigDialog::on_passwordCharTemplateSelector_activated sets the
823 * passwordChar Template
824 * combo box to the desired entry
825 * @param entry of
826 */
on_passwordCharTemplateSelector_activated(int index)827 void ConfigDialog::on_passwordCharTemplateSelector_activated(int index) {
828 ui->lineEditPasswordChars->setText(
829 QtPassSettings::getPasswordConfiguration().Characters[index]);
830 if (index == 3) {
831 ui->lineEditPasswordChars->setEnabled(true);
832 } else {
833 ui->lineEditPasswordChars->setEnabled(false);
834 }
835 }
836
837 /**
838 * @brief ConfigDialog::on_checkBoxUseTemplate_clicked enable or disable the
839 * template field and options.
840 */
on_checkBoxUseTemplate_clicked()841 void ConfigDialog::on_checkBoxUseTemplate_clicked() {
842 ui->plainTextEditTemplate->setEnabled(ui->checkBoxUseTemplate->isChecked());
843 ui->checkBoxTemplateAllFields->setEnabled(
844 ui->checkBoxUseTemplate->isChecked());
845 }
846
onProfileTableItemChanged(QTableWidgetItem * item)847 void ConfigDialog::onProfileTableItemChanged(QTableWidgetItem *item) {
848 validate(item);
849 }
850
851 /**
852 * @brief ConfigDialog::useTemplate set preference for using templates.
853 * @param useTemplate
854 */
useTemplate(bool useTemplate)855 void ConfigDialog::useTemplate(bool useTemplate) {
856 ui->checkBoxUseTemplate->setChecked(useTemplate);
857 on_checkBoxUseTemplate_clicked();
858 }
859