UI: Add (un)locking of password.

This commit is contained in:
Nodir Temirkhodjaev 2021-04-09 17:20:05 +03:00
parent 1d4ae8ac91
commit 7ef6df2307
15 changed files with 174 additions and 53 deletions

View File

@ -1,4 +1,4 @@
INCLUDEPATH *= $$PWD
# Windows
LIBS *= -lfwpuclnt -ladvapi32 -lkernel32 -luser32 -luuid -lversion -lws2_32
LIBS *= -lfwpuclnt -ladvapi32 -lkernel32 -luser32 -luuid -lversion -lws2_32 -lwtsapi32

View File

@ -76,17 +76,24 @@ QPushButton *ControlUtil::createLinkButton(
return c;
}
QPushButton *ControlUtil::createSplitterButton(
QPushButton *ControlUtil::createFlatButton(
const QString &iconPath, const std::function<void()> &onClicked)
{
auto c = createButton(iconPath, onClicked);
c->setFixedSize(32, 32);
c->setFlat(true);
c->setCursor(Qt::PointingHandCursor);
c->setFocusPolicy(Qt::NoFocus);
return c;
}
QPushButton *ControlUtil::createSplitterButton(
const QString &iconPath, const std::function<void()> &onClicked)
{
auto c = createFlatButton(iconPath, onClicked);
c->setFixedSize(32, 32);
return c;
}
QLabel *ControlUtil::createLabel(const QString &text)
{
auto c = new QLabel(text);

View File

@ -31,6 +31,8 @@ public:
const QString &iconPath, const std::function<void()> &onClicked);
static QPushButton *createLinkButton(const QString &iconPath,
const QString &linkPath = QString(), const QString &toolTip = QString());
static QPushButton *createFlatButton(
const QString &iconPath, const std::function<void()> &onClicked);
static QPushButton *createSplitterButton(
const QString &iconPath, const std::function<void()> &onClicked);
static QLabel *createLabel(const QString &text = QString());

View File

@ -1,5 +1,6 @@
#include "passworddialog.h"
#include <QComboBox>
#include <QDialogButtonBox>
#include <QHBoxLayout>
#include <QLabel>
@ -19,12 +20,24 @@ void PasswordDialog::retranslateUi()
{
m_labelPassword->setText(tr("Please enter the password:"));
m_labelUnlock->setText(tr("Unlock till:"));
retranslateComboUnlock();
m_buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK"));
m_buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel"));
this->setWindowTitle(tr("Password input"));
}
void PasswordDialog::retranslateComboUnlock()
{
const QStringList list = { tr("Disabled"), tr("Session lockout"), tr("Program exit") };
m_comboUnlock->clear();
m_comboUnlock->addItems(list);
m_comboUnlock->setCurrentIndex(0);
}
void PasswordDialog::setupUi()
{
// Password Row
@ -33,9 +46,13 @@ void PasswordDialog::setupUi()
// Button Box
setupButtonBox();
// Unlock Row
auto unlockLayout = setupUnlockLayout();
// Main layout
auto layout = new QVBoxLayout();
layout->addLayout(passwordLayout);
layout->addLayout(unlockLayout);
layout->addStretch();
layout->addWidget(ControlUtil::createSeparator());
layout->addWidget(m_buttonBox);
@ -64,6 +81,22 @@ QLayout *PasswordDialog::setupPasswordLayout()
return layout;
}
QLayout *PasswordDialog::setupUnlockLayout()
{
auto layout = new QHBoxLayout();
layout->setSpacing(6);
m_labelUnlock = ControlUtil::createLabel();
m_comboUnlock = new QComboBox();
m_comboUnlock->setMinimumWidth(150);
layout->addWidget(m_labelUnlock);
layout->addWidget(m_comboUnlock);
return layout;
}
void PasswordDialog::setupButtonBox()
{
m_buttonBox =
@ -72,8 +105,13 @@ void PasswordDialog::setupButtonBox()
QObject::connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}
QString PasswordDialog::getPassword(QWidget *parent)
bool PasswordDialog::getPassword(QString &password, UnlockType &unlock, QWidget *parent)
{
PasswordDialog dialog(parent);
return dialog.exec() == 1 ? dialog.m_editPassword->text() : QString();
if (dialog.exec() == 0)
return false;
password = dialog.m_editPassword->text();
unlock = static_cast<UnlockType>(dialog.m_comboUnlock->currentIndex());
return true;
}

View File

@ -3,6 +3,7 @@
#include <QDialog>
QT_FORWARD_DECLARE_CLASS(QComboBox)
QT_FORWARD_DECLARE_CLASS(QDialogButtonBox)
QT_FORWARD_DECLARE_CLASS(QLabel)
QT_FORWARD_DECLARE_CLASS(QLineEdit)
@ -12,21 +13,31 @@ class PasswordDialog : public QDialog
Q_OBJECT
public:
enum UnlockType {
UnlockDisabled = 0,
UnlockTillSessionLock,
UnlockTillAppExit,
};
explicit PasswordDialog(QWidget *parent = nullptr);
static QString getPassword(QWidget *parent = nullptr);
static bool getPassword(QString &password, UnlockType &unlock, QWidget *parent = nullptr);
private:
void retranslateUi();
void retranslateComboUnlock();
void setupUi();
QLayout *setupPasswordLayout();
QLayout *setupUnlockLayout();
void setupButtonBox();
private:
QLabel *m_labelPassword = nullptr;
QLineEdit *m_editPassword = nullptr;
QDialogButtonBox *m_buttonBox = nullptr;
QLabel *m_labelUnlock = nullptr;
QComboBox *m_comboUnlock = nullptr;
};
#endif // PASSWORDDIALOG_H

View File

@ -70,9 +70,11 @@ void OptionsPage::onSaved()
const auto password = m_editPassword->text();
settings()->setPasswordHash(StringUtil::cryptoHash(password));
m_editPassword->clear();
}
settings()->setPasswordCheckOnce(m_cbPasswordCheckOnce->isChecked());
if (password.isEmpty() && m_btPasswordLock->isVisible()) {
m_btPasswordLock->click(); // Reset unlocked password
}
}
}
void OptionsPage::onRetranslateUi()
@ -98,7 +100,7 @@ void OptionsPage::onRetranslateUi()
m_cbPassword->setText(tr("Password:"));
retranslateEditPassword();
m_cbPasswordCheckOnce->setText(tr("Check password only once"));
m_btPasswordLock->setText(tr("Lock the password"));
m_labelLanguage->setText(tr("Language:"));
@ -277,7 +279,7 @@ void OptionsPage::setupGlobalBox()
auto layout = new QVBoxLayout();
layout->addWidget(m_cbHotKeys);
layout->addLayout(passwordLayout);
layout->addWidget(m_cbPasswordCheckOnce);
layout->addWidget(m_btPasswordLock);
layout->addLayout(langLayout);
m_gbGlobal = new QGroupBox(this);
@ -297,8 +299,11 @@ QLayout *OptionsPage::setupPasswordLayout()
setIniEdited(true);
});
m_cbPasswordCheckOnce = ControlUtil::createCheckBox(
settings()->passwordCheckOnce(), [&](bool) { setIniEdited(true); });
m_btPasswordLock = ControlUtil::createFlatButton(":/icons/lock-open.png", [&] {
settings()->resetCheckedPassword();
m_btPasswordLock->hide();
});
setupEditPassword();
@ -316,10 +321,12 @@ void OptionsPage::setupEditPassword()
m_editPassword->setFixedWidth(200);
const auto refreshEditPassword = [&] {
m_editPassword->setReadOnly(settings()->hasPassword() || !m_cbPassword->isChecked());
const bool hasPassword = settings()->hasPassword();
m_editPassword->setReadOnly(hasPassword || !m_cbPassword->isChecked());
retranslateEditPassword();
m_cbPasswordCheckOnce->setEnabled(m_cbPassword->isChecked());
m_btPasswordLock->setVisible(hasPassword && !settings()->isPasswordRequired());
};
refreshEditPassword();

View File

@ -60,7 +60,7 @@ private:
QCheckBox *m_cbHotKeys = nullptr;
QCheckBox *m_cbPassword = nullptr;
QLineEdit *m_editPassword = nullptr;
QCheckBox *m_cbPasswordCheckOnce = nullptr;
QPushButton *m_btPasswordLock = nullptr;
QLabel *m_labelLanguage = nullptr;
QComboBox *m_comboLanguage = nullptr;
QLabel *m_iconDriver = nullptr;

View File

@ -19,6 +19,7 @@
<file>icons/home.png</file>
<file>icons/key.png</file>
<file>icons/line-graph.png</file>
<file>icons/lock-open.png</file>
<file>icons/map-map-marker.png</file>
<file>icons/map-marker.png</file>
<file>icons/pencil.png</file>

View File

@ -56,23 +56,17 @@
#include "util/window/widgetwindowstatewatcher.h"
FortManager::FortManager(FortSettings *settings, EnvManager *envManager, QObject *parent) :
QObject(parent),
m_trayTriggered(false),
m_passwordChecked(false),
m_settings(settings),
m_envManager(envManager)
QObject(parent), m_trayTriggered(false), m_settings(settings), m_envManager(envManager)
{
}
FortManager::~FortManager()
{
closeEventFilter();
closeMainWindow();
closeDriver();
closeLogManager();
delete m_mainWindow;
OsUtil::closeMutex(m_instanceMutex);
}
@ -234,12 +228,6 @@ void FortManager::setupEventFilter()
m_nativeEventFilter = new NativeEventFilter(this);
}
void FortManager::closeEventFilter()
{
m_nativeEventFilter->unregisterHotKeys();
m_nativeEventFilter->unregisterSessionNotification();
}
void FortManager::setupEnvManager()
{
connect(m_nativeEventFilter, &NativeEventFilter::environmentChanged, envManager(),
@ -284,6 +272,22 @@ void FortManager::setupTaskManager()
void FortManager::setupMainWindow()
{
m_mainWindow = new MainWindow();
m_nativeEventFilter->registerSessionNotification(m_mainWindow->winId());
connect(m_nativeEventFilter, &NativeEventFilter::sessionLocked, this,
[&] { settings()->resetCheckedPassword(PasswordDialog::UnlockTillSessionLock); });
}
void FortManager::closeMainWindow()
{
if (!m_mainWindow)
return;
m_nativeEventFilter->unregisterHotKeys();
m_nativeEventFilter->unregisterSessionNotification(m_mainWindow->winId());
delete m_mainWindow;
}
void FortManager::setupHotKeyManager()
@ -616,7 +620,7 @@ bool FortManager::checkPassword()
{
static bool g_passwordDialogOpened = false;
if (!isPasswordRequired())
if (!settings()->isPasswordRequired())
return true;
if (g_passwordDialogOpened) {
@ -629,18 +633,18 @@ bool FortManager::checkPassword()
g_passwordDialogOpened = true;
const QString password = PasswordDialog::getPassword(m_mainWindow);
QString password;
PasswordDialog::UnlockType unlocked = PasswordDialog::UnlockDisabled;
const bool ok = PasswordDialog::getPassword(password, unlocked, m_mainWindow);
g_passwordDialogOpened = false;
m_passwordChecked =
!password.isEmpty() && StringUtil::cryptoHash(password) == settings()->passwordHash();
return m_passwordChecked;
}
const bool checked = ok && !password.isEmpty()
&& StringUtil::cryptoHash(password) == settings()->passwordHash();
bool FortManager::isPasswordRequired()
{
return settings()->hasPassword() && !(settings()->passwordCheckOnce() && m_passwordChecked);
settings()->setPasswordChecked(checked, checked ? unlocked : PasswordDialog::UnlockDisabled);
return checked;
}
void FortManager::showErrorBox(const QString &text, const QString &title)
@ -944,7 +948,7 @@ void FortManager::createTrayMenu()
void FortManager::updateTrayMenuFlags()
{
const bool editEnabled = (!isPasswordRequired() && !m_optWindow);
const bool editEnabled = (!settings()->isPasswordRequired() && !m_optWindow);
m_filterEnabledAction->setEnabled(editEnabled);
m_stopTrafficAction->setEnabled(editEnabled);

View File

@ -114,7 +114,6 @@ public slots:
void quitByCheckPassword();
bool checkPassword();
bool isPasswordRequired();
void showErrorBox(const QString &text, const QString &title = QString());
void showInfoBox(const QString &text, const QString &title = QString());
@ -146,8 +145,6 @@ private:
void closeLogManager();
void setupEventFilter();
void closeEventFilter();
void setupEnvManager();
void setupStatManager();
void setupConfManager();
@ -156,6 +153,8 @@ private:
void setupTaskManager();
void setupMainWindow();
void closeMainWindow();
void setupHotKeyManager();
void setupTrayIcon();
@ -214,7 +213,6 @@ private:
private:
bool m_trayTriggered : 1;
bool m_passwordChecked : 1;
TrayMessageType m_lastMessageType = MessageOptions;

View File

@ -35,6 +35,8 @@ FortSettings::FortSettings(QObject *parent) :
m_isService(false),
m_hasService(false),
m_isWindowControl(false),
m_passwordChecked(false),
m_passwordUnlocked(0),
m_bulkUpdating(false),
m_bulkIniChanged(false)
{
@ -223,6 +225,30 @@ QString FortSettings::confFilePath() const
return profilePath() + (APP_BASE ".config");
}
void FortSettings::setPasswordChecked(bool checked, bool unlocked)
{
if (m_passwordChecked == checked)
return;
m_passwordChecked = checked;
m_passwordUnlocked = unlocked;
emit iniChanged();
}
void FortSettings::resetCheckedPassword(int unlocked)
{
if (unlocked != 0 && unlocked != m_passwordUnlocked)
return;
setPasswordChecked(false, 0);
}
bool FortSettings::isPasswordRequired()
{
return hasPassword() && !(m_passwordUnlocked != 0 && m_passwordChecked);
}
void FortSettings::readConfIni(FirewallConf &conf) const
{
m_ini->beginGroup("confFlags");

View File

@ -33,9 +33,6 @@ public:
QString passwordHash() const { return iniText("base/passwordHash"); }
void setPasswordHash(const QString &v) { setIniValue("base/passwordHash", v); }
bool passwordCheckOnce() const { return iniBool("base/passwordCheckOnce"); }
void setPasswordCheckOnce(bool on) { setIniValue("base/passwordCheckOnce", on); }
QString appUpdatesUrl() const;
int appVersion() const;
@ -225,6 +222,13 @@ public:
QString errorMessage() const { return m_errorMessage; }
bool passwordChecked() const { return m_passwordChecked; }
bool passwordUnlocked() const { return m_passwordUnlocked; }
void setPasswordChecked(bool checked, bool unlocked);
void resetCheckedPassword(int unlocked = 0);
bool isPasswordRequired();
bool confMigrated() const;
bool confCanMigrate(QString &viaVersion) const;
@ -280,14 +284,17 @@ private:
static QString startupShortcutPath();
private:
bool m_iniExists : 1;
bool m_noCache : 1;
bool m_isService : 1;
bool m_hasService : 1;
bool m_isWindowControl : 1;
uint m_iniExists : 1;
uint m_noCache : 1;
uint m_isService : 1;
uint m_hasService : 1;
uint m_isWindowControl : 1;
bool m_bulkUpdating : 1;
bool m_bulkIniChanged : 1;
uint m_passwordChecked : 1;
uint m_passwordUnlocked : 3;
uint m_bulkUpdating : 1;
uint m_bulkIniChanged : 1;
QString m_defaultLanguage;
QString m_profilePath;

BIN
src/ui/icons/lock-open.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 B

View File

@ -4,6 +4,7 @@
#define WIN32_LEAN_AND_MEAN
#include <qt_windows.h>
#include <wtsapi32.h>
NativeEventFilter::NativeEventFilter(QObject *parent) : QObject(parent)
{
@ -56,6 +57,16 @@ void NativeEventFilter::unregisterHotKeys()
m_keyIdMap.clear();
}
bool NativeEventFilter::registerSessionNotification(quintptr winId)
{
return WTSRegisterSessionNotification((HWND) winId, NOTIFY_FOR_THIS_SESSION);
}
void NativeEventFilter::unregisterSessionNotification(quintptr winId)
{
WTSUnRegisterSessionNotification((HWND) winId);
}
void NativeEventFilter::setKeyId(int hotKeyId, quint32 nativeMod, quint32 nativeKey)
{
const quint32 nativeKeyMod = nativeMod | (nativeKey << 16);
@ -103,6 +114,11 @@ bool NativeEventFilter::nativeEventFilter(const QByteArray &eventType, void *mes
emit environmentChanged();
}
} break;
case WM_WTSSESSION_CHANGE: {
if (msg->wParam == WTS_SESSION_LOCK) {
emit sessionLocked();
}
} break;
}
return false;

View File

@ -29,9 +29,13 @@ public:
void unregisterHotKey(int hotKeyId);
void unregisterHotKeys();
bool registerSessionNotification(quintptr winId);
void unregisterSessionNotification(quintptr winId);
signals:
void hotKeyPressed(int hotKeyId);
void environmentChanged();
void sessionLocked();
public slots: