diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index ef7b9c5..3f82152 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -87,6 +87,11 @@ MainWindow::MainWindow(WindowManager *windowManager, Wallet *wallet, QWidget *pa #ifdef DONATE_BEG this->donationNag(); #endif + + connect(m_windowManager->eventFilter, &EventFilter::userActivity, this, &MainWindow::userActivity); + connect(&m_checkUserActivity, &QTimer::timeout, this, &MainWindow::checkUserActivity); + m_checkUserActivity.setInterval(5000); + m_checkUserActivity.start(); } void MainWindow::initStatusBar() { @@ -1579,11 +1584,12 @@ void MainWindow::updateRecentlyOpenedMenu() { bool MainWindow::verifyPassword() { bool ok; while (true) { - QString password = QInputDialog::getText(this, "Enter password", "Please enter your password:", QLineEdit::EchoMode::Password, "", &ok); - if (!ok) { // Dialog cancelled + PasswordDialog passwordDialog{this->walletName(), false, this}; + int ret = passwordDialog.exec(); + if (ret == QDialog::Rejected) { return false; } - if (password != m_ctx->wallet->getPassword()) { + if (passwordDialog.password != m_ctx->wallet->getPassword()) { QMessageBox::warning(this, "Error", "Incorrect password"); continue; } @@ -1600,6 +1606,37 @@ void MainWindow::patchStylesheetMac() { qApp->setStyleSheet(styleSheet); } +void MainWindow::userActivity() { + m_userLastActive = QDateTime::currentSecsSinceEpoch(); +} + +void MainWindow::checkUserActivity() { + if (!config()->get(Config::inactivityLockEnabled).toBool()) { + return; + } + + if (m_constructingTransaction) { + return; + } + + if ((m_userLastActive + (config()->get(Config::inactivityLockTimeout).toInt()*60)) < QDateTime::currentSecsSinceEpoch()) { + m_checkUserActivity.stop(); + qInfo() << "Locking wallet for inactivity"; + if (!this->verifyPassword()) { + this->setEnabled(false); + this->close(); + // This doesn't close the wallet immediately. + do { + QApplication::processEvents(); + // Because running it a single time is apparently not enough. + // TODO: Qt bug? Need proper fix for this. + } while (QApplication::hasPendingEvents()); + } else { + m_checkUserActivity.start(); + } + } +} + void MainWindow::toggleSearchbar(bool visible) { config()->set(Config::showSearchbar, visible); diff --git a/src/MainWindow.h b/src/MainWindow.h index aa737ec..3b3ffdb 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -30,6 +30,7 @@ #include "model/CoinsProxyModel.h" #include "utils/networking.h" #include "utils/config.h" +#include "utils/EventFilter.h" #include "widgets/CCSWidget.h" #include "widgets/RedditWidget.h" #include "widgets/TickerWidget.h" @@ -215,6 +216,8 @@ private: void updateWidgetIcons(); bool verifyPassword(); void patchStylesheetMac(); + void userActivity(); + void checkUserActivity(); QIcon hardwareDevicePairedIcon(); QIcon hardwareDeviceUnpairedIcon(); @@ -260,6 +263,7 @@ private: QMap m_tabShowHideMapper; QTimer m_updateBytes; + QTimer m_checkUserActivity; QString m_statusText; int m_statusDots; @@ -269,6 +273,9 @@ private: QTimer m_txTimer; bool cleanedUp = false; + + EventFilter *m_eventFilter = nullptr; + qint64 m_userLastActive = QDateTime::currentSecsSinceEpoch(); }; #endif // FEATHER_MAINWINDOW_H diff --git a/src/SettingsDialog.cpp b/src/SettingsDialog.cpp index 18c27ea..77361f7 100644 --- a/src/SettingsDialog.cpp +++ b/src/SettingsDialog.cpp @@ -31,6 +31,12 @@ Settings::Settings(QSharedPointer ctx, QWidget *parent) config()->set(Config::disableLogging, toggled); WalletManager::instance()->setLogLevel(toggled ? -1 : config()->get(Config::logLevel).toInt()); }); + connect(ui->checkBox_inactivityLockTimeout, &QCheckBox::toggled, [](bool toggled){ + config()->set(Config::inactivityLockEnabled, toggled); + }); + connect(ui->spinBox_inactivityLockTimeout, QOverload::of(&QSpinBox::valueChanged), [](int value){ + config()->set(Config::inactivityLockTimeout, value); + }); connect(ui->closeButton, &QDialogButtonBox::accepted, this, &Settings::close); @@ -44,6 +50,8 @@ Settings::Settings(QSharedPointer ctx, QWidget *parent) ui->checkBox_externalLink->setChecked(config()->get(Config::warnOnExternalLink).toBool()); ui->checkBox_hideBalance->setChecked(config()->get(Config::hideBalance).toBool()); ui->checkBox_disableLogging->setChecked(config()->get(Config::disableLogging).toBool()); + ui->checkBox_inactivityLockTimeout->setChecked(config()->get(Config::inactivityLockEnabled).toBool()); + ui->spinBox_inactivityLockTimeout->setValue(config()->get(Config::inactivityLockTimeout).toInt()); // setup comboboxes this->setupSkinCombobox(); diff --git a/src/SettingsDialog.ui b/src/SettingsDialog.ui index 93b437f..9f83b36 100644 --- a/src/SettingsDialog.ui +++ b/src/SettingsDialog.ui @@ -7,7 +7,7 @@ 0 0 915 - 519 + 553 @@ -218,6 +218,60 @@ + + + + + + Lock wallet on inactivity after + + + + + + + 1 + + + 120 + + + + + + + minutes + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + diff --git a/src/WindowManager.cpp b/src/WindowManager.cpp index a1e87a7..1c4a146 100644 --- a/src/WindowManager.cpp +++ b/src/WindowManager.cpp @@ -15,7 +15,9 @@ #include "utils/TorManager.h" #include "utils/WebsocketNotifier.h" -WindowManager::WindowManager() { +WindowManager::WindowManager(EventFilter *eventFilter) + : eventFilter(eventFilter) +{ m_walletManager = WalletManager::instance(); m_splashDialog = new SplashDialog; m_cleanupThread = new QThread(); diff --git a/src/WindowManager.h b/src/WindowManager.h index 93bb9db..d7a0ee2 100644 --- a/src/WindowManager.h +++ b/src/WindowManager.h @@ -17,7 +17,7 @@ class WindowManager : public QObject { Q_OBJECT public: - explicit WindowManager(); + explicit WindowManager(EventFilter *eventFilter); ~WindowManager() override; void wizardOpenWallet(); @@ -28,6 +28,8 @@ public: void restartApplication(const QString &binaryFilename); void raise(); + EventFilter *eventFilter; + signals: void torSettingsChanged(); diff --git a/src/main.cpp b/src/main.cpp index 29c262d..243b3f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,6 +11,7 @@ #include "config-feather.h" #include "constants.h" #include "MainWindow.h" +#include "utils/EventFilter.h" #include "WindowManager.h" #if defined(Q_OS_WIN) @@ -223,11 +224,16 @@ if (AttachConsole(ATTACH_PARENT_PROCESS)) { qRegisterMetaType("TxProofResult"); qRegisterMetaType>(); - WindowManager windowManager; + EventFilter filter; + app.installEventFilter(&filter); + + WindowManager windowManager(&filter); QObject::connect(&app, &SingleApplication::instanceStarted, [&windowManager]() { windowManager.raise(); }); + + return QApplication::exec(); } diff --git a/src/utils/EventFilter.cpp b/src/utils/EventFilter.cpp new file mode 100644 index 0000000..60b9d3b --- /dev/null +++ b/src/utils/EventFilter.cpp @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: BSD-3-Clause +// SPDX-FileCopyrightText: 2020-2022 The Monero Project + +#include "EventFilter.h" + +#include +#include + +EventFilter::EventFilter(QObject *parent) + : QObject(parent) +{} + +bool EventFilter::eventFilter(QObject *obj, QEvent *ev) { + if (ev->type() == QEvent::KeyPress || ev->type() == QEvent::MouseButtonRelease) { + emit userActivity(); + } + + return QObject::eventFilter(obj, ev); +} \ No newline at end of file diff --git a/src/utils/EventFilter.h b/src/utils/EventFilter.h new file mode 100644 index 0000000..2b807df --- /dev/null +++ b/src/utils/EventFilter.h @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: BSD-3-Clause +// SPDX-FileCopyrightText: 2020-2022 The Monero Project + +#ifndef FEATHER_EVENTFILTER_H +#define FEATHER_EVENTFILTER_H + +#include + +class EventFilter : public QObject +{ +Q_OBJECT + +public: + explicit EventFilter(QObject *parent = nullptr); + +protected: + bool eventFilter(QObject *obj, QEvent *ev); + + +signals: + void userActivity(); +}; + + +#endif //FEATHER_EVENTFILTER_H diff --git a/src/utils/config.cpp b/src/utils/config.cpp index 8c39d77..5157ee9 100644 --- a/src/utils/config.cpp +++ b/src/utils/config.cpp @@ -65,6 +65,8 @@ static const QHash configStrings = { {Config::dateFormat, {QS("dateFormat"), "yyyy-MM-dd"}}, {Config::timeFormat, {QS("timeFormat"), "HH:mm"}}, {Config::balanceDisplay, {QS("balanceDisplay"), Config::BalanceDisplay::spendablePlusUnconfirmed}}, + {Config::inactivityLockEnabled, {QS("inactivityLockEnabled"), false}}, + {Config::inactivityLockTimeout, {QS("inactivityLockTimeout"), 10}}, {Config::multiBroadcast, {QS("multiBroadcast"), true}}, {Config::warnOnExternalLink,{QS("warnOnExternalLink"), true}}, diff --git a/src/utils/config.h b/src/utils/config.h index 3d1f19f..7c2a360 100644 --- a/src/utils/config.h +++ b/src/utils/config.h @@ -69,6 +69,8 @@ public: dateFormat, timeFormat, balanceDisplay, + inactivityLockEnabled, + inactivityLockTimeout, multiBroadcast, warnOnExternalLink,