18#include "ui_configdialog.h"
28#include <QGuiApplication>
31#include <QListWidgetItem>
34#include <QRegularExpression>
36#include <QSystemTrayIcon>
53 ui->spinBoxAutoclearSeconds->updateGeometry();
54 ui->spinBoxAutoclearPanelSeconds->updateGeometry();
57 connect(
ui->checkBoxHidePassword, &QCheckBox::toggled,
this,
58 [
this] { updateSecretFieldsEnabled(); });
59 connect(
ui->checkBoxHideSecretFields, &QCheckBox::toggled,
this,
60 [
this] { updateSecretFieldsEnabled(); });
61 connect(
ui->checkBoxHideAllFields, &QCheckBox::toggled,
this,
62 [
this] { updateSecretFieldsEnabled(); });
63 connect(
ui->buttonDefaultSecretFields, &QPushButton::clicked,
this, [
this] {
64 ui->lineEditSecretFields->setText(
65 AppSettings::defaultSecretFieldNames().join(QStringLiteral(
", ")));
69 connect(
ui->spinBoxAutoclearSeconds, &QSpinBox::valueChanged,
this,
71 ui->labelSeconds->setVisible(value > 0);
72 ui->checkBoxRestoreClipboard->setVisible(value > 0);
74 connect(
ui->spinBoxAutoclearPanelSeconds, &QSpinBox::valueChanged,
this,
75 [
this](
int value) { ui->labelPanelSeconds->setVisible(value > 0); });
77 ui->comboBoxFields, &QComboBox::currentIndexChanged,
this,
78 [
this](
int index) { ui->plainTextEditTemplate->setEnabled(index > 0); });
83 if (!QSystemTrayIcon::isSystemTrayAvailable()) {
84 ui->checkBoxUseTrayIcon->setEnabled(
false);
85 ui->checkBoxUseTrayIcon->setToolTip(tr(
"System tray is not available"));
86 ui->checkBoxHideOnClose->setEnabled(
false);
87 ui->checkBoxStartMinimized->setEnabled(
false);
93 if (QGuiApplication::platformName().startsWith(QLatin1String(
"wayland"))) {
94 ui->checkBoxAlwaysOnTop->setEnabled(
false);
95 ui->checkBoxAlwaysOnTop->setToolTip(
96 tr(
"Not available on Wayland; use your compositor's "
97 "\"keep above\" window rule instead"));
103 ui->checkBoxUseQrencode->hide();
107 ui->checkBoxUseQrencode->setEnabled(
false);
108 ui->checkBoxUseQrencode->setToolTip(tr(
"qrencode needs to be installed"));
111 connect(
ui->profileList, &QListWidget::currentRowChanged,
this,
113 connect(
ui->profileName, &QLineEdit::textEdited,
this,
115 connect(
ui->profilePath, &QLineEdit::textEdited,
this,
117 connect(
ui->profileSigningKey, &QLineEdit::textEdited,
this,
119 for (QCheckBox *box :
120 {
ui->profileUseGit,
ui->profileAutoPush,
ui->profileAutoPull}) {
135 QFormLayout::ItemRole role = QFormLayout::FieldRole;
136 ui->profileFormLayout->getWidgetPosition(
ui->profileSigningKey, &row,
147 connect(
ui->storePath, &QLineEdit::textChanged,
this,
148 [
this] { updatePassGitWarning(); });
151 ui->label->setText(
ui->label->text() + VERSION);
152 ui->comboBoxClipboard->clear();
154 ui->comboBoxClipboard->addItem(tr(
"No clipboard"));
155 ui->comboBoxClipboard->addItem(tr(
"Always copy to clipboard"));
156 ui->comboBoxClipboard->addItem(tr(
"On-demand copy to clipboard"));
159 ui->comboBoxClipboard->setCurrentIndex(currentIndex);
162 QClipboard *clip = QApplication::clipboard();
163 if (!clip->supportsSelection()) {
165 ui->checkBoxSelection->setVisible(
false);
170 connect(
ui->pageList, &QListWidget::currentRowChanged,
ui->pages,
171 &QStackedWidget::setCurrentIndex);
172 ui->pageList->setCurrentRow(
176 :
ui->pages->indexOf(
ui->pagePrograms));
189 ui->spinBoxAutoclearSeconds->setValue(
191 ui->labelSeconds->setVisible(
ui->spinBoxAutoclearSeconds->value() > 0);
193 ui->checkBoxRestoreClipboard->setVisible(
194 ui->spinBoxAutoclearSeconds->value() > 0);
195 ui->spinBoxAutoclearPanelSeconds->setValue(
197 ui->labelPanelSeconds->setVisible(
ui->spinBoxAutoclearPanelSeconds->value() >
202 ui->lineEditSecretFields->setText(
209 ui->checkBoxAddGPGId->setChecked(settings.
addGPGId);
215 ui->checkBoxLessRandom->setChecked(settings.
lessRandom);
216 ui->checkBoxUseSymbols->setChecked(settings.
useSymbols);
220 ui->comboBoxFields->setCurrentIndex(
223 ui->checkBoxAutoPull->setChecked(settings.
autoPull);
224 ui->checkBoxAutoPush->setChecked(settings.
autoPush);
225 ui->checkBoxGitUseParentRepository->setChecked(
254 settings.
usePass =
ui->radioButtonPass->isChecked();
268 for (
const QString &name :
269 ui->lineEditSecretFields->text().split(QLatin1Char(
','))) {
270 if (!name.trimmed().isEmpty()) {
278 settings.
addGPGId =
ui->checkBoxAddGPGId->isChecked();
281 if (
ui->checkBoxUseTrayIcon->isEnabled()) {
284 if (
ui->checkBoxHideOnClose->isEnabled()) {
287 if (
ui->checkBoxStartMinimized->isEnabled()) {
290 settings.
useGit =
ui->checkBoxUseGit->isChecked();
294 settings.
autoPush =
ui->checkBoxAutoPush->isChecked();
295 settings.
autoPull =
ui->checkBoxAutoPull->isChecked();
297 ui->checkBoxGitUseParentRepository->isChecked();
298 settings.
useOtp =
ui->checkBoxUseOtp->isChecked();
302 settings.
usePwgen =
ui->checkBoxUsePwgen->isChecked();
305 settings.
lessRandom =
ui->checkBoxLessRandom->isChecked();
306 settings.
useSymbols =
ui->checkBoxUseSymbols->isChecked();
308 settings.
useTemplate =
ui->comboBoxFields->currentIndex() > 0;
317ConfigDialog::~ConfigDialog() =
default;
320 ui->gitPath->setText(path);
321 ui->checkBoxUseGit->setEnabled(!path.isEmpty());
322 if (path.isEmpty()) {
328 ui->radioButtonNative->setChecked(!
usePass);
329 ui->radioButtonPass->setChecked(
usePass);
335 static const QRegularExpression fingerprint(
336 QStringLiteral(
"^(?:[0-9A-Fa-f]{40}|[0-9A-Fa-f]{64})$"));
337 const QStringList keys = setting.split(QLatin1Char(
' '), Qt::SkipEmptyParts);
338 return std::all_of(keys.cbegin(), keys.cend(), [](
const QString &key) {
339 return fingerprint.match(key).hasMatch();
346 const QHash<QString, int> &names)
const
349 if (entry.name.isEmpty()) {
350 problems.
name = tr(
"This field is required");
351 }
else if (names.value(entry.name) > 1) {
352 problems.
name = tr(
"Another profile already has this name");
354 if (entry.profile.path.isEmpty()) {
355 problems.
path = tr(
"This field is required");
361 problems.
key = tr(
"Full key fingerprints only (40 or 64 hexadecimal "
362 "characters), separated by spaces");
368 if (QListWidgetItem *item =
ui->profileList->item(row)) {
369 item->setBackground(problems.
none() ? QBrush() : QBrush(Qt::red));
377 const auto tipOr = [](
const QString &problem,
const QString &tip) {
378 return problem.isEmpty() ? tip : problem;
382 ui->profileSigningKey->setToolTip(tipOr(problems.
key,
m_keyTip));
401 const QString real = QFileInfo(entry.profile.path).canonicalFilePath();
402 resolved.
stores << (real.isEmpty() ? QDir::cleanPath(entry.profile.path)
410 const QProcessEnvironment &env)
const
417 static const QRegularExpression complete(QStringLiteral(
418 "^(?:0X)?(?:[0-9A-F]{8}|[0-9A-F]{16}|[0-9A-F]{40}|[0-9A-F]{64})$"));
419 const QString gpg =
ui->gpgPath->text();
421 for (
const QString &key :
422 signingKey.toUpper().split(QLatin1Char(
' '), Qt::SkipEmptyParts)) {
424 if (gpg.isEmpty() || !complete.match(key).hasMatch()) {
427 const QString cacheKey = gpg + QLatin1Char(
'\n') +
428 env.value(QStringLiteral(
"GNUPGHOME")) +
429 QLatin1Char(
'\n') + key;
437 {QStringLiteral(
"--no-tty"), QStringLiteral(
"--batch"),
438 QStringLiteral(
"--no-auto-check-trustdb"),
439 QStringLiteral(
"--with-colons"),
440 QStringLiteral(
"--with-fingerprint"),
441 QStringLiteral(
"--with-subkey-fingerprint"),
442 QStringLiteral(
"--list-keys"), QStringLiteral(
"--"), key},
447 if (!cached->isEmpty()) {
448 keys.insert(*cached);
455 QDialog::changeEvent(event);
456 if (event->type() != QEvent::ActivationChange) {
463 if (!isActiveWindow()) {
465 [](
const std::pair<const QString &, QString &> &lookup) {
466 return lookup.second.isEmpty();
480 const QSet<QString> &mine = resolved.keys.at(row);
481 if (mine.isEmpty()) {
484 for (
int other = 0; other <
m_entries.size(); ++other) {
485 if (other == row || resolved.stores.at(other) == resolved.stores.at(row)) {
488 if (resolved.keys.at(other).intersects(mine)) {
497 QHash<QString, int> names;
503 for (
int row = 0; row <
m_entries.size(); ++row) {
508 tr(
"%1 signs with the same key for another store. A recipient "
509 "list signed for one of these stores is accepted in the other: "
510 "use a separate signing key for each store whose recipients "
512 .arg(others.join(QStringLiteral(
", ")));
515 status = status && problems.
none();
517 ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(status);
526 QStringList warnings;
527 if (
ui->radioButtonPass->isChecked()) {
528 QStringList stores{
ui->storePath->text()};
530 stores << entry.profile.path;
532 stores.removeDuplicates();
533 for (
const QString &store : std::as_const(stores)) {
535 if (!repository.isEmpty()) {
536 warnings << tr(
"pass commits changes in %1 to the Git repository in "
537 "%2: with a colon in the store's path, pass cannot "
538 "keep Git to the store. Run \"git init\" in the store, "
539 "or use native Git/GPG.")
540 .arg(QDir::toNativeSeparators(store),
541 QDir::toNativeSeparators(repository));
550 const QString
override =
ui->sshAuthSockOverride->text().trimmed();
551 if (
override.isEmpty()) {
559 reason = tr(
"The path does not exist.");
562 reason = tr(
"The path is not readable.");
565 reason = tr(
"The path is not a Unix domain socket.");
568 QMessageBox::warning(
569 this, tr(
"Potentially invalid SSH_AUTH_SOCK override"),
570 tr(
"The SSH_AUTH_SOCK override value may be invalid.\n\n%1\n\n"
571 "The value will still be saved as entered.")
581 if (!wasActive.isEmpty() && entry.originalName == wasActive) {
582 nowActive = entry.name;
586 const auto active = profiles.constFind(nowActive);
587 if (active != profiles.constEnd()) {
610 if (!pass.isEmpty()) {
611 ui->passPath->setText(pass);
618 if (!gpg.isEmpty()) {
619 ui->gpgPath->setText(gpg);
622 if (!git.isEmpty()) {
623 ui->gitPath->setText(git);
626 if (!pwgen.isEmpty()) {
627 ui->pwgenPath->setText(pwgen);
636 bool state =
ui->radioButtonPass->isChecked();
637 ui->groupBoxNative->setEnabled(!state);
638 ui->groupBoxPass->setEnabled(state);
642 ui->spinBoxPasswordLength->setEnabled(
false);
643 ui->checkBoxUsePwgen->setEnabled(
false);
644 ui->checkBoxAvoidCapitals->setEnabled(
false);
645 ui->checkBoxUseSymbols->setEnabled(
false);
646 ui->checkBoxLessRandom->setEnabled(
false);
647 ui->checkBoxAvoidNumbers->setEnabled(
false);
648 ui->labelPasswordChars->setEnabled(
false);
649 ui->passwordCharTemplateSelector->setEnabled(
false);
650 ui->lineEditPasswordChars->setEnabled(
false);
653 ui->spinBoxPasswordLength->setEnabled(
true);
654 ui->checkBoxUsePwgen->setEnabled(!
ui->pwgenPath->text().isEmpty());
660 QFileDialog dialog(
this);
661 dialog.setFileMode(QFileDialog::ExistingFile);
662 dialog.setOption(QFileDialog::ReadOnly);
664 return dialog.selectedFiles().constFirst();
671 QFileDialog dialog(
this);
672 dialog.setFileMode(QFileDialog::Directory);
673 dialog.setFilter(QDir::NoFilter);
674 dialog.setOption(QFileDialog::ShowDirsOnly);
676 return dialog.selectedFiles().constFirst();
684 bool state = !git.isEmpty();
686 ui->gitPath->setText(git);
691 ui->checkBoxUseGit->setEnabled(state);
696 if (!gpg.isEmpty()) {
697 ui->gpgPath->setText(gpg);
708 if (!pass.isEmpty()) {
709 ui->passPath->setText(pass);
715 if (!store.isEmpty()) {
716 ui->storePath->setText(store);
722 bool state = index > 0;
724 ui->checkBoxSelection->setEnabled(state);
725 ui->checkBoxHidePassword->setEnabled(state);
727 ui->checkBoxHideContent->setEnabled(state);
728 ui->labelAutoclear->setEnabled(state);
729 ui->spinBoxAutoclearSeconds->setEnabled(state);
730 ui->labelSeconds->setEnabled(state);
731 ui->checkBoxRestoreClipboard->setEnabled(state);
738 const bool hiding =
ui->checkBoxHidePassword->isEnabled() &&
739 ui->checkBoxHidePassword->isChecked();
740 ui->checkBoxHideAllFields->setEnabled(hiding);
741 const bool all = hiding &&
ui->checkBoxHideAllFields->isChecked();
742 ui->checkBoxHideSecretFields->setEnabled(hiding && !all);
744 hiding && !all &&
ui->checkBoxHideSecretFields->isChecked();
745 ui->lineEditSecretFields->setEnabled(words);
746 ui->buttonDefaultSecretFields->setEnabled(words);
759 const QString ¤tProfile) {
761 profiles.remove(QString());
764 ui->profileList->clear();
766 for (
auto i = profiles.cbegin(); i != profiles.cend(); ++i) {
767 if (i.key() == currentProfile) {
770 m_entries.append({i.key(), i.value(), i.key()});
771 ui->profileList->addItem(i.key());
773 ui->profileList->setCurrentRow(currentRow);
774 if (currentRow < 0) {
781 if (m_currentEntry < 0 || m_currentEntry >=
m_entries.size()) {
793 ui->profileForm->setEnabled(entry !=
nullptr);
794 ui->deleteButton->setEnabled(entry !=
nullptr);
795 ui->profileName->setText(entry ? entry->
name : QString());
796 ui->profilePath->setText(entry ? entry->
profile.
path : QString());
799 entry && entry->
profile.
useGit.value_or(
ui->checkBoxUseGit->isChecked());
800 ui->profileUseGit->setChecked(
useGit);
801 ui->profileAutoPush->setChecked(
804 ui->profileAutoPull->setChecked(
807 ui->profileAutoPush->setEnabled(
useGit);
808 ui->profileAutoPull->setEnabled(
useGit);
817 profiles.insert(entry.name, entry.profile);
823 if (QDir(path).exists()) {
826 if (QMessageBox::question(
827 this, tr(
"Create profile directory?"),
828 tr(
"Would you like to create a password store at %1?").arg(path),
829 QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) {
833 QMessageBox::warning(
835 tr(
"Could not create profile directory: %1").arg(path));
843 const QString &path) {
859 usersDialog.setWindowTitle(tr(
"Select recipients for %1").arg(name));
860 if (usersDialog.exec() != QDialog::Accepted) {
868 QMessageBox::warning(
this, tr(
"Could not initialise profile %1").arg(name),
870 }
else if (!note.isEmpty()) {
871 QMessageBox::information(
this, tr(
"Profile %1").arg(name), note);
878 for (
auto it = newProfiles.cbegin(); it != newProfiles.cend(); ++it) {
879 const QString path = QDir::cleanPath(it.value().path);
882 const bool known = std::any_of(
883 existingProfiles.cbegin(), existingProfiles.cend(),
884 [&it](
const Profile &old) { return old.path == it.value().path; });
894 entry.
name = tr(
"New profile");
897 ui->profileList->addItem(entry.
name);
898 ui->profileList->setCurrentRow(
m_entries.size() - 1);
899 ui->profileName->setFocus();
900 ui->profileName->selectAll();
906 if (!dir.isEmpty()) {
907 ui->profilePath->setText(dir);
913 const int row =
ui->profileList->currentRow();
914 if (row < 0 || row >=
m_entries.size()) {
915 QMessageBox::warning(
this, tr(
"No profile selected"),
916 tr(
"No profile selected to delete"));
920 delete ui->profileList->takeItem(row);
926 QMessageBox::critical(
this, title, text, QMessageBox::Ok, QMessageBox::Ok);
933 Q_UNUSED(configuredPath);
936 if (!configuredPath.isEmpty()) {
937 const QFileInfo configured(configuredPath);
938 if (configured.isFile() && configured.isExecutable()) {
943 if (found.isEmpty()) {
952 if (QSystemTrayIcon::isSystemTrayAvailable()) {
953 ui->checkBoxUseTrayIcon->setChecked(useSystray);
954 ui->checkBoxHideOnClose->setEnabled(useSystray);
955 ui->checkBoxStartMinimized->setEnabled(useSystray);
958 ui->checkBoxHideOnClose->setChecked(
false);
959 ui->checkBoxStartMinimized->setChecked(
false);
965 bool state =
ui->checkBoxUseTrayIcon->isChecked();
966 ui->checkBoxHideOnClose->setEnabled(state);
967 ui->checkBoxStartMinimized->setEnabled(state);
971 ui->checkBoxUseGit->setChecked(
useGit);
976 ui->checkBoxUseOtp->setChecked(
useOtp);
988 ui->checkBoxAddGPGId->setEnabled(
ui->checkBoxUseGit->isChecked());
989 ui->checkBoxAutoPull->setEnabled(
ui->checkBoxUseGit->isChecked());
990 ui->checkBoxAutoPush->setEnabled(
ui->checkBoxUseGit->isChecked());
993 ui->checkBoxGitUseParentRepository->setEnabled(
994 ui->checkBoxUseGit->isChecked() && !
ui->radioButtonPass->isChecked());
999 if (!pwgen.isEmpty()) {
1000 ui->pwgenPath->setText(pwgen);
1001 ui->checkBoxUsePwgen->setEnabled(
true);
1003 ui->checkBoxUsePwgen->setEnabled(
false);
1004 ui->checkBoxUsePwgen->setChecked(
false);
1009 ui->pwgenPath->setText(pwgen);
1010 if (pwgen.isEmpty()) {
1011 ui->checkBoxUsePwgen->setChecked(
false);
1012 ui->checkBoxUsePwgen->setEnabled(
false);
1018 if (
ui->radioButtonPass->isChecked())
1020 bool usePwgen =
ui->checkBoxUsePwgen->isChecked();
1021 ui->checkBoxAvoidCapitals->setEnabled(
usePwgen);
1022 ui->checkBoxAvoidNumbers->setEnabled(
usePwgen);
1023 ui->checkBoxLessRandom->setEnabled(
usePwgen);
1024 ui->checkBoxUseSymbols->setEnabled(
usePwgen);
1025 ui->lineEditPasswordChars->setEnabled(!
usePwgen);
1026 ui->labelPasswordChars->setEnabled(!
usePwgen);
1027 ui->passwordCharTemplateSelector->setEnabled(!
usePwgen);
1031 if (
ui->pwgenPath->text().isEmpty()) {
1043 ui->spinBoxPasswordLength->setValue(config.
length);
1044 ui->passwordCharTemplateSelector->setCurrentIndex(config.
selected);
1046 ui->lineEditPasswordChars->setEnabled(
false);
1053 config.
length =
ui->spinBoxPasswordLength->value();
1055 ui->passwordCharTemplateSelector->currentIndex());
1060 ui->lineEditPasswordChars->text();
1068 ui->lineEditPasswordChars->setText(
1071 ui->lineEditPasswordChars->setEnabled(
true);
1073 ui->lineEditPasswordChars->setEnabled(
false);
1086 item->setText(name);
1120 ui->profileAutoPush->setEnabled(
ui->profileUseGit->isChecked());
1121 ui->profileAutoPull->setEnabled(
ui->profileUseGit->isChecked());
1126 if (entry ==
nullptr) {
1127 ui->statusLabel->setText(QString());
1131 QString statusMessage;
1133 const QString path = QDir::cleanPath(entry->
profile.
path);
1134 if (!QDir(path).exists()) {
1135 statusMessage = tr(
"New profile: %1 at %2").arg(entry->
name, path);
1137 statusMessage = tr(
"Profile: %1 at %2").arg(entry->
name, path);
1140 statusMessage = tr(
"Fill in all required fields");
1143 ui->statusLabel->setText(statusMessage);
AppSettings, the value object holding every flat QtPass setting.
void setPasswordConfiguration(const PasswordConfiguration &config)
Apply a password configuration to the dialog controls.
void on_deleteButton_clicked()
Remove the selected profile row (a message when none is); the list's currentRowChanged re-points the ...
std::optional< AppSettings > m_gpgSettings
void on_passwordCharTemplateSelector_activated(int index)
Show the chosen character set's characters in the line edit, editable only for the custom set.
static auto isFingerprintList(const QString &setting) -> bool
Whether a signing-key setting holds only full key fingerprints (40 or 64 hexadecimal characters each,...
void on_toolButtonGit_clicked()
Pick the git executable in a file dialog; a cancelled dialog turns Git off and disables its checkbox,...
auto sharingTheKey(int row, const SigningStores &resolved) const -> QStringList
The other profiles, for other stores, whose signing keys share a fingerprint with row row's.
void validate()
Check every profile (problemsOf(), sharingTheKey()), mark the rows and the form, enable OK only when ...
void updatePassGitWarning()
auto ensureProfileFolder(const QString &path) -> bool
Offer to create a new profile's store folder when it is missing.
void on_radioButtonNative_clicked()
Native (gpg/git) backend chosen: enable its group box, disable pass's.
QList< ProfileEntry > m_entries
The profiles as shown; index == row in profileList.
void useOtp(bool useOtp)
Enable or disable OTP support.
void updateSecretFieldsEnabled()
void loadProfileForm(int row)
Show row row's profile in the form (or clear and disable it for -1), with m_loadingForm set so the fi...
void on_pushButtonGenerateKey_clicked()
Open KeygenDialog for the gpg shown in the dialog.
void setPwgenPath(const QString &path)
Set the path to the pwgen executable.
void on_toolButtonStore_clicked()
Pick the password store folder for the pass backend's store path.
void on_checkBoxUseTrayIcon_clicked()
Hide-on-close and start-minimised are only offered with a tray icon.
QHash< QString, QString > m_primaryOf
void useGit(bool useGit)
Enable or disable git integration.
void on_radioButtonPass_clicked()
pass backend chosen: enable its group box, disable the native one.
void showProblems(int row, const ProfileProblems &problems)
Mark row row of the profile list, and the form fields when it is the row being edited,...
int m_currentEntry
Row whose fields the form shows, -1 for none.
void on_profilePathBrowse_clicked()
Pick the selected profile's store folder and store it in its entry.
QLabel * m_sharedKeyWarning
Below the signing key: the profiles that share it, if any.
QScopedPointer< Ui::ConfigDialog > ui
The widgets from configdialog.ui.
void on_checkBoxUsePwgen_clicked()
Enable pwgen's flags or the character-set controls, whichever the "use pwgen" box selects; nothing in...
auto signerKeys(const QString &signingKey, const QProcessEnvironment &env) const -> QSet< QString >
One profile's signing keys as signers: each key as written, plus the primary fingerprint gpg gives fo...
void setProfiles(Profiles profiles, const QString ¤tProfile)
Fill the profile list and m_entries from profiles, dropping the empty-named leftover older versions w...
void useQrencode(bool useQrencode)
Enable or disable QR code display.
void on_autodetectButton_clicked()
Fill the pass, gpg (gpg2 first), git and pwgen paths from PATH, keeping a field as it is when nothing...
auto problemsOf(const ProfileEntry &entry, const QHash< QString, int > &names) const -> ProfileProblems
What is wrong with entry's name, store path and signing keys.
void on_comboBoxClipboard_activated(int index)
Enable the controls that only mean something with a clipboard (selection, hiding, autoclear) unless "...
void onProfilePathEdited(const QString &path)
The path field was typed in: store it in the entry, validate and refresh the status line.
void usePass(bool usePass)
Tick the pass or the native radio button and enable the matching group box.
void useGrepSearch(bool useGrepSearch)
Enable or disable grep content search.
QLabel * m_passGitWarning
In the pass box: the stores pass would commit outside of, if any.
void initializeNewProfiles(const Profiles &existingProfiles)
For every saved profile whose store was not a profile's store when the dialog opened: offer to create...
ConfigDialog(QWidget *parent)
Construct a ConfigDialog associated with the given main window.
void onProfileSelected(int row)
The profile list's current row changed: show that profile.
auto signingStores() const -> SigningStores
Resolve every profile's store and fingerprints once.
auto selectExecutable() -> QString
Ask for an existing file in a read-only file dialog.
QString m_customPasswordChars
void setGitPath(const QString &path)
Show path as the git executable; an empty path disables and turns off "use Git".
void on_toolButtonPass_clicked()
Pick the pass executable in a file dialog; cancel keeps the field.
void setGroupBoxState()
Enable the group box of the chosen backend and, in pass mode, disable the password-generation control...
void onProfileGitToggled()
One of the profile's Git boxes was clicked: all three flags become the profile's own (no longer follo...
void on_checkBoxUseGit_clicked()
Enable the Git-dependent boxes (add .gpg-id, auto pull/push, and in native mode the parent-repository...
auto getPasswordConfiguration() -> PasswordConfiguration
Read the current password configuration from the dialog controls.
auto currentEntry() -> ProfileEntry *
The entry the form is editing.
void initialiseProfileStore(const QString &name, const Profile &profile, const QString &path)
Ask for a new profile's recipients and initialise its store with them, keeping the active backend's s...
void criticalMessage(const QString &title, const QString &text)
QMessageBox::critical with a single OK button. Once a workaround for crashes in Qt 5....
void useTrayIcon(bool useSystray)
Show or hide the system tray icon.
void onProfileSigningKeyEdited(const QString &key)
The signing-key field was typed in: store it in the entry and validate (fingerprints only,...
void followActiveProfile(const Profiles &profiles)
Point the active profile at its new name after a rename (or at none after a deletion),...
void on_toolButtonGpg_clicked()
Pick the gpg executable in a file dialog; cancel keeps the field.
void warnAboutSshAuthSockOverride()
void applySettings(const AppSettings &settings)
Load the dialog's value widgets from an AppSettings struct.
auto getProfiles() -> Profiles
Return all configured profiles.
void on_accepted()
On OK: warn about a dubious SSH_AUTH_SOCK override, save the settings and the profiles,...
void on_checkBoxSelection_clicked()
Re-apply the clipboard gating for the current clipboard mode.
void on_toolButtonPwgen_clicked()
Pick the pwgen executable; a choice enables "use pwgen", a cancelled dialog unticks and disables it.
void usePwgen(bool usePwgen)
Enable or disable pwgen-based password generation.
void changeEvent(QEvent *event) override
Forget the signing keys gpg did not know while the dialog is in the background, and check them again ...
void updateProfileStatus()
Refresh the status line under the form: the profile's name and cleaned path, marked "New" while the f...
auto isQrencodeAvailable(const QString &configuredPath) -> bool
Whether qrencode can run: configuredPath when it is an executable file, else a qrencode on Util's PAT...
auto readSettings() -> AppSettings
Build an AppSettings struct from the dialog's widgets.
void onProfileNameEdited(const QString &name)
The name field was typed in: store it in the entry and the list item, then validate (duplicates,...
void on_addButton_clicked()
Append a "New profile" row pointing at the global store path, select it and put the cursor in the nam...
auto selectFolder() -> QString
Ask for a directory in a directories-only file dialog.
void useSelection(bool useSelection)
Enable or disable clipboard selection mode.
static auto executeBlocking(const QString &app, const QStringList &args, const QString &input=QString(), QString *process_out=nullptr, QString *process_err=nullptr) -> int
Run a command synchronously and return its exit code.
Handles GPG keypair generation.
static auto needsInit(const QString &path) -> bool
Check if a profile path needs initialization.
static auto gpgEnvironment(const AppSettings &s) -> QProcessEnvironment
The environment QtPass runs gpg in outside the active store's backend: the system's,...
static auto initialise(const QString &dir, const QList< UserInfo > &users, const AppSettings &s, bool useGit, QString *note) -> bool
Write the recipients and, if wanted, put the folder under git.
static auto getPass() -> Pass *
Get currently active pass backend instance.
static auto getPasswordConfiguration() -> PasswordConfiguration
Get complete password generation configuration.
static auto load() -> AppSettings
Load all flat settings into an AppSettings value object.
static auto getProfiles() -> Profiles
Get all configured profiles.
static void setQrencodeExecutable(const QString &qrencodeExecutable)
Save qrencode executable path.
static auto getProfile(const QString &defaultValue=QVariant().toString()) -> QString
Get active profile name.
static void setProfiles(const Profiles &profiles)
Save all configured profiles.
static void save(const AppSettings &settings)
Persist an AppSettings value object to the singleton store.
@ Valid
Exists, readable, and on Unix a Unix domain socket.
@ NotUnixDomainSocket
Unix only: stat() says the path is not S_ISSOCK.
@ DoesNotExist
QFileInfo::exists() returned false.
static auto overrideStatus(const QString &path) -> OverrideStatus
Validate an SSH_AUTH_SOCK override path. Caller is expected to skip validation when the input is empt...
Dialog for selecting GPG recipients for password encryption.
auto selectedUsers() const -> QList< UserInfo >
The key list with the user's choice in each entry's enabled flag.
@ Nothing
None: for a store that had no list when it was chosen.
void setInitOnAccept(bool initOnAccept)
Choose whether OK runs Pass::Init on the folder.
static auto repositoryPassClimbsTo(const QString &store) -> QString
The repository above store that pass itself would commit to, if any.
static auto configIsValid(const AppSettings &s) -> bool
Verify that the required configuration is complete.
static auto mkpathForStore(const QString &path) -> bool
Create path and any missing parents as pass would.
static auto normalizeFolderPath(const QString &path) -> QString
Ensure a folder path always ends with '/'.
static auto findBinaryInPath(const QString &binary) -> QString
Locate an executable by searching the process PATH and (on Windows) falling back to WSL.
Settings dialog: every page of the configuration window and the profile table, with the validation th...
Executor, the FIFO queue every gpg, git and pass child process of QtPass goes through,...
auto primaryFingerprintOf(const QString &output, const QString &key) -> QString
The primary key fingerprint of the key that key names.
Parsing of gpg --with-colons key listings into UserInfo records.
Dialog that collects name, e-mail and passphrase for a new GPG keypair and drives gpg --gen-key --bat...
ClipBoardType
Defines when to copy passwords to clipboard.
void attach(QDialog &dialog, const QString &key)
restore() now, save() whenever the dialog finishes.
QMap< QString, Profile > Profiles
All profiles by name. QMap so iteration order is the name order.
Initialising a new profile's store (.gpg-id, signature, Git) with blocking processes,...
The "qtpass" logging category.
QtPassSettings, the QSettings singleton behind every saved setting, the profiles and the Pass backend...
SshAuthSock: finding an SSH agent socket for child processes and judging a configured override.
Plain value-object holding all flat QtPass configuration.
bool displayAsIs
Show file content unmodified.
bool useGrepSearch
Enable content (grep) search.
QString gpgExecutable
Path to the gpg/gpg2 executable.
QString qrencodeExecutable
Path to the qrencode executable.
QString sshAuthSockOverride
Manual SSH_AUTH_SOCK override path.
bool lessRandom
Generate memorable (less random) passwords.
bool useSymbols
Include special symbols.
bool hideOnClose
Hide to tray instead of quitting on close.
QStringList secretFieldNames
QString passSigningKey
GPG key used to sign .gpg-id files.
bool usePass
Use the pass CLI (true) or native git/gpg.
QString pwgenExecutable
Path to the pwgen executable.
bool hideContent
Hide the entire content panel.
bool useOtp
Enable native TOTP (OTP) support.
QString passStore
Password-store root path.
bool useAutoclearPanel
Clear the content panel after a delay.
bool noLineWrapping
Disable line wrapping in the panel.
QString gitExecutable
Path to the git executable.
bool autoPull
Automatically git pull on open.
bool alwaysOnTop
Keep the main window always on top.
int autoclearPanelSeconds
Panel autoclear delay (seconds).
bool startMinimized
Start the window minimised.
bool usePwgen
Use pwgen for password generation.
bool useTrayIcon
Show a system tray icon.
bool gitUseParentRepository
QString passExecutable
Path to the pass executable.
bool avoidCapitals
Exclude uppercase letters.
int autoclearSeconds
Clipboard autoclear delay (seconds).
bool useSelection
Use the X11 primary selection.
bool useGit
Enable git integration.
bool addGPGId
Auto-add .gpg-id files to git.
Enums::ClipBoardType clipBoardType
Clipboard copy behaviour.
QString version
Last-run application version.
QString passTemplate
Newline-separated template field names.
bool useMonospace
Render content in a monospace font.
bool templateAllFields
Treat every key: line as a field.
bool avoidNumbers
Exclude digits.
bool useQrencode
Enable qrencode support.
QString activeProfile
Name of the active profile.
bool useTemplate
Use the password template.
PasswordConfiguration passwordConfiguration
Length/charset/custom chars.
One row of the profile list while the dialog is open. A QList rather than the Profiles map so a profi...
QString name
The name as typed; may be empty or a duplicate.
What is wrong with one profile's fields; empty strings where nothing is.
QString name
Empty or duplicate name; empty when fine.
auto none() const -> bool
Whether all three fields are fine.
auto first() const -> QString
The first complaint, for a tooltip on the profile's row.
QString path
Missing store path; empty when fine.
QStringList stores
Canonical (or cleaned) store path.
QList< QSet< QString > > keys
Fingerprints of the signing key.
Holds the password generator settings: which character set is selected, the alphabet of every set,...
int length
Length of the generated password, in characters.
CharacterSet selected
Currently active character set selection.
QString Characters[CHARSETS_COUNT]
The alphabet of each character set, indexed by CharacterSet. Only the CUSTOM entry is meant to be cha...
CharacterSet
Character set options for password generation; also the index into Characters.
One named password store: where it is, how its .gpg-id is signed and, optionally, its own Git switche...
std::optional< bool > autoPush
Push after commits; unset = global.
QString path
Password store directory.
std::optional< bool > autoPull
Pull on start; unset = global.
std::optional< bool > useGit
Git on/off; unset follows the global.
QString signingKey
Key(s) that sign this store's .gpg-id.
UsersDialog, the recipient picker for a folder's .gpg-id.
Util: static helpers for the process environment, binary discovery, store paths, URL safety and the l...
WindowStateStore: saves and restores top-level window geometry through QtPassSettings,...