Skip to content

Commit

Permalink
Add Pin Quick Unlock option
Browse files Browse the repository at this point in the history
* Introduce QuickUnlockManager to fall back to pin unlock if OS native options are not available.
  • Loading branch information
droidmonkey committed Dec 2, 2024
1 parent b1dead2 commit dfbec82
Show file tree
Hide file tree
Showing 13 changed files with 401 additions and 119 deletions.
108 changes: 68 additions & 40 deletions share/translations/keepassxc_en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -586,10 +586,6 @@
<source>Convenience</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable database quick unlock (Touch ID / Windows Hello)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Lock databases when session is locked or lid is closed</source>
<translation type="unfinished"></translation>
Expand Down Expand Up @@ -634,6 +630,18 @@
<source>Hide notes in the entry preview panel</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable database quick unlock (Touch ID / Windows Hello / Polkit / Pin)</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Quick unlock can only be remembered when using Touch ID or Windows Hello</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Remember quick unlock after database is closed</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>AutoType</name>
Expand Down Expand Up @@ -1664,6 +1672,10 @@ Are you sure you want to continue with this file?.</source>
<source>&lt;a href=&quot;#&quot; style=&quot;text-decoration: underline&quot;&gt;I have a key file&lt;/a&gt;</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enable Quick Unlock</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>DatabaseSettingWidgetMetaData</name>
Expand Down Expand Up @@ -8852,46 +8864,10 @@ This option is deprecated, use --set-key-file instead.</source>
<source>Passkeys</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AES initialization failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AES encrypt failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to store in Linux Keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Polkit returned an error: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Could not locate key in keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Could not read key in keyring</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>AES decrypt failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No Polkit authentication agent was available</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Polkit authorization failed</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No Quick Unlock provider is available</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to init KeePassXC crypto.</source>
<translation type="unfinished"></translation>
Expand Down Expand Up @@ -9073,6 +9049,58 @@ This option is deprecated, use --set-key-file instead.</source>
<source>Passkey</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Quick Unlock Pin Entry</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enter a %1 to %2 digit pin to use for quick unlock:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Pin setup was canceled. Quick unlock has not been enabled.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to get credentials for quick unlock.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Enter quick unlock pin (%1 of %2 attempts):</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Pin entry was canceled.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Maximum pin attempts have been reached.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Failed to store key in Linux Keyring. Quick unlock has not been enabled.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Could not locate key in Linux Keyring.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Could not read key in Linux Keyring.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>No Polkit authentication agent was available.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Polkit authorization failed.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Windows Hello setup was canceled or failed. Quick unlock has not been enabled.</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>QtIOCompressor</name>
Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ set(gui_SOURCES
gui/wizard/NewDatabaseWizardPageEncryption.cpp
gui/wizard/NewDatabaseWizardPageDatabaseKey.cpp
quickunlock/QuickUnlockInterface.cpp
quickunlock/PinUnlock.cpp
../share/icons/icons.qrc
../share/wizard/wizard.qrc)

Expand Down
1 change: 1 addition & 0 deletions src/core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ class Config : public QObject
Security_EnableCopyOnDoubleClick,
Security_QuickUnlock,
Security_QuickUnlockRemember,
Security_DatabasePasswordMinimumQuality,

Browser_Enabled,
Browser_ShowNotification,
Expand Down
14 changes: 6 additions & 8 deletions src/gui/ApplicationSettingsWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,17 +346,15 @@ void ApplicationSettingsWidget::loadSettings()
m_secUi->hideTotpCheckBox->setChecked(config()->get(Config::Security_HideTotpPreviewPanel).toBool());
m_secUi->hideNotesCheckBox->setChecked(config()->get(Config::Security_HideNotes).toBool());

m_secUi->quickUnlockCheckBox->setEnabled(getQuickUnlock()->isAvailable());
m_secUi->quickUnlockCheckBox->setChecked(config()->get(Config::Security_QuickUnlock).toBool());
m_secUi->quickUnlockCheckBox->setToolTip(
m_secUi->quickUnlockCheckBox->isEnabled() ? QString() : tr("Quick unlock is not available on your device."));

m_secUi->quickUnlockRememberCheckBox->setEnabled(getQuickUnlock()->isAvailable()
&& getQuickUnlock()->canRemember());
#ifdef Q_OS_LINUX
// Remembering quick unlock is not supported on Linux
m_secUi->quickUnlockRememberCheckBox->setVisible(false);
#else
m_secUi->quickUnlockRememberCheckBox->setEnabled(m_secUi->quickUnlockCheckBox->isChecked());
m_secUi->quickUnlockRememberCheckBox->setChecked(config()->get(Config::Security_QuickUnlockRemember).toBool());
m_secUi->quickUnlockRememberCheckBox->setToolTip(m_secUi->quickUnlockRememberCheckBox->isEnabled()
? QString()
: tr("Quick unlock cannot be remembered on your device."));
#endif

for (const ExtraPage& page : asConst(m_extraPages)) {
page.loadSettings();
Expand Down
9 changes: 6 additions & 3 deletions src/gui/ApplicationSettingsWidgetSecurity.ui
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>364</width>
<height>505</height>
<width>391</width>
<height>529</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
Expand Down Expand Up @@ -168,7 +168,7 @@
<item>
<widget class="QCheckBox" name="quickUnlockCheckBox">
<property name="text">
<string>Enable database quick unlock (Touch ID / Windows Hello / Polkit)</string>
<string>Enable database quick unlock (Touch ID / Windows Hello / Polkit / Pin)</string>
</property>
</widget>
</item>
Expand All @@ -195,6 +195,9 @@
</item>
<item>
<widget class="QCheckBox" name="quickUnlockRememberCheckBox">
<property name="toolTip">
<string>Quick unlock can only be remembered when using Touch ID or Windows Hello</string>
</property>
<property name="text">
<string>Remember quick unlock after database is closed</string>
</property>
Expand Down
35 changes: 24 additions & 11 deletions src/gui/DatabaseOpenWidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,17 @@ namespace
bool isQuickUnlockAvailable()
{
if (config()->get(Config::Security_QuickUnlock).toBool()) {
return getQuickUnlock()->isAvailable();
auto qu = getQuickUnlock()->interface();
return qu && qu->isAvailable();
}
return false;
}

bool canPerformQuickUnlock(const QUuid& dbUuid)

Check notice

Code scanning / CodeQL

Unused static function Note

Static function canPerformQuickUnlock is unreachable
{
if (isQuickUnlockAvailable()) {
auto qu = getQuickUnlock()->interface();
return qu->hasKey(dbUuid);
}
return false;
}
Expand Down Expand Up @@ -356,9 +366,9 @@ void DatabaseOpenWidget::openDatabase()
// Save Quick Unlock credentials if available
if (!blockQuickUnlock && isQuickUnlockAvailable()) {
auto keyData = databaseKey->serialize();
if (!getQuickUnlock()->setKey(m_db->publicUuid(), keyData) && !getQuickUnlock()->errorString().isEmpty()) {
getMainWindow()->displayTabMessage(getQuickUnlock()->errorString(),
MessageWidget::MessageType::Warning);
auto qu = getQuickUnlock()->interface();
if (!qu->setKey(m_db->publicUuid(), keyData) && !qu->errorString().isEmpty()) {
getMainWindow()->displayTabMessage(qu->errorString(), MessageWidget::MessageType::Warning);
}
m_ui->messageWidget->hideMessage();
}
Expand Down Expand Up @@ -405,12 +415,15 @@ QSharedPointer<CompositeKey> DatabaseOpenWidget::buildDatabaseKey()
auto databaseKey = QSharedPointer<CompositeKey>::create();

if (!m_db.isNull() && canPerformQuickUnlock()) {
// try to retrieve the stored password using Windows Hello
// try to retrieve the stored password using quick unlock
QByteArray keyData;
if (!getQuickUnlock()->getKey(m_db->publicUuid(), keyData)) {
m_ui->messageWidget->showMessage(
tr("Failed to authenticate with Quick Unlock: %1").arg(getQuickUnlock()->errorString()),
MessageWidget::Error);
auto qu = getQuickUnlock()->interface();
if (!qu->getKey(m_db->publicUuid(), keyData)) {
m_ui->messageWidget->showMessage(tr("Failed to authenticate with Quick Unlock: %1").arg(qu->errorString()),
MessageWidget::Error);
if (!qu->hasKey(m_db->publicUuid())) {
resetQuickUnlock();
}
return {};
}
databaseKey->setRawKey(keyData);
Expand Down Expand Up @@ -602,7 +615,7 @@ void DatabaseOpenWidget::setUserInteractionLock(bool state)

bool DatabaseOpenWidget::canPerformQuickUnlock() const
{
return !m_db.isNull() && isQuickUnlockAvailable() && getQuickUnlock()->hasKey(m_db->publicUuid());
return !m_db.isNull() && isQuickUnlockAvailable() && getQuickUnlock()->interface()->hasKey(m_db->publicUuid());
}

bool DatabaseOpenWidget::isOnQuickUnlockScreen() const
Expand Down Expand Up @@ -645,7 +658,7 @@ void DatabaseOpenWidget::resetQuickUnlock()
return;
}
if (!m_db.isNull()) {
getQuickUnlock()->reset(m_db->publicUuid());
getQuickUnlock()->interface()->reset(m_db->publicUuid());
}
load(m_filename);
}
26 changes: 26 additions & 0 deletions src/gui/DatabaseOpenWidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,32 @@
<property name="bottomMargin">
<number>5</number>
</property>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="enableQuickUnlockCheckBox">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Enable Quick Unlock</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item alignment="Qt::AlignRight">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="focusPolicy">
Expand Down
2 changes: 1 addition & 1 deletion src/gui/dbsettings/DatabaseSettingsWidgetDatabaseKey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ bool DatabaseSettingsWidgetDatabaseKey::saveSettings()

m_db->setKey(newKey, true, false, false);

getQuickUnlock()->reset(m_db->publicUuid());
getQuickUnlock()->interface()->reset(m_db->publicUuid());

emit editFinished(true);
if (m_isDirty) {
Expand Down
Loading

0 comments on commit dfbec82

Please sign in to comment.