QtPass 1.6.0
Multi-platform GUI for pass, the standard unix password manager.
Loading...
Searching...
No Matches
configdialog.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2014 Anne Jan Brouwer
2// SPDX-License-Identifier: GPL-3.0-or-later
3#include "configdialog.h"
4#include "keygendialog.h"
5#include "mainwindow.h"
6#include "profileinit.h"
7#include "qtpasssettings.h"
8#include "ui_configdialog.h"
9#include "usersdialog.h"
10#include "util.h"
11#include <QClipboard>
12#include <QDir>
13#include <QFileDialog>
14#include <QMessageBox>
15#include <QPushButton>
16#include <QSystemTrayIcon>
17#include <QTableWidgetItem>
18#include <utility>
19#ifdef Q_OS_WIN
20#include <windows.h>
21#endif
22
23#ifdef QT_DEBUG
24#include "debughelper.h"
25#endif
26
32 : QDialog(parent), ui(new Ui::ConfigDialog) {
33 mainWindow = parent;
34 ui->setupUi(this);
35
36 // Restore dialog state
37 QByteArray savedGeometry = QtPassSettings::getDialogGeometry("configDialog");
38 bool hasSavedGeometry = !savedGeometry.isEmpty();
39 if (hasSavedGeometry) {
40 restoreGeometry(savedGeometry);
41 }
42 if (QtPassSettings::isDialogMaximized("configDialog")) {
43 showMaximized();
44 } else if (!hasSavedGeometry) {
45 // Let window manager handle positioning for first launch
46 }
47
48 ui->passPath->setText(QtPassSettings::getPassExecutable());
50 ui->gpgPath->setText(QtPassSettings::getGpgExecutable());
51 ui->storePath->setText(QtPassSettings::getPassStore());
52
53 ui->spinBoxAutoclearSeconds->setValue(QtPassSettings::getAutoclearSeconds());
54 ui->spinBoxAutoclearPanelSeconds->setValue(
56 ui->checkBoxHidePassword->setChecked(QtPassSettings::isHidePassword());
57 ui->checkBoxHideContent->setChecked(QtPassSettings::isHideContent());
58 ui->checkBoxUseMonospace->setChecked(QtPassSettings::isUseMonospace());
59 ui->checkBoxDisplayAsIs->setChecked(QtPassSettings::isDisplayAsIs());
60 ui->checkBoxNoLineWrapping->setChecked(QtPassSettings::isNoLineWrapping());
61 ui->checkBoxAddGPGId->setChecked(QtPassSettings::isAddGPGId(true));
62
63 if (QSystemTrayIcon::isSystemTrayAvailable()) {
64 ui->checkBoxHideOnClose->setChecked(QtPassSettings::isHideOnClose());
65 ui->checkBoxStartMinimized->setChecked(QtPassSettings::isStartMinimized());
66 } else {
67 ui->checkBoxUseTrayIcon->setEnabled(false);
68 ui->checkBoxUseTrayIcon->setToolTip(tr("System tray is not available"));
69 ui->checkBoxHideOnClose->setEnabled(false);
70 ui->checkBoxStartMinimized->setEnabled(false);
71 }
72
73 ui->checkBoxAvoidCapitals->setChecked(QtPassSettings::isAvoidCapitals());
74 ui->checkBoxAvoidNumbers->setChecked(QtPassSettings::isAvoidNumbers());
75 ui->checkBoxLessRandom->setChecked(QtPassSettings::isLessRandom());
76 ui->checkBoxUseSymbols->setChecked(QtPassSettings::isUseSymbols());
77 ui->plainTextEditTemplate->setPlainText(QtPassSettings::getPassTemplate());
78 ui->checkBoxTemplateAllFields->setChecked(
80 ui->checkBoxAutoPull->setChecked(QtPassSettings::isAutoPull());
81 ui->checkBoxAutoPush->setChecked(QtPassSettings::isAutoPush());
82 ui->checkBoxAlwaysOnTop->setChecked(QtPassSettings::isAlwaysOnTop());
83
84#if defined(Q_OS_WIN)
85 ui->checkBoxUseOtp->hide();
86 ui->checkBoxUseQrencode->hide();
87 ui->label_10->hide();
88#endif
89
90 if (!isPassOtpAvailable()) {
91 ui->checkBoxUseOtp->setEnabled(false);
92 ui->checkBoxUseOtp->setToolTip(
93 tr("Pass OTP extension needs to be installed"));
94 }
95
96 if (!isQrencodeAvailable()) {
97 ui->checkBoxUseQrencode->setEnabled(false);
98 ui->checkBoxUseQrencode->setToolTip(tr("qrencode needs to be installed"));
99 }
100
104
105 usePass(QtPassSettings::isUsePass());
110
114
117
118 ui->profileTable->verticalHeader()->hide();
119 ui->profileTable->horizontalHeader()->setSectionResizeMode(
120 1, QHeaderView::Stretch);
121 ui->label->setText(ui->label->text() + VERSION);
122 ui->comboBoxClipboard->clear();
123
124 ui->comboBoxClipboard->addItem(tr("No Clipboard"));
125 ui->comboBoxClipboard->addItem(tr("Always copy to clipboard"));
126 ui->comboBoxClipboard->addItem(tr("On-demand copy to clipboard"));
127
128 int currentIndex = QtPassSettings::getClipBoardTypeRaw();
129 ui->comboBoxClipboard->setCurrentIndex(currentIndex);
130 on_comboBoxClipboard_activated(currentIndex);
131
132 QClipboard *clip = QApplication::clipboard();
133 if (!clip->supportsSelection()) {
134 useSelection(false);
135 ui->checkBoxSelection->setVisible(false);
136 } else {
138 }
139
140 if (!Util::configIsValid()) {
141 // Show Programs tab, which is likely
142 // what the user needs to fix now.
143 ui->tabWidget->setCurrentIndex(1);
144 }
145
146 connect(ui->profileTable, &QTableWidget::itemChanged, this,
147 &ConfigDialog::onProfileTableItemChanged);
148 connect(this, &ConfigDialog::accepted, this, &ConfigDialog::on_accepted);
149}
150
156 QtPassSettings::setGitExecutable(ui->gitPath->text());
157 QtPassSettings::setGpgExecutable(ui->gpgPath->text());
158 QtPassSettings::setPassExecutable(ui->passPath->text());
159}
160
166void ConfigDialog::setGitPath(const QString &path) {
167 ui->gitPath->setText(path);
168 ui->checkBoxUseGit->setEnabled(!path.isEmpty());
169 if (path.isEmpty()) {
170 useGit(false);
171 }
172}
173
179void ConfigDialog::usePass(bool usePass) {
180 ui->radioButtonNative->setChecked(!usePass);
181 ui->radioButtonPass->setChecked(usePass);
182 setGroupBoxState();
183}
184
197void ConfigDialog::validate(QTableWidgetItem *item) {
198 bool status = true;
199
200 if (item == nullptr) {
201 for (int i = 0; i < ui->profileTable->rowCount(); i++) {
202 for (int j = 0; j < ui->profileTable->columnCount(); j++) {
203 QTableWidgetItem *_item = ui->profileTable->item(i, j);
204
205 if (_item->text().isEmpty() && j != 2) {
206 _item->setBackground(Qt::red);
207 _item->setToolTip(tr("This field is required"));
208 status = false;
209 break;
210 } else {
211 _item->setBackground(QBrush());
212 _item->setToolTip(QString());
213 }
214 }
215
216 if (!status) {
217 break;
218 }
219 }
220 } else {
221 if (item->text().isEmpty() && item->column() != 2) {
222 item->setBackground(Qt::red);
223 item->setToolTip(tr("This field is required"));
224 status = false;
225 } else {
226 item->setBackground(QBrush());
227 item->setToolTip(QString());
228 }
229 }
230
231 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status);
232}
233
245void ConfigDialog::on_accepted() {
246 QtPassSettings::setPassExecutable(ui->passPath->text());
247 QtPassSettings::setGitExecutable(ui->gitPath->text());
248 QtPassSettings::setGpgExecutable(ui->gpgPath->text());
250 Util::normalizeFolderPath(ui->storePath->text()));
251 QtPassSettings::setUsePass(ui->radioButtonPass->isChecked());
252 QtPassSettings::setClipBoardType(ui->comboBoxClipboard->currentIndex());
253 QtPassSettings::setUseSelection(ui->checkBoxSelection->isChecked());
254 QtPassSettings::setUseAutoclear(ui->checkBoxAutoclear->isChecked());
255 QtPassSettings::setAutoclearSeconds(ui->spinBoxAutoclearSeconds->value());
256 QtPassSettings::setUseAutoclearPanel(ui->checkBoxAutoclearPanel->isChecked());
258 ui->spinBoxAutoclearPanelSeconds->value());
259 QtPassSettings::setHidePassword(ui->checkBoxHidePassword->isChecked());
260 QtPassSettings::setHideContent(ui->checkBoxHideContent->isChecked());
261 QtPassSettings::setUseMonospace(ui->checkBoxUseMonospace->isChecked());
262 QtPassSettings::setDisplayAsIs(ui->checkBoxDisplayAsIs->isChecked());
263 QtPassSettings::setNoLineWrapping(ui->checkBoxNoLineWrapping->isChecked());
264 QtPassSettings::setAddGPGId(ui->checkBoxAddGPGId->isChecked());
265 QtPassSettings::setUseTrayIcon(ui->checkBoxUseTrayIcon->isEnabled() &&
266 ui->checkBoxUseTrayIcon->isChecked());
267 QtPassSettings::setHideOnClose(ui->checkBoxHideOnClose->isEnabled() &&
268 ui->checkBoxHideOnClose->isChecked());
269 QtPassSettings::setStartMinimized(ui->checkBoxStartMinimized->isEnabled() &&
270 ui->checkBoxStartMinimized->isChecked());
271 QHash<QString, QHash<QString, QString>> existingProfiles =
274 QtPassSettings::setUseGit(ui->checkBoxUseGit->isChecked());
275 QtPassSettings::setUseOtp(ui->checkBoxUseOtp->isChecked());
276 QtPassSettings::setUseGrepSearch(ui->checkBoxUseGrepSearch->isChecked());
277 QtPassSettings::setUseQrencode(ui->checkBoxUseQrencode->isChecked());
278 QtPassSettings::setPwgenExecutable(ui->pwgenPath->text());
279 QtPassSettings::setUsePwgen(ui->checkBoxUsePwgen->isChecked());
280 QtPassSettings::setAvoidCapitals(ui->checkBoxAvoidCapitals->isChecked());
281 QtPassSettings::setAvoidNumbers(ui->checkBoxAvoidNumbers->isChecked());
282 QtPassSettings::setLessRandom(ui->checkBoxLessRandom->isChecked());
283 QtPassSettings::setUseSymbols(ui->checkBoxUseSymbols->isChecked());
285 QtPassSettings::setUseTemplate(ui->checkBoxUseTemplate->isChecked());
286 QtPassSettings::setPassTemplate(ui->plainTextEditTemplate->toPlainText());
288 ui->checkBoxTemplateAllFields->isChecked());
289 QtPassSettings::setAutoPush(ui->checkBoxAutoPush->isChecked());
290 QtPassSettings::setAutoPull(ui->checkBoxAutoPull->isChecked());
291 QtPassSettings::setAlwaysOnTop(ui->checkBoxAlwaysOnTop->isChecked());
292
294
295 // Initialize new profiles that need pass/git initialization
296 initializeNewProfiles(existingProfiles);
297}
298
308void ConfigDialog::on_autodetectButton_clicked() {
309 QString pass = Util::findBinaryInPath("pass");
310 if (!pass.isEmpty()) {
311 ui->passPath->setText(pass);
312 }
313 usePass(!pass.isEmpty());
314 QString gpg = Util::findBinaryInPath("gpg2");
315 if (gpg.isEmpty()) {
316 gpg = Util::findBinaryInPath("gpg");
317 }
318 if (!gpg.isEmpty()) {
319 ui->gpgPath->setText(gpg);
320 }
321 QString git = Util::findBinaryInPath("git");
322 if (!git.isEmpty()) {
323 ui->gitPath->setText(git);
324 }
325 QString pwgen = Util::findBinaryInPath("pwgen");
326 if (!pwgen.isEmpty()) {
327 ui->pwgenPath->setText(pwgen);
328 }
329}
330
335void ConfigDialog::on_radioButtonNative_clicked() { setGroupBoxState(); }
336
341void ConfigDialog::on_radioButtonPass_clicked() { setGroupBoxState(); }
342
347auto ConfigDialog::getSecretKeys() -> QStringList {
348 QList<UserInfo> keys = QtPassSettings::getPass()->listKeys("", true);
349 QStringList names;
350
351 if (keys.empty()) {
352 return names;
353 }
354
355 foreach (const UserInfo &sec, keys)
356 names << sec.name;
357
358 return names;
359}
360
364void ConfigDialog::setGroupBoxState() {
365 bool state = ui->radioButtonPass->isChecked();
366 ui->groupBoxNative->setEnabled(!state);
367 ui->groupBoxPass->setEnabled(state);
368 if (state) {
369 // pass mode: disable all password generation controls
370 ui->spinBoxPasswordLength->setEnabled(false);
371 ui->checkBoxUsePwgen->setEnabled(false);
372 ui->checkBoxAvoidCapitals->setEnabled(false);
373 ui->checkBoxUseSymbols->setEnabled(false);
374 ui->checkBoxLessRandom->setEnabled(false);
375 ui->checkBoxAvoidNumbers->setEnabled(false);
376 ui->labelPasswordChars->setEnabled(false);
377 ui->passwordCharTemplateSelector->setEnabled(false);
378 ui->lineEditPasswordChars->setEnabled(false);
379 } else {
380 // native mode: restore pwgen/charset state from existing handlers
381 ui->spinBoxPasswordLength->setEnabled(true);
382 ui->checkBoxUsePwgen->setEnabled(!ui->pwgenPath->text().isEmpty());
383 on_checkBoxUsePwgen_clicked();
384 }
385}
386
391auto ConfigDialog::selectExecutable() -> QString {
392 QFileDialog dialog(this);
393 dialog.setFileMode(QFileDialog::ExistingFile);
394 dialog.setOption(QFileDialog::ReadOnly);
395 if (dialog.exec()) {
396 return dialog.selectedFiles().constFirst();
397 }
398
399 return {};
400}
401
406auto ConfigDialog::selectFolder() -> QString {
407 QFileDialog dialog(this);
408 dialog.setFileMode(QFileDialog::Directory);
409 dialog.setFilter(QDir::NoFilter);
410 dialog.setOption(QFileDialog::ShowDirsOnly);
411 if (dialog.exec()) {
412 return dialog.selectedFiles().constFirst();
413 }
414
415 return {};
416}
417
422void ConfigDialog::on_toolButtonGit_clicked() {
423 QString git = selectExecutable();
424 bool state = !git.isEmpty();
425 if (state) {
426 ui->gitPath->setText(git);
427 } else {
428 useGit(false);
429 }
430
431 ui->checkBoxUseGit->setEnabled(state);
432}
433
437void ConfigDialog::on_toolButtonGpg_clicked() {
438 QString gpg = selectExecutable();
439 if (!gpg.isEmpty()) {
440 ui->gpgPath->setText(gpg);
441 }
442}
443
447void ConfigDialog::on_pushButtonGenerateKey_clicked() {
448 KeygenDialog d(this);
449 d.exec();
450}
451
455void ConfigDialog::on_toolButtonPass_clicked() {
456 QString pass = selectExecutable();
457 if (!pass.isEmpty()) {
458 ui->passPath->setText(pass);
459 }
460}
461
466void ConfigDialog::on_toolButtonStore_clicked() {
467 QString store = selectFolder();
468 if (!store.isEmpty()) {
469 ui->storePath->setText(store);
470 }
471}
472
477void ConfigDialog::on_comboBoxClipboard_activated(int index) {
478 bool state = index > 0;
479
480 ui->checkBoxSelection->setEnabled(state);
481 ui->checkBoxAutoclear->setEnabled(state);
482 ui->checkBoxHidePassword->setEnabled(state);
483 ui->checkBoxHideContent->setEnabled(state);
484 if (state) {
485 ui->spinBoxAutoclearSeconds->setEnabled(ui->checkBoxAutoclear->isChecked());
486 ui->labelSeconds->setEnabled(ui->checkBoxAutoclear->isChecked());
487 } else {
488 ui->spinBoxAutoclearSeconds->setEnabled(false);
489 ui->labelSeconds->setEnabled(false);
490 }
491}
492
497void ConfigDialog::on_checkBoxAutoclearPanel_clicked() {
498 bool state = ui->checkBoxAutoclearPanel->isChecked();
499 ui->spinBoxAutoclearPanelSeconds->setEnabled(state);
500 ui->labelPanelSeconds->setEnabled(state);
501}
502
509 ui->checkBoxSelection->setChecked(useSelection);
510 on_checkBoxSelection_clicked();
511}
512
519 ui->checkBoxAutoclear->setChecked(useAutoclear);
520 on_checkBoxAutoclear_clicked();
521}
522
529 ui->checkBoxAutoclearPanel->setChecked(useAutoclearPanel);
530 on_checkBoxAutoclearPanel_clicked();
531}
532
537void ConfigDialog::on_checkBoxSelection_clicked() {
538 on_comboBoxClipboard_activated(ui->comboBoxClipboard->currentIndex());
539}
540
545void ConfigDialog::on_checkBoxAutoclear_clicked() {
546 on_comboBoxClipboard_activated(ui->comboBoxClipboard->currentIndex());
547}
548
555void ConfigDialog::genKey(const QString &batch, QDialog *dialog) {
556 mainWindow->generateKeyPair(batch, dialog);
557}
558
565void ConfigDialog::setProfiles(QHash<QString, QHash<QString, QString>> profiles,
566 const QString &currentProfile) {
567 if (profiles.contains("")) {
568 profiles.remove("");
569 // remove weird "" key value pairs
570 }
571
572 ui->profileTable->setRowCount(profiles.count());
573 QHashIterator<QString, QHash<QString, QString>> i(profiles);
574 int n = 0;
575 while (i.hasNext()) {
576 i.next();
577 if (!i.value().isEmpty() && !i.key().isEmpty()) {
578 ui->profileTable->setItem(n, 0, new QTableWidgetItem(i.key()));
579 ui->profileTable->setItem(n, 1,
580 new QTableWidgetItem(i.value().value("path")));
581 ui->profileTable->setItem(
582 n, 2, new QTableWidgetItem(i.value().value("signingKey")));
583 if (i.key() == currentProfile) {
584 ui->profileTable->selectRow(n);
585 }
586 }
587 ++n;
588 }
589}
590
595auto ConfigDialog::getProfiles() -> QHash<QString, QHash<QString, QString>> {
596 QHash<QString, QHash<QString, QString>> profiles;
597 // Check?
598 for (int i = 0; i < ui->profileTable->rowCount(); ++i) {
599 QHash<QString, QString> profile;
600 QTableWidgetItem *pathItem = ui->profileTable->item(i, 1);
601 if (nullptr != pathItem) {
602 QTableWidgetItem *item = ui->profileTable->item(i, 0);
603 if (item == nullptr) {
604 continue;
605 }
606 profile["path"] = pathItem->text();
607 QTableWidgetItem *signingKeyItem = ui->profileTable->item(i, 2);
608 if (nullptr != signingKeyItem) {
609 profile["signingKey"] = signingKeyItem->text();
610 }
611 profiles.insert(item->text(), profile);
612 }
613 }
614 return profiles;
615}
616
622void ConfigDialog::initializeNewProfiles(
623 const QHash<QString, QHash<QString, QString>> &existingProfiles) {
624 QHash<QString, QHash<QString, QString>> newProfiles = getProfiles();
625
626 // Collect keys and sort for deterministic iteration
627 QStringList keys = newProfiles.keys();
628 keys.sort();
629
630 for (const QString &name : keys) {
631 const QString &path = newProfiles.value(name).value("path");
632
633 // Skip if already existed before (check by name and path)
634 if (existingProfiles.contains(name) &&
635 existingProfiles.value(name).value("path") == path) {
636 continue;
637 }
638
639 // This is a new profile - check if needs initialization
640 // needsInit returns false for non-existent directories
641 if (!ProfileInit::needsInit(path)) {
642 continue;
643 }
644
645 // Temporarily switch the active store so pass/git init operate on
646 // the new profile's directory rather than the currently-saved one.
647 const QString prevStore = QtPassSettings::getPassStore();
649
650 // Show user selection dialog for GPG recipients
651 // UsersDialog will run pass init when accepted
652 UsersDialog usersDialog(path, this);
653 usersDialog.setWindowTitle(tr("Select recipients for %1").arg(name));
654 const int result = usersDialog.exec();
655
656 if (result == QDialog::Accepted && ui->checkBoxUseGit->isChecked()) {
657 QtPassSettings::getPass()->GitInit();
658 }
659
660 // Restore previous store setting
662 }
663}
664
668void ConfigDialog::on_addButton_clicked() {
669 int n = ui->profileTable->rowCount();
670 ui->profileTable->insertRow(n);
671 ui->profileTable->setItem(n, 0, new QTableWidgetItem(tr("New Profile")));
672 ui->profileTable->setItem(n, 1, new QTableWidgetItem(ui->storePath->text()));
673 ui->profileTable->setItem(n, 2, new QTableWidgetItem());
674 ui->profileTable->selectRow(n);
675 ui->deleteButton->setEnabled(true);
676
677 ui->profileTable->editItem(ui->profileTable->item(n, 0));
678 ui->profileTable->item(n, 0)->setSelected(true);
679
680 validate();
681}
682
687void ConfigDialog::on_profileTable_cellDoubleClicked(int row, int column) {
688 if (column == 1) {
689 QString dir = selectFolder();
690 if (!dir.isEmpty()) {
691 ui->profileTable->item(row, 1)->setText(dir);
692 }
693 }
694}
695
699void ConfigDialog::on_deleteButton_clicked() {
700 QSet<int> selectedRows; // we use a set to prevent doubles
701 QList<QTableWidgetItem *> itemList = ui->profileTable->selectedItems();
702 if (itemList.count() == 0) {
703 QMessageBox::warning(this, tr("No profile selected"),
704 tr("No profile selected to delete"));
705 return;
706 }
707 QTableWidgetItem *item;
708 foreach (item, itemList)
709 selectedRows.insert(item->row());
710 // get a list, and sort it big to small
711 QList<int> rows = selectedRows.values();
712 std::sort(rows.begin(), rows.end());
713 // now actually do the removing:
714 foreach (int row, rows)
715 ui->profileTable->removeRow(row);
716 if (ui->profileTable->rowCount() < 1) {
717 ui->deleteButton->setEnabled(false);
718 }
719
720 validate();
721}
722
729void ConfigDialog::criticalMessage(const QString &title, const QString &text) {
730 QMessageBox::critical(this, title, text, QMessageBox::Ok, QMessageBox::Ok);
731}
732
743auto ConfigDialog::isQrencodeAvailable() -> bool {
744#ifdef Q_OS_WIN
745 return false;
746#else
747 QProcess which;
748 which.start("which", QStringList() << "qrencode");
749 which.waitForFinished();
751 which.readAllStandardOutput().trimmed());
752 return which.exitCode() == 0;
753#endif
754}
755
756auto ConfigDialog::isPassOtpAvailable() -> bool {
757#ifdef Q_OS_WIN
758 return false;
759#else
760 QProcess pass;
761 pass.start(QtPassSettings::getPassExecutable(), QStringList() << "otp"
762 << "--help");
763 pass.waitForFinished(2000);
764 return pass.exitCode() == 0;
765#endif
766}
767
772 (void)Util::configIsValid();
773 on_autodetectButton_clicked();
774
775 if (!checkGpgExistence()) {
776 return;
777 }
778 if (!checkSecretKeys()) {
779 return;
780 }
781 if (!checkPasswordStore()) {
782 return;
783 }
784 handleGpgIdFile();
785
786 ui->checkBoxHidePassword->setCheckState(Qt::Checked);
787}
788
799auto ConfigDialog::checkGpgExistence() -> bool {
800 QString gpg = ui->gpgPath->text();
801 if (!gpg.startsWith("wsl ") && !QFile(gpg).exists()) {
802 criticalMessage(
803 tr("GnuPG not found"),
804#ifdef Q_OS_WIN
805#ifdef WINSTORE
806 tr("Please install GnuPG on your system.<br>Install "
807 "<strong>Ubuntu</strong> from the Microsoft Store to get it.<br>"
808 "If you already did so, make sure you started it once and<br>"
809 "click \"Autodetect\" in the next dialog.")
810#else
811 tr("Please install GnuPG on your system.<br>Install "
812 "<strong>Ubuntu</strong> from the Microsoft Store<br>or <a "
813 "href=\"https://www.gnupg.org/download/#sec-1-2\">download</a> it "
814 "from GnuPG.org")
815#endif
816#else
817 tr("Please install GnuPG on your system.<br>Install "
818 "<strong>gpg</strong> using your favorite package manager<br>or "
819 "<a "
820 "href=\"https://www.gnupg.org/download/#sec-1-2\">download</a> it "
821 "from GnuPG.org")
822#endif
823 );
824 return false;
825 }
826 return true;
827}
828
840auto ConfigDialog::checkSecretKeys() -> bool {
841 QString gpg = ui->gpgPath->text();
842 QStringList names = getSecretKeys();
843
844#ifdef QT_DEBUG
845 dbg() << names;
846#endif
847
848 if ((gpg.startsWith("wsl ") || QFile(gpg).exists()) && names.empty()) {
849 KeygenDialog d(this);
850 return d.exec();
851 }
852 return true;
853}
854
866auto ConfigDialog::checkPasswordStore() -> bool {
867 QString passStore = ui->storePath->text();
868
869 if (!QFile(passStore).exists()) {
870 if (QMessageBox::question(
871 this, tr("Create password-store?"),
872 tr("Would you like to create a password-store at %1?")
873 .arg(passStore),
874 QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
875 if (!QDir().mkdir(passStore)) {
876 QMessageBox::warning(
877 this, tr("Error"),
878 tr("Failed to create password-store at: %1").arg(passStore));
879 return false;
880 }
881#ifdef Q_OS_WIN
882 SetFileAttributes(passStore.toStdWString().c_str(),
883 FILE_ATTRIBUTE_HIDDEN);
884#endif
885 if (ui->checkBoxUseGit->isChecked()) {
886 emit mainWindow->passGitInitNeeded();
887 }
888 mainWindow->userDialog(passStore);
889 }
890 }
891 return true;
892}
893
903void ConfigDialog::handleGpgIdFile() {
904 QString passStore = ui->storePath->text();
905 if (!QFile(QDir(passStore).filePath(".gpg-id")).exists()) {
906#ifdef QT_DEBUG
907 dbg() << ".gpg-id file does not exist";
908#endif
909 criticalMessage(tr("Password store not initialised"),
910 tr("The folder %1 doesn't seem to be a password store or "
911 "is not yet initialised.")
912 .arg(passStore));
913
914 while (!QFile(passStore).exists()) {
915 on_toolButtonStore_clicked();
916 if (passStore == ui->storePath->text()) {
917 return;
918 }
919 passStore = ui->storePath->text();
920 }
921 if (!QFile(passStore + ".gpg-id").exists()) {
922#ifdef QT_DEBUG
923 dbg() << ".gpg-id file still does not exist :/";
924#endif
925 mainWindow->userDialog(passStore);
926 }
927 }
928}
929
935void ConfigDialog::useTrayIcon(bool useSystray) {
936 if (QSystemTrayIcon::isSystemTrayAvailable()) {
937 ui->checkBoxUseTrayIcon->setChecked(useSystray);
938 ui->checkBoxHideOnClose->setEnabled(useSystray);
939 ui->checkBoxStartMinimized->setEnabled(useSystray);
940
941 if (!useSystray) {
942 ui->checkBoxHideOnClose->setChecked(false);
943 ui->checkBoxStartMinimized->setChecked(false);
944 }
945 }
946}
947
952void ConfigDialog::on_checkBoxUseTrayIcon_clicked() {
953 bool state = ui->checkBoxUseTrayIcon->isChecked();
954 ui->checkBoxHideOnClose->setEnabled(state);
955 ui->checkBoxStartMinimized->setEnabled(state);
956}
957
962void ConfigDialog::closeEvent(QCloseEvent *event) {
963 QtPassSettings::setDialogGeometry("configDialog", saveGeometry());
964 if (!isMaximized()) {
965 QtPassSettings::setDialogPos("configDialog", pos());
966 QtPassSettings::setDialogSize("configDialog", size());
967 }
968 QtPassSettings::setDialogMaximized("configDialog", isMaximized());
969 event->accept();
970}
971
977 ui->checkBoxUseGit->setChecked(useGit);
978 on_checkBoxUseGit_clicked();
979}
980
986 ui->checkBoxUseOtp->setChecked(useOtp);
987}
988
990 ui->checkBoxUseGrepSearch->setChecked(useGrepSearch);
991}
992
998 ui->checkBoxUseQrencode->setChecked(useQrencode);
999}
1000
1005void ConfigDialog::on_checkBoxUseGit_clicked() {
1006 ui->checkBoxAddGPGId->setEnabled(ui->checkBoxUseGit->isChecked());
1007 ui->checkBoxAutoPull->setEnabled(ui->checkBoxUseGit->isChecked());
1008 ui->checkBoxAutoPush->setEnabled(ui->checkBoxUseGit->isChecked());
1009}
1010
1015void ConfigDialog::on_toolButtonPwgen_clicked() {
1016 QString pwgen = selectExecutable();
1017 if (!pwgen.isEmpty()) {
1018 ui->pwgenPath->setText(pwgen);
1019 ui->checkBoxUsePwgen->setEnabled(true);
1020 } else {
1021 ui->checkBoxUsePwgen->setEnabled(false);
1022 ui->checkBoxUsePwgen->setChecked(false);
1023 }
1024}
1025
1031void ConfigDialog::setPwgenPath(const QString &pwgen) {
1032 ui->pwgenPath->setText(pwgen);
1033 if (pwgen.isEmpty()) {
1034 ui->checkBoxUsePwgen->setChecked(false);
1035 ui->checkBoxUsePwgen->setEnabled(false);
1036 }
1037 on_checkBoxUsePwgen_clicked();
1038}
1039
1044void ConfigDialog::on_checkBoxUsePwgen_clicked() {
1045 if (ui->radioButtonPass->isChecked())
1046 return;
1047 bool usePwgen = ui->checkBoxUsePwgen->isChecked();
1048 ui->checkBoxAvoidCapitals->setEnabled(usePwgen);
1049 ui->checkBoxAvoidNumbers->setEnabled(usePwgen);
1050 ui->checkBoxLessRandom->setEnabled(usePwgen);
1051 ui->checkBoxUseSymbols->setEnabled(usePwgen);
1052 ui->lineEditPasswordChars->setEnabled(!usePwgen);
1053 ui->labelPasswordChars->setEnabled(!usePwgen);
1054 ui->passwordCharTemplateSelector->setEnabled(!usePwgen);
1055}
1056
1065 if (ui->pwgenPath->text().isEmpty()) {
1066 usePwgen = false;
1067 }
1068 ui->checkBoxUsePwgen->setChecked(usePwgen);
1069 on_checkBoxUsePwgen_clicked();
1070}
1071
1073 const PasswordConfiguration &config) {
1074 ui->spinBoxPasswordLength->setValue(config.length);
1075 ui->passwordCharTemplateSelector->setCurrentIndex(config.selected);
1077 ui->lineEditPasswordChars->setEnabled(false);
1078 }
1079 ui->lineEditPasswordChars->setText(config.Characters[config.selected]);
1080}
1081
1083 PasswordConfiguration config;
1084 config.length = ui->spinBoxPasswordLength->value();
1085 config.selected = static_cast<PasswordConfiguration::characterSet>(
1086 ui->passwordCharTemplateSelector->currentIndex());
1088 ui->lineEditPasswordChars->text();
1089 return config;
1090}
1091
1098void ConfigDialog::on_passwordCharTemplateSelector_activated(int index) {
1099 ui->lineEditPasswordChars->setText(
1100 QtPassSettings::getPasswordConfiguration().Characters[index]);
1101 if (index == PasswordConfiguration::CUSTOM) {
1102 ui->lineEditPasswordChars->setEnabled(true);
1103 } else {
1104 ui->lineEditPasswordChars->setEnabled(false);
1105 }
1106}
1107
1112void ConfigDialog::on_checkBoxUseTemplate_clicked() {
1113 ui->plainTextEditTemplate->setEnabled(ui->checkBoxUseTemplate->isChecked());
1114 ui->checkBoxTemplateAllFields->setEnabled(
1115 ui->checkBoxUseTemplate->isChecked());
1116}
1117
1118void ConfigDialog::onProfileTableItemChanged(QTableWidgetItem *item) {
1119 validate(item);
1120}
1121
1127 ui->checkBoxUseTemplate->setChecked(useTemplate);
1128 on_checkBoxUseTemplate_clicked();
1129}
void setPasswordConfiguration(const PasswordConfiguration &config)
auto getProfiles() -> QHash< QString, QHash< QString, QString > >
ConfigDialog::getProfiles return profile list.
~ConfigDialog() override
ConfigDialog::~ConfigDialog config destructor, makes sure the mainWindow knows about git,...
void useOtp(bool useOtp)
ConfigDialog::useOtp set preference for using otp plugin.
void useGit(bool useGit)
ConfigDialog::useGit set preference for using git.
void useAutoclearPanel(bool useAutoclearPanel)
ConfigDialog::useAutoclearPanel set the panel autoclear use from MainWindow.
void useAutoclear(bool useAutoclear)
ConfigDialog::useAutoclear set the clipboard autoclear use from MainWindow.
void useQrencode(bool useQrencode)
ConfigDialog::useQrencode set preference for using qrencode plugin.
void useTemplate(bool useTemplate)
ConfigDialog::useTemplate set preference for using templates.
ConfigDialog(MainWindow *parent)
ConfigDialog::ConfigDialog this sets up the configuration screen.
void useGrepSearch(bool useGrepSearch)
void setPwgenPath(const QString &)
ConfigDialog::setPwgenPath set pwgen executable path. Enable or disable related options in the interf...
auto getPasswordConfiguration() -> PasswordConfiguration
void useTrayIcon(bool useSystray)
ConfigDialog::useTrayIcon set preference for using trayicon. Enable or disable related checkboxes acc...
void usePwgen(bool usePwgen)
ConfigDialog::usePwgen set preference for using pwgen (can be overruled by empty pwgenPath)....
void wizard()
ConfigDialog::wizard first-time use wizard.
void closeEvent(QCloseEvent *event) override
ConfigDialog::closeEvent close this window.
void useSelection(bool useSelection)
ConfigDialog::useSelection set the clipboard type use from MainWindow.
void genKey(const QString &, QDialog *)
ConfigDialog::genKey tunnel function to make MainWindow generate a gpg key pair.
Handles GPG keypair generation.
The MainWindow class does way too much, not only is it a switchboard, configuration handler and more,...
Definition mainwindow.h:52
static auto needsInit(const QString &path) -> bool
Check if a profile path needs initialization.
static auto isUseSelection(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to use selection (X11) for clipboard.
static void setStartMinimized(const bool &startMinimized)
Save start-minimized flag.
static auto isUseAutoclear(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to use autoclear for clipboard.
static void setAutoclearPanelSeconds(const int &autoClearPanelSeconds)
Save panel autoclear seconds.
static void setPassExecutable(const QString &passExecutable)
Save pass executable path.
static auto isStartMinimized(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether application should start minimized.
static void setHidePassword(const bool &hidePassword)
Save hide password setting.
static auto isUseOtp(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether OTP support is enabled.
static void setPwgenExecutable(const QString &pwgenExecutable)
Save pwgen executable path.
static auto getPwgenExecutable(const QString &defaultValue=QVariant().toString()) -> QString
Get pwgen executable path.
static void setUseTrayIcon(const bool &useTrayIcon)
Save tray icon support flag.
static auto isNoLineWrapping(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to disable line wrapping.
static void setUseGrepSearch(const bool &useGrepSearch)
Save content search flag.
static void setPassStore(const QString &passStore)
Save password store path.
static auto isHideContent(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to hide content (password + username).
static void setPasswordConfiguration(const PasswordConfiguration &config)
Save complete password generation configuration.
static void setHideOnClose(const bool &hideOnClose)
Save hide-on-close flag.
static auto getPass() -> Pass *
Get currently active pass backend instance.
static auto getPasswordConfiguration() -> PasswordConfiguration
Get complete password generation configuration.
static auto isUseQrencode(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether qrencode support is enabled.
static auto isUseAutoclearPanel(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to use panel autoclear.
static auto isAutoPull(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether automatic pull is enabled.
static void setGitExecutable(const QString &gitExecutable)
Save git executable path.
static auto isUseGit(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether Git integration is enabled.
static void setUseOtp(const bool &useOtp)
Save OTP support flag.
static void setProfiles(const QHash< QString, QHash< QString, QString > > &profiles)
Save all configured profiles.
static void setUsePwgen(const bool &usePwgen)
Save pwgen support flag.
static auto isTemplateAllFields(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether template applies to all fields.
static auto isUsePass(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to use pass (true) or GPG (false).
static auto getPassStore(const QString &defaultValue=QVariant().toString()) -> QString
Get password store directory path.
static auto isUseTemplate(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether template usage is enabled.
static auto isUseTrayIcon(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether tray icon support is enabled.
static void setUseTemplate(const bool &useTemplate)
Save template usage flag.
static void setDialogPos(const QString &key, const QPoint &pos)
Save dialog position.
static auto isAvoidCapitals(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether uppercase characters should be avoided.
static auto isAddGPGId(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to auto-add GPG ID when receiving files.
static auto getGpgExecutable(const QString &defaultValue=QVariant().toString()) -> QString
Get GPG executable path.
static void setAutoPull(const bool &autoPull)
Save automatic pull flag.
static auto isUseGrepSearch(const bool &defaultValue=false) -> bool
Check whether content search (pass grep) is enabled.
static void setPassTemplate(const QString &passTemplate)
Save pass entry template.
static auto isUseSymbols(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether symbol characters are enabled.
static void setGpgExecutable(const QString &gpgExecutable)
Save GPG executable path.
static void setVersion(const QString &version)
Save application version.
static void setUseAutoclear(const bool &useAutoclear)
Save use autoclear setting.
static auto isLessRandom(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether less random password generation is enabled.
static void setAlwaysOnTop(const bool &alwaysOnTop)
Save always-on-top flag.
static auto getPassTemplate(const QString &defaultValue=QVariant().toString()) -> QString
Get pass entry template.
static void setDisplayAsIs(const bool &displayAsIs)
Save display as-is setting.
static void setUseMonospace(const bool &useMonospace)
Save use monospace setting.
static void setDialogSize(const QString &key, const QSize &size)
Save dialog size.
static void setAvoidCapitals(const bool &avoidCapitals)
Save uppercase avoidance flag.
static void setDialogMaximized(const QString &key, const bool &maximized)
Save dialog maximized state.
static void setQrencodeExecutable(const QString &qrencodeExecutable)
Save qrencode executable path.
static auto getProfile(const QString &defaultValue=QVariant().toString()) -> QString
Get active profile name.
static auto isUseMonospace(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to use monospace font.
static void setAddGPGId(const bool &addGPGId)
Save add GPG ID setting.
static void setUsePass(const bool &usePass)
Save use pass setting.
static auto isDialogMaximized(const QString &key, const bool &defaultValue=QVariant().toBool()) -> bool
Get dialog maximized state.
static auto getAutoclearPanelSeconds(const int &defaultValue=QVariant().toInt()) -> int
Get panel autoclear delay in seconds.
static auto isUsePwgen(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether pwgen support is enabled.
static auto isAlwaysOnTop(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether main window should stay always on top.
static auto isAvoidNumbers(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether numeric characters should be avoided.
static auto isHidePassword(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to hide password in UI.
static void setDialogGeometry(const QString &key, const QByteArray &geometry)
Save dialog geometry.
static auto getPassExecutable(const QString &defaultValue=QVariant().toString()) -> QString
Get pass executable path.
static void setUseAutoclearPanel(const bool &useAutoclearPanel)
Save use autoclear panel setting.
static void setAutoclearSeconds(const int &autoClearSeconds)
Save autoclear seconds.
static void setNoLineWrapping(const bool &noLineWrapping)
Save no line wrapping setting.
static void setUseQrencode(const bool &useQrencode)
Save qrencode support flag.
static void setAvoidNumbers(const bool &avoidNumbers)
Save numeric avoidance flag.
static auto getDialogGeometry(const QString &key, const QByteArray &defaultValue=QVariant().toByteArray()) -> QByteArray
Get saved dialog geometry.
static auto isHideOnClose(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether closing the window hides the application.
static void setAutoPush(const bool &autoPush)
Save automatic push flag.
static void setClipBoardType(const int &clipBoardType)
Save clipboard type.
static auto getProfiles() -> QHash< QString, QHash< QString, QString > >
Get all configured profiles.
static void setLessRandom(const bool &lessRandom)
Save less-random generation flag.
static auto getAutoclearSeconds(const int &defaultValue=QVariant().toInt()) -> int
Get autoclear delay in seconds.
static void setHideContent(const bool &hideContent)
Save hide content setting.
static auto isAutoPush(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether automatic push is enabled.
static void setUseSelection(const bool &useSelection)
Save use selection setting.
static auto getClipBoardTypeRaw(const Enums::clipBoardType &defaultValue=Enums::CLIPBOARD_NEVER) -> int
Get clipboard type preference.
static auto getGitExecutable(const QString &defaultValue=QVariant().toString()) -> QString
Get git executable path.
static void setTemplateAllFields(const bool &templateAllFields)
Save template-all-fields flag.
static void setUseSymbols(const bool &useSymbols)
Save symbol usage flag.
static auto isDisplayAsIs(const bool &defaultValue=QVariant().toBool()) -> bool
Get whether to display password as-is (no modification).
static void setUseGit(const bool &useGit)
Save Git integration flag.
static auto normalizeFolderPath(const QString &path) -> QString
Ensure a folder path always ends with the native directory separator.
Definition util.cpp:94
static auto findBinaryInPath(const QString &binary) -> QString
Locate an executable by searching the process PATH and (on Windows) falling back to WSL.
Definition util.cpp:120
static auto configIsValid() -> bool
Verify that the required configuration is complete.
Definition util.cpp:191
Debug utilities for QtPass.
#define dbg()
Simple debug macro that includes file and line number.
Definition debughelper.h:21
Profile initialization utilities.
Holds the Password configuration settings.
int length
Length of the password.
enum PasswordConfiguration::characterSet selected
characterSet
The selected character set.
QString Characters[CHARSETS_COUNT]
The different character sets.
Stores key info lines including validity, creation date and more.
Definition userinfo.h:13
QString name
UserInfo::name GPG user ID / full name.
Definition userinfo.h:36