34#include "ui_mainwindow.h"
38#include <QApplication>
41#include <QDesktopServices>
46#include <QInputDialog>
52#include <QProgressDialog>
55#include <QTextCharFormat>
69 qt_set_sequence_auto_mnemonic(
true);
77 new QShortcut(QKeySequence(QKeySequence::StandardKey::Copy),
this,
this,
83 connect(
ui->treeView, &QWidget::customContextMenuRequested,
this,
98 ui->lineEdit->installEventFilter(
this);
101 ui->toolBar->installEventFilter(
this);
102 menuBar()->installEventFilter(
this);
110 ui->lineEdit->setClearButtonEnabled(
true);
115 ui->lineEdit->setText(searchText);
137 [
this](
const QString &html) {
flashText(html,
false,
true); });
146 [
this](
const QString &message) { showStatusMessage(message); });
164 QFont monospace(
"Monospace");
165 monospace.setStyleHint(QFont::Monospace);
166 ui->textBrowser->setFont(monospace);
169 ui->textBrowser->setLineWrapMode(QTextBrowser::NoWrap);
173 ui->textBrowser->setOpenExternalLinks(
true);
174 ui->textBrowser->setContextMenuPolicy(Qt::CustomContextMenu);
175 connect(
ui->textBrowser, &QWidget::customContextMenuRequested,
this,
181 ui->gridLayout,
ui->verticalLayoutPassword,
this,
this);
192 if (
ui->actionEdit->isEnabled()) {
211 connect(&
m_uiWatchdog, &QTimer::timeout,
this, [
this]() {
228 ui->actionShowProcessOutput->setChecked(
230 connect(
ui->actionShowProcessOutput, &QAction::toggled,
this,
232 m_processOutput->setVisible(show);
233 AppSettings s = QtPassSettings::load();
234 if (s.showProcessOutput != show) {
235 s.showProcessOutput = show;
236 QtPassSettings::save(s);
241 [
this](
const QString &out,
const QString &err,
Enums::PROCESS pid) {
251 if (!out.isEmpty()) {
252 onProcessOutput(out,
false, pid);
254 if (!err.isEmpty()) {
255 onProcessOutput(err,
true, pid);
302 auto *lineEdit = findChild<QLineEdit *>(QStringLiteral(
"lineEdit"));
303 if (lineEdit ==
nullptr || !lineEdit->isVisible()) {
306 lineEdit->selectAll();
307 lineEdit->setFocus();
314 if (
event->type() == QEvent::ApplicationPaletteChange) {
320 return QMainWindow::event(
event);
324 QWidget::changeEvent(
event);
331 if (
event->type() == QEvent::ActivationChange && isActiveWindow() &&
336 Qt::QueuedConnection);
341 QMainWindow::showEvent(
event);
349 Qt::QueuedConnection);
353 connect(
ui->actionAddPassword, &QAction::triggered,
this,
355 connect(
ui->actionAddFolder, &QAction::triggered,
this,
368 connect(
ui->actionQuit, &QAction::triggered, qApp, &QApplication::quit);
369 connect(
ui->actionClose, &QAction::triggered,
this, &MainWindow::close);
372 ui->actionShowMenuBar->setVisible(
false);
376 addAction(
ui->actionShowMenuBar);
378 menuBar()->setVisible(
ui->actionShowMenuBar->isChecked());
379 connect(
ui->actionShowMenuBar, &QAction::toggled,
this, [
this](
bool show) {
380 menuBar()->setVisible(show);
381 AppSettings s = QtPassSettings::load();
382 s.showMenuBar = show;
383 QtPassSettings::save(s);
387 connect(
ui->actionFaq, &QAction::triggered,
this, [] {
388 QDesktopServices::openUrl(QUrl(QStringLiteral(
"https://qtpass.org/faq")));
391 connect(
ui->actionAboutQt, &QAction::triggered, qApp, &QApplication::aboutQt);
393 ui->actionAddPassword->setIcon(
394 QIcon::fromTheme(
"document-new", QIcon(
":/icons/document-new.svg")));
395 ui->actionAddFolder->setIcon(
396 QIcon::fromTheme(
"folder-new", QIcon(
":/icons/folder-new.svg")));
397 ui->actionEdit->setIcon(QIcon::fromTheme(
398 "document-properties", QIcon(
":/icons/document-properties.svg")));
399 ui->actionDelete->setIcon(
400 QIcon::fromTheme(
"edit-delete", QIcon(
":/icons/edit-delete.svg")));
401 ui->actionPush->setIcon(
402 QIcon::fromTheme(
"go-up", QIcon(
":/icons/go-top.svg")));
403 ui->actionUpdate->setIcon(
404 QIcon::fromTheme(
"go-down", QIcon(
":/icons/go-bottom.svg")));
405 ui->actionUsers->setIcon(QIcon::fromTheme(
406 "x-office-address-book", QIcon(
":/icons/x-office-address-book.svg")));
407 ui->actionConfig->setIcon(QIcon::fromTheme(
408 "applications-system", QIcon(
":/icons/applications-system.svg")));
412 ui->statusBar->showMessage(tr(
"Welcome to QtPass %1").arg(VERSION), 2000);
414 QPixmap logo = QPixmap::fromImage(QImage(
":/artwork/icon.svg"))
415 .scaledToHeight(statusBar()->height());
416 auto *logoApp =
new QLabel(statusBar());
417 logoApp->setPixmap(logo);
418 statusBar()->addPermanentWidget(logoApp);
422 return ui->treeView->currentIndex();
428 ui->textBrowser->setTextColor(Qt::red);
433 QTextCharFormat format =
ui->textBrowser->currentCharFormat();
434 format.clearForeground();
435 ui->textBrowser->setCurrentCharFormat(format);
439 QString _text = text;
440 if (!
ui->textBrowser->toPlainText().isEmpty()) {
441 _text =
ui->textBrowser->toHtml() + _text;
443 ui->textBrowser->setHtml(_text);
445 ui->textBrowser->setText(text);
452 QFont monospace(
"Monospace");
453 monospace.setStyleHint(QFont::Monospace);
454 ui->textBrowser->setFont(monospace);
456 ui->textBrowser->setFont(QFont());
460 ui->textBrowser->setLineWrapMode(QTextBrowser::NoWrap);
462 ui->textBrowser->setLineWrapMode(QTextBrowser::WidgetWidth);
468 const Qt::WindowFlags flags = windowFlags();
469 if (flags.testFlag(Qt::WindowStaysOnTopHint) == wantOnTop) {
475 const bool wasVisible = isVisible();
476 setWindowFlags(wantOnTop ? (flags | Qt::WindowStaysOnTopHint)
477 : (flags & ~Qt::WindowStaysOnTopHint));
490 if (wizard.exec() != QDialog::Accepted) {
496 if (d.exec() != QDialog::Accepted) {
508 ui->treeView->setCurrentIndex(QModelIndex());
512 m_tree->setPass(activePass);
514 m_qtPass->clipboard().setAutoclearTimer();
540 ui->statusBar->showMessage(tr(
"Updating password-store"), 2000);
550 ui->statusBar->showMessage(tr(
"Updating password-store"), 2000);
556 return m_tree->fileFor(index, forPass);
560 bool cleared =
ui->treeView->currentIndex().flags() == Qt::NoItemFlags;
561 QString file =
getFile(index,
true);
562 ui->passwordName->setText(file);
563 if (!file.isEmpty() && !cleared) {
571 ui->actionEdit->setEnabled(
false);
572 ui->actionDelete->setEnabled(
true);
579 if (fileOrFolder.isFile()) {
588 ui->treeView->clearSelection();
589 ui->actionEdit->setEnabled(
false);
590 ui->actionDelete->setEnabled(
false);
591 ui->passwordName->setText(
"");
597 ui->textBrowser->clear();
633 p_output, templ, allFields, [
this, &s](
const QString &name) {
636 QString output = p_output;
650 output =
"***" + tr(
"Content hidden") +
"***";
670 const QString &file) {
678 if (p_output.isEmpty()) {
680 flashText(tr(
"Could not decrypt this password entry"),
true);
689 if (!shown.isEmpty()) {
699 const QStringList templ =
705 const std::optional<Totp::Settings> settings =
707 if (settings.has_value()) {
711 flashText(tr(
"No OTP code found in this password entry"),
true);
718 const bool grepWasVisible =
ui->grepResultsList->isVisible();
719 ui->grepResultsList->clear();
720 if (grepWasVisible) {
721 ui->grepResultsList->setVisible(
false);
722 ui->treeView->setVisible(
true);
725 ui->grepButton->blockSignals(
true);
726 ui->grepButton->setChecked(
false);
727 ui->grepButton->blockSignals(
false);
728 ui->lineEdit->blockSignals(
true);
729 ui->lineEdit->clear();
730 ui->lineEdit->blockSignals(
false);
731 ui->lineEdit->setPlaceholderText(tr(
"Search password"));
735 QString output =
"***" + tr(
"Password and content hidden") +
"***";
736 ui->textBrowser->setHtml(output);
738 ui->textBrowser->setHtml(
"");
756 ui->treeView->setEnabled(state);
757 ui->lineEdit->setEnabled(state);
758 ui->actionAddPassword->setEnabled(state);
759 ui->actionAddFolder->setEnabled(state);
760 ui->actionUsers->setEnabled(state);
761 ui->actionConfig->setEnabled(state);
764 const bool uiEnabled = state;
766 state &=
ui->treeView->currentIndex().isValid();
767 ui->actionDelete->setEnabled(state);
768 ui->actionEdit->setEnabled(state);
779 if (geometry.isEmpty() || !restoreGeometry(geometry)) {
791 QTimer::singleShot(10,
this, &MainWindow::hide);
802 this, tr(
"About QtPass"),
803 tr(
"<h3>QtPass %1</h3>"
804 "<p>A multi-platform GUI for <a "
805 "href=\"https://www.passwordstore.org/\">"
806 "pass</a>, the standard Unix password manager.</p>"
807 "<p><a href=\"https://qtpass.org/\">qtpass.org</a> · "
808 "<a href=\"https://github.com/IJHack/QtPass\">Source and "
810 "<p>Copyright © 2014–%2 IJhack. Licensed under the "
811 "<a href=\"https://www.gnu.org/licenses/gpl-3.0.html\">GNU GPL "
812 "version 3</a> or later.</p>")
813 .arg(QStringLiteral(VERSION),
814 QString::number(QDate::currentDate().year())));
820 ui->statusBar->showMessage(tr(
"Looking for: %1").arg(arg1), 1000);
821 ui->treeView->expandAll();
828 ui->passwordName->setText(
"");
829 ui->actionEdit->setEnabled(
false);
830 ui->actionDelete->setEnabled(
false);
835 QString query =
ui->lineEdit->text();
837 if (query.isEmpty()) {
838 ui->treeView->collapseAll();
846 for (
const QString &word :
847 query.split(QLatin1Char(
' '), Qt::SkipEmptyParts)) {
848 words << QRegularExpression::escape(word);
850 QRegularExpression regExp(words.join(QStringLiteral(
".*")),
851 QRegularExpression::CaseInsensitiveOption);
854 if (
m_tree->
proxy().rowCount() > 0 && !query.isEmpty()) {
857 ui->actionEdit->setEnabled(
false);
858 ui->actionDelete->setEnabled(
false);
863 qCDebug(lcQtPass) <<
"on_lineEdit_returnPressed"
867 const QString query =
ui->lineEdit->text();
868 if (!query.isEmpty()) {
869 ui->grepResultsList->clear();
870 ui->statusBar->showMessage(tr(
"Searching…"));
872 QApplication::setOverrideCursor(Qt::WaitCursor);
877 QApplication::restoreOverrideCursor();
879 ui->grepResultsList->clear();
880 ui->grepResultsList->setVisible(
false);
881 ui->treeView->setVisible(
true);
896 ui->lineEdit->setPlaceholderText(tr(
"Search content (regex)"));
899 ui->lineEdit->setToolTip(
900 tr(
"Content search uses Perl-compatible regular expressions (PCRE)."));
901 ui->lineEdit->clear();
904 ui->grepResultsList->setVisible(
false);
908 QApplication::restoreOverrideCursor();
911 ui->lineEdit->blockSignals(
true);
912 ui->lineEdit->clear();
913 ui->lineEdit->blockSignals(
false);
914 ui->lineEdit->setPlaceholderText(tr(
"Search password"));
915 ui->lineEdit->setToolTip(QString());
916 ui->grepResultsList->clear();
917 ui->grepResultsList->setVisible(
false);
918 ui->treeView->setVisible(
true);
924 const QList<QPair<QString, QStringList>> &results) {
927 QApplication::restoreOverrideCursor();
937 ui->grepResultsList->clear();
938 if (results.isEmpty()) {
939 ui->statusBar->showMessage(tr(
"No matches found."), 3000);
940 ui->grepResultsList->setVisible(
false);
941 ui->treeView->setVisible(
true);
948 bool stopped =
false;
949 for (
const auto &pair : results) {
955 auto *entryItem =
new QTreeWidgetItem(
ui->grepResultsList);
956 entryItem->setText(0, pair.first);
957 entryItem->setData(0, Qt::UserRole, pair.first);
958 for (
const QString &line : pair.second) {
959 auto *lineItem =
new QTreeWidgetItem(entryItem);
963 lineItem->setText(0, tr(
"… more matches in this entry"));
965 lineItem->setText(0, hideContent ?
"***" + tr(
"Content hidden") +
"***"
969 lineItem->setData(0, Qt::UserRole, pair.first);
972 ui->grepResultsList->expandAll();
973 ui->treeView->setVisible(
false);
974 ui->grepResultsList->setVisible(
true);
977 ui->statusBar->showMessage(
978 tr(
"Showing the first %n match(es); search for something narrower "
980 nullptr, totalLines),
983 ui->statusBar->showMessage(tr(
"Found %n match(es)",
nullptr, totalLines) +
985 tr(
"in %n entr(ies).",
nullptr, entries),
995 const QString entry = item->data(0, Qt::UserRole).toString();
998 const QString fullPath =
999 QDir::cleanPath(QDir(s.
passStore).filePath(entry +
".gpg"));
1001 if (!proxyIndex.isValid())
1003 ui->treeView->setCurrentIndex(proxyIndex);
1006 ui->grepResultsList->clear();
1007 ui->grepResultsList->setVisible(
false);
1008 ui->treeView->setVisible(
true);
1009 ui->treeView->scrollTo(proxyIndex);
1010 ui->treeView->setFocus();
1015 ui->treeView->setCurrentIndex(index);
1020 int numRows = proxy.rowCount(parentIndex);
1021 for (
int row = 0; row < numRows; ++row) {
1022 QModelIndex index = proxy.index(row, 0, parentIndex);
1023 if (
m_tree->fileInfo(index).isFile()) {
1026 if (proxy.hasChildren(index)) {
1027 QModelIndex childFile =
firstFile(index);
1028 if (childFile.isValid())
1032 return QModelIndex();
1041 QMessageBox::warning(
this, tr(
"Invalid name"),
1042 tr(
"That name would resolve outside the password "
1043 "store. Please choose a different name."));
1057 if (folder.isEmpty()) {
1062 QStringList folders{QString()};
1064 for (
const QString &path : found) {
1065 const QString rel = QDir(storePath).relativeFilePath(path);
1066 if (!rel.startsWith(u
'.') && !rel.contains(QStringLiteral(
"/."))) {
1070 std::sort(folders.begin() + 1, folders.end());
1072 QDir(storePath).relativeFilePath(folder));
1073 QHash<QString, QStringList> templates =
1075 if (!templates.isEmpty()) {
1076 QString defaultTemplate =
1083 ui->treeView->setFocus();
1090 const QString path = QDir::separator() + file;
1093 this, tr(
"Delete password?"),
1094 tr(
"Are you sure you want to delete %1?").arg(path));
1101 tr(
"Are you sure you want to delete %1 and the whole content?").arg(path);
1104 QStringList skipped;
1106 m_tree->fileSystem().rootPath() + path, {QStringLiteral(
"*")}, &skipped);
1107 const bool unexpected =
1108 !skipped.isEmpty() ||
1109 std::any_of(content.cbegin(), content.cend(), [](
const QString &entry) {
1110 return QFileInfo(entry).suffix() != QLatin1String(
"gpg");
1113 question += QStringLiteral(
"\n\n") +
1114 tr(
"Attention: there are unexpected files in the given "
1115 "folder, check them before continuing.");
1124 this, tr(
"Delete link?"),
1125 tr(
"%1 is a symbolic link or junction. Remove the link? What it "
1126 "points to is left alone.")
1127 .arg(QDir::separator() + file));
1131 const QModelIndex currentIndex =
ui->treeView->currentIndex();
1132 if (!currentIndex.isValid()) {
1138 const QString file =
1140 const QString folder =
1148 const bool confirmed =
1172 QString file =
getFile(
ui->treeView->currentIndex(),
true);
1173 if (file.isEmpty()) {
1174 flashText(tr(
"No password selected for OTP generation"),
true);
1179 flashText(tr(
"No OTP code found in this password entry"),
true);
1187 const QString shown =
1189 if (!shown.isEmpty()) {
1206 QString file =
getFile(
ui->treeView->currentIndex(),
true);
1218 ui->treeView->setFocus();
1225 if (message.isEmpty()) {
1228 ui->treeView->expandAll();
1229 ui->lineEdit->setText(message);
1236 bool activeGone =
false;
1238 if (profiles.isEmpty()) {
1239 ui->profileWidget->hide();
1241 ui->profileWidget->show();
1244 const QSignalBlocker quiet(
ui->profileBox);
1245 ui->profileBox->clear();
1246 for (
auto i = profiles.cbegin(); i != profiles.cend(); ++i) {
1247 if (!i.key().isEmpty()) {
1248 ui->profileBox->addItem(i.key());
1251 ui->profileBox->model()->sort(0);
1254 ui->profileBox->setCurrentIndex(index);
1255 }
else if (
ui->profileBox->count() > 0) {
1259 ui->profileBox->setCurrentIndex(0);
1277 ui->profileBox->setEnabled(
m_uiEnabled &&
ui->profileBox->count() > 1 &&
1288 const QSignalBlocker quiet(
ui->profileBox);
1295 ui->grepButton->setChecked(
false);
1298 ui->lineEdit->clear();
1310 ui->statusBar->showMessage(tr(
"Profile changed to %1").arg(name), 2000);
1316 ui->treeView->setCurrentIndex(QModelIndex());
1347 QApplication::quit();
1352 if ((obj ==
ui->toolBar || obj == menuBar()) &&
1353 event->type() == QEvent::PaletteChange) {
1360 if (obj ==
ui->lineEdit &&
event->type() == QEvent::KeyPress) {
1361 auto *key =
dynamic_cast<QKeyEvent *
>(
event);
1362 if (key !=
nullptr && key->key() == Qt::Key_Down) {
1363 ui->treeView->setFocus();
1366 return QObject::eventFilter(obj,
event);
1376 constexpr int kStaleToolsAreaLightness = 64;
1380 const int appLightness = QApplication::palette()
1381 .color(QPalette::Active, QPalette::Window)
1383 for (QWidget *bar : {
static_cast<QWidget *
>(
ui->toolBar),
1384 static_cast<QWidget *
>(menuBar())}) {
1385 if (!bar->testAttribute(Qt::WA_SetPalette)) {
1388 const int barLightness =
1389 bar->palette().color(QPalette::Active, QPalette::Window).lightness();
1390 if (qAbs(barLightness - appLightness) <= kStaleToolsAreaLightness) {
1393 bar->setPalette(QPalette());
1397 bar->setBackgroundRole(QPalette::Window);
1398 bar->setAutoFillBackground(
true);
1403 switch (
event->key()) {
1404 case Qt::Key_Delete:
1407 case Qt::Key_Return:
1413 case Qt::Key_Escape:
1414 ui->lineEdit->clear();
1423 auto *shareMenu =
new QMenu(tr(
"Share"), &contextMenu);
1424 contextMenu.addMenu(shareMenu);
1427 const bool gpgIdExists = !gpgIdPath.isEmpty() && QFile(gpgIdPath).exists();
1429 const bool gpgAvailable =
1430 !exePath.isEmpty() &&
1433 QAction *reencrypt = shareMenu->addAction(tr(
"Re-encrypt all passwords"));
1434 reencrypt->setEnabled(gpgIdExists && gpgAvailable);
1435 connect(reencrypt, &QAction::triggered,
this,
1438 QAction *exportKey = shareMenu->addAction(tr(
"Export my public key..."));
1439 exportKey->setEnabled(gpgAvailable);
1442 QAction *addRecipientAction = shareMenu->addAction(tr(
"Add recipient..."));
1443 addRecipientAction->setEnabled(gpgIdExists && gpgAvailable);
1444 connect(addRecipientAction, &QAction::triggered,
this,
1447 QAction *shareHelp = shareMenu->addAction(tr(
"What is this?"));
1453 const QModelIndex index =
ui->treeView->indexAt(pos);
1454 const bool selected = index.isValid();
1456 ui->treeView->clearSelection();
1457 ui->actionDelete->setEnabled(
false);
1458 ui->actionEdit->setEnabled(
false);
1460 ui->treeView->setCurrentIndex(index);
1461 const QPoint globalPos =
ui->treeView->viewport()->mapToGlobal(pos);
1462 const QFileInfo fileOrFolder =
m_tree->
fileInfo(
ui->treeView->currentIndex());
1463 const bool isDir = fileOrFolder.isDir();
1466 if (!selected || isDir) {
1467 const std::array<std::pair<QString, void (
MainWindow::*)()>, 4> onFolder{{
1473 for (
const auto &[text, slot] : onFolder) {
1474 connect(contextMenu.addAction(text), &QAction::triggered,
this, slot);
1476 }
else if (fileOrFolder.isFile()) {
1477 connect(contextMenu.addAction(tr(
"Edit")), &QAction::triggered,
this,
1481 contextMenu.addSeparator();
1483 connect(contextMenu.addAction(tr(
"Rename folder")), &QAction::triggered,
1485 }
else if (fileOrFolder.isFile()) {
1486 connect(contextMenu.addAction(tr(
"Rename password")), &QAction::triggered,
1489 connect(contextMenu.addAction(tr(
"Delete")), &QAction::triggered,
this,
1495 contextMenu.exec(globalPos);
1499 QMenu *contextMenu =
ui->textBrowser->createStandardContextMenu(pos);
1502 contextMenu->setParent(
this, contextMenu->windowFlags());
1503 QPoint globalPos =
ui->textBrowser->viewport()->mapToGlobal(pos);
1505 contextMenu->exec(globalPos);
1512 QString path = QDir::toNativeSeparators(dir);
1513 QDesktopServices::openUrl(QUrl::fromLocalFile(path));
1521 QInputDialog::getText(
this, tr(
"New folder"),
1522 tr(
"New folder: \n(Will be placed in %1 )")
1524 QLineEdit::Normal,
"", &ok);
1525 if (!ok || newdir.isEmpty()) {
1531 newdir = QDir::cleanPath(newdir.prepend(dir));
1538 tr(
"Failed to create folder: %1").arg(newdir));
1545 const bool signingConfigured = !s.
passSigningKey.trimmed().isEmpty();
1546 if (s.
addGPGId && !signingConfigured) {
1553 tr(
"Failed to create .gpg-id file in: %1").arg(newdir));
1562 QString srcDirName = QDir(srcDir).dirName();
1564 QInputDialog::getText(
this, tr(
"Rename folder"), tr(
"Rename folder to: "),
1565 QLineEdit::Normal, srcDirName, &ok);
1566 if (!ok || newName.isEmpty()) {
1569 QString destDir = srcDir;
1570 destDir.replace(srcDir.lastIndexOf(srcDirName), srcDirName.length(), newName);
1578 if (!file.isEmpty()) {
1595 QString file =
getFile(
ui->treeView->currentIndex(),
false);
1596 QString filePath = QFileInfo(file).path();
1597 QString fileName = QFileInfo(file).fileName();
1598 if (fileName.endsWith(
".gpg", Qt::CaseInsensitive)) {
1603 QInputDialog::getText(
this, tr(
"Rename file"), tr(
"Rename file to: "),
1604 QLineEdit::Normal, fileName, &ok);
1605 if (!ok || newName.isEmpty()) {
1608 QString newFile = QDir(filePath).filePath(newName);
1618 if (fileOrFolder.isFile()) {
1619 QString file =
getFile(
ui->treeView->currentIndex(),
true);
1630 const QString &file) {
1637 const QString first = text.left(text.indexOf(QLatin1Char(
'\n')));
1642 flashText(tr(
"This entry holds an OTP secret, not a password"),
true);
1649 ui->statusBar->showMessage(msg, timeout);
1654 if (!checkDir.exists()) {
1656 tr(
"Directory does not exist: %1").arg(dir));
1664 this, tr(
"Re-encrypt passwords"),
1665 tr(
"Re-encrypt all passwords in %1?\n\n"
1666 "This will re-encrypt ALL password files in this folder "
1667 "using the current recipients defined in .gpg-id.\n\n"
1668 "This may rewrite many files and cannot be undone easily.\n\n"
1670 .arg(QDir(dir).dirName()));
1692 ui->treeView->setDisabled(
true);
1695 auto *progress =
new QProgressDialog(tr(
"Re-encrypting passwords..."),
1696 tr(
"Cancel"), 0, 0,
this);
1697 progress->setWindowTitle(tr(
"Re-encrypt passwords"));
1698 progress->setWindowModality(Qt::WindowModal);
1699 progress->setAutoClose(
false);
1700 progress->setAutoReset(
false);
1701 progress->setMinimumDuration(0);
1702 connect(progress, &QProgressDialog::canceled,
this, [
this]() {
1715 tr(
"Re-encrypting passwords: %1 of %2").arg(current).arg(total));
1734 if (identity.isEmpty()) {
1735 QMessageBox::information(
1736 this, tr(
"Export public key"),
1737 tr(
"<h3>Export your public key</h3>"
1738 "<p>No signing key is configured. Set one in QtPass Settings "
1739 "> GPG keys, or run this in a terminal:</p>"
1740 "<pre>gpg --armor --export --output my_key.asc <your-key-id"
1742 "<p>Then send the file to your teammates.</p>"));
1746 if (gpgExe.isEmpty()) {
1747 gpgExe = QStringLiteral(
"gpg");
1749 QStringList args = {
"--armor",
"--export"};
1750 args.append(identity.split(
' ', Qt::SkipEmptyParts));
1754 if (exitCode != 0 || stdOut.isEmpty()) {
1756 tr(
"Could not export public key for %1.\n\n%2")
1757 .arg(identity, stdErr.isEmpty()
1758 ? tr(
"No output from gpg.")
1784 this, tr(
"Not a folder of the store"),
1785 tr(
"%1 is, or lies behind, a symbolic link or junction. What that "
1786 "points to is not part of the password store and is left alone.")
1787 .arg(QDir::toNativeSeparators(QDir::cleanPath(dir))));
1792 QMessageBox::information(
1793 this, tr(
"Sharing passwords with GPG"),
1794 tr(
"<h3>Sharing passwords with GPG</h3>"
1795 "<p>To share passwords with other users:</p>"
1797 "<li><b>Export your public key</b> and send it to teammates</li>"
1798 "<li><b>Import teammates' public keys</b> into your GPG keyring</li>"
1799 "<li><b>Re-encrypt passwords</b> so all recipients can decrypt "
1802 "<p>Only people who have a matching secret key can decrypt the "
1804 "<p><b>Tip:</b> Use the same GPG key for all shared folders.</p>"
1805 "<p>See the FAQ for more details.</p>"));
1814 ui->actionPush->setVisible(usable);
1815 ui->actionUpdate->setVisible(usable);
1817 const QList<QAction *> actions =
ui->toolBar->actions();
1818 const qsizetype at = actions.indexOf(
ui->actionPush);
1819 if (at > 0 && actions.at(at - 1)->isSeparator()) {
1820 actions.at(at - 1)->setVisible(usable);
1830 ui->actionOtp->setVisible(
true);
1836 ui->grepButton->setVisible(enabled);
1837 ui->grepCaseButton->setVisible(enabled);
1839 ui->grepButton->setChecked(
false);
1844 ui->actionPush->setEnabled(state);
1845 ui->actionUpdate->setEnabled(state);
1864 ui->actionShowProcessOutput->setChecked(
void trackCopied(const QString &text)
Track text that got onto the clipboard some other way.
void copyText(const QString &text)
Copy text into the system clipboard (or the X11 primary selection when configured) and arm the autocl...
void statusMessage(const QString &message)
Something worth showing in the status bar happened.
The ConfigDialog handles the configuration interface.
void emptyClicked()
Emitted after deselect() has cleared the selection because of a single click on empty space or on a s...
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.
static auto parseWslCommand(const QString &app) -> std::optional< WslCommand >
Parse a configured executable as a WSL command.
Dialog showing an ASCII-armored public GPG key for sharing.
Represents the parsed contents of a password file.
static auto boundedForDisplay(const QString &text) -> QString
text cut to kMaxDisplayLines lines, as getRemainingDataForDisplay() is: for showing an entry as it is...
auto getNamedValues() const -> NamedValues
static auto parse(const QString &fileContent, const QStringList &templateFields, bool allFields, const std::function< bool(const QString &)> &alsoField={}) -> FileContent
parse parses the given fileContent in a FileContent object. The password is accessible through getPas...
auto getRemainingDataForDisplay() const -> QString
Like getRemainingData but without data that should not be displayed (like a TOTP secret).
auto getOtpUri() const -> QString
The entry's raw one-time password configuration, if it has one.
auto getPasswordForDisplay() const -> QString
Like getPassword but empty when the password line is itself an otpauth URI.
static auto isOtpUriValue(const QString &value) -> bool
Whether a field value is an otpauth URI, and therefore a secret.
The first start of QtPass: find GnuPG (and pass and Git), make sure there is a secret key,...
void clearGrepMode()
Drop the mode flag only, without touching busy/cancelled state.
auto beginSearch() -> bool
Begin a search for a non-empty query.
auto leaveGrepMode() -> bool
Leave content-search mode (search button toggled off).
auto finishSearch() -> FinishOutcome
Record that a search finished and report required side effects.
void enterGrepMode()
Enter content-search mode (search button toggled on).
auto cancelSearch() -> bool
Cancel the current search (e.g. query cleared).
auto inGrepMode() const -> bool
Whether content-search mode is currently active.
Implementation that imitates 'pass' when the real tool is unavailable.
void reencryptProgress(int current, int total)
Re-encryption progress: current of total files checked.
void endReencryptPath()
A reencryptPath() run is over, whether it finished, failed, was cancelled or was refused; the main wi...
void startReencryptPath()
A reencryptPath() run is about to start its worker thread.
GrepSearchController m_grep
Mode/busy/cancelled state of the content search.
void dropStaleToolsAreaPalettes()
Drop a style-imposed menu bar or toolbar palette that belongs to the other theme (Breeze header palet...
void startReencryptPath()
Begin a re-encryption pass on the current path.
void addPassword()
Toolbar/context-menu "Add password": open PasswordDialog for a new entry in the current folder.
void closeEvent(QCloseEvent *event) override
Save window state and geometry on close.
void cancelOtpRequest()
Forget the pending OTP and copy requests.
void renameFolder()
Context menu "Rename folder": ask for a new name and Move the current folder, refusing a target outsi...
void initTextBrowser()
Font, wrapping and link handling of the text browser, per the settings.
void enableGitButtons(const bool &state)
Enable or disable the Push and Pull actions together.
void onConfig()
Toolbar "Config": config(), ignoring its result.
void initToolBarButtons()
~MainWindow() override
Save the window state (a quit from the tray menu or a SIGTERM never delivers closeEvent()) and delete...
void endReencryptPath()
Finish a re-encryption pass on the current path.
void onGrepFinished(const QList< QPair< QString, QStringList > > &results)
Handle results from a completed grep search.
void setPassword(const QString &file, bool isNew=true)
Run PasswordDialog for a new or existing entry. For a new one the dialog gets the store's real folder...
void executeWrapperStarted()
Slot called when an external process wrapper has started.
PasswordDisplayPanel * m_displayPanel
Renders decrypted fields into the grid; created in initDisplayPanel(), parented to this window.
void updateGitButtonVisibility(bool uiEnabled=true)
Show Push and Pull only when Git is in use; enable them only while the interface is.
void onDelete()
Toolbar "Delete" or the Delete key: confirm, then remove the current entry or folder....
void showEvent(QShowEvent *event) override
First-show hook used to focus the search input once the window is actually mapped (avoids races with ...
void editPassword(const QString &file)
Open PasswordDialog on an existing entry, after a blocking pull when auto-pull is on....
void changeEvent(QEvent *event) override
React to language or window state changes.
QPointer< QProgressDialog > m_reencryptProgress
void on_profileBox_currentTextChanged(const QString &name)
The user picked another profile: save its store, key and Git flags as the active settings,...
void addFolder()
Toolbar/context-menu "Add folder": ask for a name, create the folder under the current one (refusing ...
void updateGrepButtonVisibility()
ProcessOutputPanel * m_processOutput
void messageAvailable(const QString &message)
Handle an incoming inter-process message (single-instance mode).
MainWindow(const QString &searchText=QString(), QWidget *parent=nullptr)
Construct the main window.
void copyPasswordFromTreeview()
Ctrl+C on the tree: decrypt the current entry and let passwordFromFileToClipboard() copy its first li...
void connectPassSignals(Pass *pass)
Connect the signals of one backend that the window answers itself: errors, critical messages,...
StoreTree * m_tree
The store as shown in the tree: models, view setup, path mapping.
void reencryptProgress(int current, int total)
Update the re-encryption progress dialog.
void keyPressEvent(QKeyEvent *event) override
Handle keyboard shortcuts.
void addShareMenu(QMenu &contextMenu, const AppSettings &s)
Add the Share submenu for the folder under the cursor: the entries are enabled only where a recipient...
void on_treeView_doubleClicked(const QModelIndex &index)
A double-click on a tree entry opens it for editing; folders are left to the view.
void showShareHelp()
Share menu "What is this?": the explanation of sharing with GPG.
void onTimeoutSearch()
searchTimer fired: filter the tree on the typed words (matched literally, in order,...
void onPush()
Trigger a git push operation.
void showStatusMessage(const QString &msg, int timeout=2000)
Show a message in the status bar for the given duration.
void focusInput()
Select-all and focus the search box once the window is visible; sets m_firstShowCompleted only on suc...
void on_lineEdit_returnPressed()
Enter in the search box: in content-search mode start (or, for an empty query, cancel) the grep; othe...
auto refuseLinkedFolder(const QString &dir) -> bool
Refuse, with a message, a tree-picked folder that is or lies behind a symlink or junction: what it po...
QString m_copyRequestFile
void on_grepButton_toggled(bool checked)
The content-search toggle changed: switch the search box between name filtering and regex content sea...
void selectFirstFile()
Make the first entry (depth first) under the store root current.
auto confirmDeletion(const QString &file, bool isDir) -> bool
Ask before deleting an entry or a folder, naming what goes and warning when the folder holds anything...
void onOperationError()
An operation ended in an error before or instead of a result: forget the pending requests and what th...
void updateProcessOutputVisibility()
void on_grepResultsList_itemClicked(QTreeWidgetItem *item, int column)
A content-search result was clicked: select the entry in the tree, show it, and go back to the tree (...
void reencryptPath(const QString &dir)
Share menu "Re-encrypt all passwords": confirm, lock the UI via startReencryptPath() and have Imitate...
void passwordFromFileToClipboard(const QString &text, const QString &file)
Copy the first line of a decrypted entry (Ctrl+C). Ignores decrypts of anything but the entry copyPas...
auto confirmPathInStore(const QString &candidate) -> bool
Guard the input dialogs (create, move, rename) against names like ../../etc/passwd or absolute paths ...
void showContextMenu(const QPoint &pos)
Build and show the tree's context menu for the item under the cursor: folder actions (open,...
void updateProfileBoxEnabled()
Enable the profile box only when there is more than one profile, the interface is enabled and the bac...
void critical(const QString &title, const QString &msg)
Display a critical error dialog.
void applyWindowFlagsSettings()
void updateProfileBox()
Fill the profile box from the settings, the active profile selected, without switching profiles while...
void updateOtpButtonVisibility(bool uiEnabled=true)
Refresh the OTP toolbar action from settings.
void addRecipient(const QString &dir)
Share menu "Add recipient": open UsersDialog for dir (keys already in the keyring only).
bool m_firstShowCompleted
Set once focusInput() has actually focused the search box, so later show events leave the focus alone...
void onEdit()
Toolbar "Edit" or a double-click: editPassword() on the current entry.
void restoreWindow()
Restore window geometry and state from saved settings.
void onOtp()
Toolbar "OTP": copy the current entry's one-time code. Uses the code the panel already shows for this...
auto confirmLinkRemoval(const QString &file) -> bool
Ask before removing a folder that is a link, which takes the link and leaves what it points to.
void showBrowserContextMenu(const QPoint &pos)
Show the text browser's standard context menu, reparented to the window so the browser's stylesheet d...
QScopedPointer< Ui::MainWindow > ui
The widgets generated from mainwindow.ui.
auto eventFilter(QObject *obj, QEvent *event) -> bool override
Filter events from watched objects.
void showAbout()
Show the About box: version, project link, licence.
static constexpr int UiWatchdogMs
Interval of m_uiWatchdog in milliseconds.
void openFolder()
Context menu "Open folder with file manager" on the current folder.
void exportPublicKey()
Share menu "Export my public key": run gpg --armor --export for the configured signing key and show t...
void initTrayIcon()
Create m_tray and add the menu bar toggle to its menu; gives up (m_tray stays null) when no system tr...
void flashText(const QString &text, const bool isError, const bool isHtml=false)
Display a transient message in the text panel.
void initStatusBar()
Welcome message and the permanent logo in the status bar.
void initDisplayPanel()
The grid of decrypted fields and what its buttons ask for.
void otpFromFileToClipboard(const QString &output, const QString &file)
Generate a one-time password from decrypted content and copy it. Ignores decrypts of anything but the...
void clearPanel(bool notify=true)
Empty the display panel and the text browser, and leave content search if its results were showing....
void setUiElementsEnabled(bool state)
Enable or disable the main UI elements.
auto event(QEvent *event) -> bool override
Notice an application palette change, the theme switch that makes a style-imposed bar palette suspect...
void applyTextBrowserSettings()
auto config() -> bool
Open the configuration dialog.
auto getCurrentTreeViewIndex() -> QModelIndex
Return the currently selected index in the tree view.
void onUpdate(bool block=false)
Toolbar "Update": git pull.
void deselect()
Clear the current tree view selection.
auto getFile(const QModelIndex &index, bool forPass) -> QString
StoreTree::fileFor() on the tree.
void onProcessOutput(const QString &output, bool isError, Enums::PROCESS pid=Enums::INVALID)
Handle generic process output for display in output panel.
void passShowHandler(const QString &output, const QString &file=QString())
Render a decrypted entry: fields into the display panel, the rest into the text browser,...
void on_treeView_clicked(const QModelIndex &index)
Handle a click on an item in the tree view.
void onUsers()
Toolbar/context-menu "Users": open UsersDialog for the current folder, unless it lies behind a link.
void destroyTrayIcon()
Delete m_tray and reset it to null.
QtPass * m_qtPass
The UI-neutral glue to the backends (output, status, clipboard, QR codes); created in the constructor...
auto firstFile(QModelIndex parentIndex) -> QModelIndex
Depth-first search for the first entry under a folder.
void renamePassword()
Context menu "Rename password": ask for a new name and Move the current entry within its folder,...
void on_lineEdit_textChanged(const QString &arg1)
The search box changed (name filtering only): drop the pending decrypt and the panel,...
static auto isMoreMarker(const QString &line) -> bool
Whether a line in a result is the marker for "more matches inthis entry" rather than a match.
static auto isStoppedMarker(const QPair< QString, QStringList > &result) -> bool
Whether a result is the marker for "the search stopped atkMaxMatches, more entries were not searched"...
Abstract base class for password store operations.
void startingExecuteWrapper()
Emitted each time a queued process is about to start, and by the refusals that go on to emit processE...
void finishedAnyWithPid(const QString &out, const QString &err, Enums::PROCESS pid)
A process of any kind finished successfully and its output cannot contain a secret.
static auto getGpgIdPath(const QString &for_file, const QString &passStore) -> QString
Get .gpg-id file path for a password file.
void finishedShow(const QString &out, const QString &file)
Emitted when a Show() succeeds.
void statusMsg(const QString &msg, int timeout)
Progress or a non-fatal problem worth a line in the status bar ("Creating backup commit",...
static auto seedGpgIdFile(const QString &newDir, const QString &passStore) -> bool
Seed a new folder's .gpg-id from the recipients it inherits.
void finishedGrep(const QList< QPair< QString, QStringList > > &results)
The newest Grep() is over; an empty list means no entry matched.
void processErrorExit(int exitCode, const QString &err)
An operation ended in failure: its process exited non-zero, could not be started or crashed,...
void updateEnv()
Update environment for subprocesses.
void idle()
Nothing of the store's runs or waits any more (isIdle()).
void critical(const QString &title, const QString &message)
Something went wrong that the user has to be told about in a dialog, such as a refused path or a fail...
Dialog for creating a password entry or editing an existing one.
void setAvailableTemplates(const QHash< QString, QStringList > &templates, const QString &defaultTemplate)
Set available templates from file and select default.
void copied(const QString &text)
Text was copied out of the password, a field or the body, marked as a secret: for ClipboardManager::t...
void setNewEntryLocation(const QString &storeRoot, const QStringList &folders, const QString ¤tFolder)
Let a new entry be named inside the dialog: a folder picker over the store's folders and a name field...
auto isSecret(const QString &field, const AppSettings &s) const -> bool
Whether a field is a secret "Hide password" hides: one a template marks (setMarkedSecrets()),...
void qrRequested(const QString &text)
Emitted when a field's QR button is clicked.
void refreshPalette()
Re-derive palette-dependent styling after a runtime theme change.
void setMarkedSecrets(const QStringList &names)
Set the field names a template marks as secret.
void displayFields(const QString &password, const NamedValues &namedValues, const AppSettings &s, const QString &otpConfig={})
Render the password and template fields of a decrypted entry.
void clear()
Remove all field rows and collapse the container spacing.
PasswordDisplayPanel(QGridLayout *grid, QBoxLayout *container, QWidget *widgetParent, QObject *parent=nullptr)
Construct a panel that renders into the given layouts.
void textCopied(const QString &text)
Text was selected and copied out of a field's value (Ctrl+C, the context menu, a drag,...
void copyRequested(const QString &text)
Emitted when a field's copy button is clicked.
auto currentOtpCode() const -> QString
The one-time password currently on display, if there is one.
void editRequested()
Emitted on a double-click anywhere on a field row: the user wants to change what they are looking at.
static auto isPathInStore(const QString &storeRoot, const QString &candidate) -> bool
Check that a candidate path resolves inside the password store root, after following symlinks and res...
static auto isSensitiveProcess(Enums::PROCESS pid) -> bool
Whether a process's output may carry secrets and must never reach this long-lived panel (pass show,...
ProcessOutputPanel(QWidget *parent=nullptr)
Build the console (Clear button + read-only text edit).
static auto processName(Enums::PROCESS pid) -> QString
Human-readable command label for a process id.
void append(const QString &output, bool isError, const QString &linePrefix=QString())
Append output, one numbered line per non-empty input line.
void operationFinished()
A backend operation is over, successfully or not; the interface can be enabled again.
void statusMessage(const QString &message, int timeout)
A short message for the status bar.
static auto formatOutput(QString output, const QString &prefix=QString(), const QString &postfix=QString()) -> QString
Turn a process' plain-text output into the HTML the text browser shows: http(s) URLs become links,...
void entryInserted()
An entry was written; the view of the current entry is stale.
void pushRequested()
The store changed and the settings ask for an automatic push.
void outputReady(const QString &html)
Formatted output (see formatOutput()) or an error rendered in colour, ready for the text browser.
auto clipboard() -> ClipboardManager &
The clipboard handling for this application instance.
void init()
Resolve the password store and the executables and migrate the settings of an older version (fresh-in...
QtPass(QObject *parent=nullptr)
Construct the glue and connect it to both pass backends.
void showTextAsQRCode(const QString &text)
Render text as a QR code with qrencode and show it in a popup at the cursor; failures are reported th...
static auto getPass() -> Pass *
Get currently active pass backend instance.
static auto isUseGit(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether Git integration is enabled.
static auto isUseOtp(const bool &defaultValue=true) -> bool
Check whether OTP support is enabled.
static auto getPassStore(const QString &defaultValue=QVariant().toString()) -> QString
Get password store directory path.
static auto load() -> AppSettings
Load all flat settings into an AppSettings value object.
static auto isUseGrepSearch(const bool &defaultValue=false) -> bool
Check whether content search is enabled.
static auto getProfiles() -> Profiles
Get all configured profiles.
static auto getRealPass() -> RealPass *
Get real pass backend instance.
static auto getProfile(const QString &defaultValue=QVariant().toString()) -> QString
Get active profile name.
static auto isShowProcessOutput(const bool &defaultValue=false) -> bool
Get showProcessOutput setting.
static void setSavestate(const QByteArray &saveState)
Save window state.
static auto isAlwaysOnTop(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether main window should stay always on top.
static auto getImitatePass() -> ImitatePass *
Get imitate pass backend instance.
static auto isHideOnClose(const bool &defaultValue=QVariant().toBool()) -> bool
Check whether closing the window hides the application.
static void save(const AppSettings &settings)
Persist an AppSettings value object to the singleton store.
static void setGeometry(const QByteArray &geometry)
Save window geometry.
static auto getGeometry(const QByteArray &defaultValue=QVariant().toByteArray()) -> QByteArray
Get saved window geometry.
static auto getSavestate(const QByteArray &defaultValue=QVariant().toByteArray()) -> QByteArray
Get saved window state.
static auto backendsIdle() -> bool
Whether no backend, the active one or one kept from before a switch, runs or waits for anything (Pass...
void copied(const QString &text)
Selected text was copied out of the browser.
QSortFilterProxyModel for filtering and displaying password store.
auto fileInfo(const QModelIndex &index) const -> QFileInfo
File system information for a view index.
auto rootIndex() -> QModelIndex
The proxy's root index for the current store.
void setFilter(const QRegularExpression &pattern)
Filter the visible entries.
StoreTree(QTreeView *view, QObject *parent=nullptr)
Attach the proxy model to the view and set its look: hidden header, indentation, scroll bars,...
void setStore(const QString &path)
Point everything at path: file system root, proxy store and view root index. Also drops a search filt...
auto fileSystem() -> QFileSystemModel &
auto indexFor(const QString &path) const -> QModelIndex
The view index for an absolute path, or invalid when the file system model does not (yet) know it.
auto proxy() -> StoreModel &
void setPass(Pass *pass)
Hand the proxy the backend it drops onto.
auto currentDir(bool forPass) const -> QString
dirFor() applied to the view's current index.
static auto readTemplates(const QString &storePath) -> QHash< QString, QStringList >
Read templates from .templates file in password store.
static auto fieldsIn(const QString &templateText) -> QStringList
The field names of the template in the settings: one per line, with comment lines (starting with #,...
static auto getFolderTemplate(const QString &folderPath, const QString &storePath) -> QString
Get default template for a folder. Looks in folder, then parent folders up to root.
static auto readSecretFields(const QString &storePath) -> QStringList
The field names the store's .templates file marks as secret, in any of its sections (see secretFields...
static auto secretFieldsIn(const QString &templateText) -> QStringList
The field names a template marks as secret.
static auto generateNow(const Settings &settings) -> QString
Generate the code for the current wall-clock time.
static auto parse(const QString &config) -> std::optional< Settings >
Parse an OTP configuration string.
void addToggle(QAction *action)
Put one of the window's toggles in the tray menu, above Quit.
TrayIcon(QMainWindow *parent)
Construct a TrayIcon associated with the given main window.
auto getIsAllocated() -> bool
Check whether tray resources have been allocated and initialized.
Dialog for selecting GPG recipients for password encryption.
static auto regularFilesUnder(const QString &dir, const QStringList &nameFilters, QStringList *skipped=nullptr, bool hiddenFiles=false) -> QStringList
Regular files under dir whose name matches one of nameFilters, found by walking only real directories...
static auto isUnderLink(const QString &path, const QString &storeRoot, bool includeSelf=true) -> bool
Whether the way from storeRoot down to path passes through a symbolic link or NTFS junction: path its...
static auto findPasswordStore() -> QString
Locate the password store directory.
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 isLinkedFolder(const QString &path) -> bool
Whether path names a symbolic link or NTFS junction, with or without a trailing separator (which woul...
static auto directoriesUnder(const QString &dir) -> QStringList
Every real, visible directory under dir, walked by the same rules as regularFilesUnder(): links,...
Settings dialog: every page of the configuration window and the profile table, with the validation th...
The Enums namespace: clipboard behaviour and the identifiers of the subprocess kinds QtPass queues.
Executor, the FIFO queue every gpg, git and pass child process of QtPass goes through,...
Dialog that shows an ASCII-armored public key and lets the user copy it or save it as a ....
Parser for a decrypted password entry: password line, key: value fields, remaining text and the OTP c...
The first-run wizard and its four pages: programs, key, store and summary.
MainWindow: the main application window (tree, toolbar, search, status bar, process output dock) and ...
PROCESS
Identifies different subprocess operations used in QtPass.
auto askYes(QWidget *parent, const QString &title, const QString &text) -> bool
Ask a yes/no question in plain text.
void warning(QWidget *parent, const QString &title, const QString &text)
Show a warning in plain text.
void critical(QWidget *parent, const QString &title, const QString &text)
Show an error in plain text.
void centreOnCursorScreen(QWidget &window)
Move window so its frame is centred on the screen under the mouse pointer (the primary screen when th...
NativeGrep, the content search that decrypts every entry on a worker thread instead of running pass g...
Dialog for creating or editing one password entry, including the generator, template fields,...
PasswordDisplayPanel: renders the decrypted fields of an entry (password, template fields,...
PathValidator: is a path inside the password store, and how is it spelled relative to the store root.
QMessageBox helpers that force Qt::PlainText so store-controlled names can never be read as rich-text...
ProcessOutputPanel: the dockable console that shows numbered, colour-coded git/pass/gpg output.
QMap< QString, Profile > Profiles
All profiles by name. QMap so iteration order is the name order.
QtPass: UI-neutral glue that turns backend completion signals into formatted output,...
The "qtpass" logging category.
QtPassSettings, the QSettings singleton behind every saved setting, the profiles and the Pass backend...
Plain value-object holding all flat QtPass configuration.
bool displayAsIs
Show file content unmodified.
QString gpgExecutable
Path to the gpg/gpg2 executable.
QString passSigningKey
GPG key used to sign .gpg-id files.
bool usePass
Use the pass CLI (true) or native git/gpg.
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.
bool showMenuBar
Show the menu bar (Ctrl+M toggles it).
QString gitExecutable
Path to the git executable.
bool autoPull
Automatically git pull on open.
int autoclearPanelSeconds
Panel autoclear delay (seconds).
bool startMinimized
Start the window minimised.
bool useTrayIcon
Show a system tray icon.
QString passExecutable
Path to the pass executable.
bool useGit
Enable git integration.
bool addGPGId
Auto-add .gpg-id files to git.
QString passTemplate
Newline-separated template field names.
bool useMonospace
Render content in a monospace font.
bool templateAllFields
Treat every key: line as a field.
QString activeProfile
Name of the active profile.
bool useTemplate
Use the password template.
Outcome of a search-completion transition.
bool discard
The finished search was cancelled; ignore results.
bool restoreCursor
A wait cursor was active and must be restored.
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.
TemplateIO: the store's .templates and .default_template files and the # secret: marker in template t...
RFC 6238 TOTP: otpauth URI parsing, code generation and canonical re-serialisation.
TrayIcon: the system tray icon and its context menu that show, hide, minimise, maximise,...
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...
constexpr int MS_PER_SECOND
Milliseconds in a second, for timers set from a setting in seconds.
WindowStateStore: saves and restores top-level window geometry through QtPassSettings,...