Skip to content

Commit

Permalink
Removed advanced mode entirely and refactored to a tab widget
Browse files Browse the repository at this point in the history
  • Loading branch information
droidmonkey committed Jun 24, 2023
1 parent abc84fc commit 785147c
Show file tree
Hide file tree
Showing 16 changed files with 493 additions and 600 deletions.
6 changes: 4 additions & 2 deletions src/core/Config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
{Config::GUI_MinimizeOnClose, {QS("GUI/MinimizeOnClose"), Roaming, false}},
{Config::GUI_HideUsernames, {QS("GUI/HideUsernames"), Roaming, false}},
{Config::GUI_HidePasswords, {QS("GUI/HidePasswords"), Roaming, true}},
{Config::GUI_AdvancedSettings, {QS("GUI/AdvancedSettings"), Roaming, false}},
{Config::GUI_ColorPasswords, {QS("GUI/ColorPasswords"), Roaming, false}},
{Config::GUI_MonospaceNotes, {QS("GUI/MonospaceNotes"), Roaming, false}},
{Config::GUI_ApplicationTheme, {QS("GUI/ApplicationTheme"), Roaming, QS("auto")}},
Expand Down Expand Up @@ -371,7 +370,10 @@ static const QHash<QString, Config::ConfigKey> deprecationMap = {
{QS("UseTouchID"), Config::Deleted},
{QS("Security/ResetTouchId"), Config::Deleted},
{QS("Security/ResetTouchIdTimeout"), Config::Deleted},
{QS("Security/ResetTouchIdScreenlock"), Config::Deleted}};
{QS("Security/ResetTouchIdScreenlock"), Config::Deleted},

// 2.8.0
{QS("GUI/AdvancedSettings"), Config::Deleted}};

/**
* Migrate settings from previous versions.
Expand Down
1 change: 0 additions & 1 deletion src/core/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ class Config : public QObject
GUI_MinimizeOnClose,
GUI_HideUsernames,
GUI_HidePasswords,
GUI_AdvancedSettings,
GUI_ColorPasswords,
GUI_MonospaceNotes,
GUI_ApplicationTheme,
Expand Down
4 changes: 0 additions & 4 deletions src/gui/dbsettings/DatabaseSettingsWidgetBrowser.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,6 @@ class DatabaseSettingsWidgetBrowser : public DatabaseSettingsWidget
~DatabaseSettingsWidgetBrowser() override;

CustomData* customData() const;
inline bool hasAdvancedMode() const override
{
return false;
}

public slots:
void initialize() override;
Expand Down
5 changes: 0 additions & 5 deletions src/gui/dbsettings/DatabaseSettingsWidgetDatabaseKey.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,6 @@ class DatabaseSettingsWidgetDatabaseKey : public DatabaseSettingsWidget

void load(QSharedPointer<Database> db) override;

inline bool hasAdvancedMode() const override
{
return false;
}

public slots:
void initialize() override;
void uninitialize() override;
Expand Down
118 changes: 54 additions & 64 deletions src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#include "ui_DatabaseSettingsWidgetEncryption.h"

#include "core/AsyncTask.h"
#include "core/Config.h"
#include "core/Database.h"
#include "core/Global.h"
#include "core/Metadata.h"
Expand All @@ -28,16 +27,30 @@
#include "format/KeePass2Writer.h"
#include "gui/MessageBox.h"

#include <QPushButton>

const char* DatabaseSettingsWidgetEncryption::CD_DECRYPTION_TIME_PREFERENCE_KEY = "KPXC_DECRYPTION_TIME_PREFERENCE";

#define IS_ARGON2(uuid) (uuid == KeePass2::KDF_ARGON2D || uuid == KeePass2::KDF_ARGON2ID)
#define IS_AES_KDF(uuid) (uuid == KeePass2::KDF_AES_KDBX3 || uuid == KeePass2::KDF_AES_KDBX4)

namespace
{
QString getTextualEncryptionTime(int millisecs)
{
if (millisecs < 1000) {
return QObject::tr("%1 ms", "milliseconds", millisecs).arg(millisecs);
}
return QObject::tr("%1 s", "seconds", millisecs / 1000).arg(millisecs / 1000.0, 0, 'f', 1);
}
} // namespace

DatabaseSettingsWidgetEncryption::DatabaseSettingsWidgetEncryption(QWidget* parent)
: DatabaseSettingsWidget(parent)
, m_ui(new Ui::DatabaseSettingsWidgetEncryption())
{
m_ui->setupUi(this);
m_ui->advancedSettingsToggle->setChecked(config()->get(Config::GUI_AdvancedSettings).toBool());

connect(m_ui->advancedSettingsToggle, SIGNAL(toggled(bool)), SLOT(setAdvancedMode(bool)));
connect(m_ui->transformBenchmarkButton, SIGNAL(clicked()), SLOT(benchmarkTransformRounds()));
connect(m_ui->kdfComboBox, SIGNAL(currentIndexChanged(int)), SLOT(changeKdf(int)));
m_ui->formatCannotBeChanged->setVisible(false);
Expand All @@ -53,19 +66,16 @@ DatabaseSettingsWidgetEncryption::DatabaseSettingsWidgetEncryption(QWidget* pare
updateDecryptionTime(m_ui->decryptionTimeSlider->value());

m_ui->transformBenchmarkButton->setText(
QObject::tr("Benchmark %1 delay")
.arg(DatabaseSettingsWidgetEncryption::getTextualEncryptionTime(Kdf::DEFAULT_ENCRYPTION_TIME)));
m_ui->minTimeLabel->setText(DatabaseSettingsWidgetEncryption::getTextualEncryptionTime(Kdf::MIN_ENCRYPTION_TIME));
m_ui->maxTimeLabel->setText(DatabaseSettingsWidgetEncryption::getTextualEncryptionTime(Kdf::MAX_ENCRYPTION_TIME));
QObject::tr("Benchmark %1 delay").arg(getTextualEncryptionTime(Kdf::DEFAULT_ENCRYPTION_TIME)));
m_ui->minTimeLabel->setText(getTextualEncryptionTime(Kdf::MIN_ENCRYPTION_TIME));
m_ui->maxTimeLabel->setText(getTextualEncryptionTime(Kdf::MAX_ENCRYPTION_TIME));

connect(m_ui->activateChangeDecryptionTimeButton, SIGNAL(clicked()), SLOT(activateChangeDecryptionTime()));
connect(m_ui->decryptionTimeSlider, SIGNAL(valueChanged(int)), SLOT(updateDecryptionTime(int)));
connect(m_ui->compatibilitySelection, SIGNAL(currentIndexChanged(int)), SLOT(updateFormatCompatibility(int)));

// conditions under which a key re-transformation is needed
connect(m_ui->decryptionTimeSlider, SIGNAL(valueChanged(int)), SLOT(markDirty()));
connect(m_ui->compatibilitySelection, SIGNAL(currentIndexChanged(int)), SLOT(markDirty()));
connect(m_ui->activateChangeDecryptionTimeButton, SIGNAL(clicked()), SLOT(markDirty()));
connect(m_ui->algorithmComboBox, SIGNAL(currentIndexChanged(int)), SLOT(markDirty()));
connect(m_ui->kdfComboBox, SIGNAL(currentIndexChanged(int)), SLOT(markDirty()));
connect(m_ui->transformRoundsSpinBox, SIGNAL(valueChanged(int)), SLOT(markDirty()));
Expand All @@ -75,8 +85,13 @@ DatabaseSettingsWidgetEncryption::DatabaseSettingsWidgetEncryption(QWidget* pare

DatabaseSettingsWidgetEncryption::~DatabaseSettingsWidgetEncryption() = default;

#define IS_ARGON2(uuid) (uuid == KeePass2::KDF_ARGON2D || uuid == KeePass2::KDF_ARGON2ID)
#define IS_AES_KDF(uuid) (uuid == KeePass2::KDF_AES_KDBX3 || uuid == KeePass2::KDF_AES_KDBX4)
void DatabaseSettingsWidgetEncryption::showBasicEncryption(int decryptionMillisecs)
{
// Show the basic encryption settings tab and set the slider to the stored values
m_ui->decryptionTimeSlider->setValue(decryptionMillisecs / 100);
m_ui->encryptionSettingsTabWidget->setCurrentWidget(m_ui->basicTab);
m_initWithAdvanced = false;
}

void DatabaseSettingsWidgetEncryption::initialize()
{
Expand All @@ -85,41 +100,44 @@ void DatabaseSettingsWidgetEncryption::initialize()
return;
}

setAdvancedMode(m_ui->advancedSettingsToggle->isChecked());
auto version = KDBX4;
if (m_db->kdf()) {
version = (m_db->kdf()->uuid() == KeePass2::KDF_AES_KDBX3) ? KDBX3 : KDBX4;
}
m_ui->compatibilitySelection->setCurrentIndex(version);

bool isDirty = false;
bool isNewDatabase = false;

if (!m_db->kdf()) {
m_db->setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D));
isDirty = true;
isNewDatabase = true;
}
if (!m_db->key()) {
m_db->setKey(QSharedPointer<CompositeKey>::create(), true, false, false);
m_db->setCipher(KeePass2::CIPHER_AES256);
isDirty = true;
isNewDatabase = true;
}
bool kdbx3Enabled = KeePass2Writer::kdbxVersionRequired(m_db.data(), true, true) <= KeePass2::FILE_VERSION_3_1;

// check if the DB's custom data has a decryption time setting stored
// and set the slider to it, otherwise just state that the time is unchanged
// (we cannot infer the time from the raw KDF settings)

auto* cd = m_db->metadata()->customData();
if (cd->hasKey(CD_DECRYPTION_TIME_PREFERENCE_KEY)) {
int decryptionTime = qMax(100, cd->value(CD_DECRYPTION_TIME_PREFERENCE_KEY).toInt());
bool block = m_ui->decryptionTimeSlider->blockSignals(true);
m_ui->decryptionTimeSlider->setValue(decryptionTime / 100);
updateDecryptionTime(decryptionTime / 100);
m_ui->decryptionTimeSlider->blockSignals(block);
m_ui->activateChangeDecryptionTimeButton->setVisible(false);
showBasicEncryption(decryptionTime);
} else if (isNewDatabase) {
showBasicEncryption();
} else {
m_ui->decryptionTimeSettings->setVisible(isDirty);
m_ui->activateChangeDecryptionTimeButton->setVisible(!isDirty);
if (!isDirty) {
m_ui->decryptionTimeValueLabel->setText(tr("unchanged", "Database decryption time is unchanged"));
}
// Set default basic decryption time
m_ui->decryptionTimeSlider->setValue(Kdf::DEFAULT_ENCRYPTION_TIME / 100);
// Show the advanced encryption settings tab
m_ui->encryptionSettingsTabWidget->setCurrentWidget(m_ui->advancedTab);
m_initWithAdvanced = true;
}

updateFormatCompatibility(m_db->kdf()->uuid() == KeePass2::KDF_AES_KDBX3 ? KDBX3 : KDBX4, isDirty);
updateFormatCompatibility(m_db->kdf()->uuid() == KeePass2::KDF_AES_KDBX3 ? KDBX3 : KDBX4, isNewDatabase);
setupAlgorithmComboBox();
setupKdfComboBox(kdbx3Enabled);
loadKdfParameters();
Expand All @@ -129,7 +147,7 @@ void DatabaseSettingsWidgetEncryption::initialize()
m_ui->formatCannotBeChanged->setVisible(true);
}

m_isDirty = isDirty;
m_isDirty = isNewDatabase;
}

void DatabaseSettingsWidgetEncryption::uninitialize()
Expand Down Expand Up @@ -206,13 +224,6 @@ void DatabaseSettingsWidgetEncryption::updateKdfFields()
m_ui->parallelismSpinBox->setVisible(IS_ARGON2(id));
}

void DatabaseSettingsWidgetEncryption::activateChangeDecryptionTime()
{
m_ui->decryptionTimeSettings->setVisible(true);
m_ui->activateChangeDecryptionTimeButton->setVisible(false);
updateDecryptionTime(m_ui->decryptionTimeSlider->value());
}

void DatabaseSettingsWidgetEncryption::markDirty()
{
m_isDirty = true;
Expand All @@ -225,6 +236,11 @@ bool DatabaseSettingsWidgetEncryption::save()
return false;
}

if (m_initWithAdvanced != isAdvancedMode()) {
// Switched from basic <-> advanced mode, need to recalculate everything
m_isDirty = true;
}

if (m_db->key() && !m_db->key()->keys().isEmpty() && !m_isDirty) {
// nothing has changed, don't re-transform
return true;
Expand All @@ -233,7 +249,7 @@ bool DatabaseSettingsWidgetEncryption::save()
auto kdf = m_db->kdf();
Q_ASSERT(kdf);

if (!advancedMode()) {
if (!isAdvancedMode()) {
if (kdf && !m_isDirty && !m_ui->decryptionTimeSettings->isVisible()) {
return true;
}
Expand Down Expand Up @@ -356,7 +372,6 @@ void DatabaseSettingsWidgetEncryption::changeKdf(int index)
QUuid id(m_ui->kdfComboBox->itemData(index).toByteArray());
m_db->setKdf(KeePass2::uuidToKdf(id));
updateKdfFields();
activateChangeDecryptionTime();
benchmarkTransformRounds();
}

Expand All @@ -376,28 +391,14 @@ void DatabaseSettingsWidgetEncryption::parallelismChanged(int value)
m_ui->parallelismSpinBox->setSuffix(tr(" thread(s)", "Threads for parallel execution (KDF settings)", value));
}

void DatabaseSettingsWidgetEncryption::setAdvancedMode(bool advanced)
bool DatabaseSettingsWidgetEncryption::isAdvancedMode()
{
DatabaseSettingsWidget::setAdvancedMode(advanced);

if (advanced) {
loadKdfParameters();
} else {
auto version = KDBX4;
if (m_db->kdf()) {
version = (m_db->kdf()->uuid() == KeePass2::KDF_AES_KDBX3) ? KDBX3 : KDBX4;
}
m_ui->compatibilitySelection->setCurrentIndex(version);
}

m_ui->advancedSettings->setVisible(advanced);
m_ui->decryptionTimeSlider->setEnabled(!advanced);
config()->set(Config::GUI_AdvancedSettings, advanced);
return m_ui->encryptionSettingsTabWidget->currentWidget() == m_ui->advancedTab;
}

void DatabaseSettingsWidgetEncryption::updateDecryptionTime(int value)
{
m_ui->decryptionTimeValueLabel->setText(DatabaseSettingsWidgetEncryption::getTextualEncryptionTime(value * 100));
m_ui->decryptionTimeValueLabel->setText(getTextualEncryptionTime(value * 100));
}

void DatabaseSettingsWidgetEncryption::updateFormatCompatibility(int index, bool retransform)
Expand Down Expand Up @@ -425,16 +426,5 @@ void DatabaseSettingsWidgetEncryption::updateFormatCompatibility(int index, bool
argon2Kdf->setMemory(1 << 16);
argon2Kdf->setParallelism(2);
}

activateChangeDecryptionTime();
}
}

QString DatabaseSettingsWidgetEncryption::getTextualEncryptionTime(int millisecs)
{
if (millisecs < 1000) {
return QObject::tr("%1 ms", "milliseconds", millisecs).arg(millisecs);
} else {
return QObject::tr("%1 s", "seconds", millisecs / 1000).arg(millisecs / 1000.0, 0, 'f', 1);
}
}
13 changes: 4 additions & 9 deletions src/gui/dbsettings/DatabaseSettingsWidgetEncryption.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,10 @@ class DatabaseSettingsWidgetEncryption : public DatabaseSettingsWidget
Q_DISABLE_COPY(DatabaseSettingsWidgetEncryption);
~DatabaseSettingsWidgetEncryption() override;

inline bool hasAdvancedMode() const override
{
return true;
}

public slots:
void initialize() override;
void uninitialize() override;
bool save() override;
void setAdvancedMode(bool advanced) override;

static QString getTextualEncryptionTime(int millisecs);

protected:
void showEvent(QShowEvent* event) override;
Expand All @@ -64,10 +56,12 @@ private slots:
void setupKdfComboBox(bool enableKdbx3);
void loadKdfParameters();
void updateKdfFields();
void activateChangeDecryptionTime();
void markDirty();

private:
bool isAdvancedMode();
void showBasicEncryption(int decryptionMillisecs = Kdf::DEFAULT_ENCRYPTION_TIME);

enum FormatSelection
{
KDBX4,
Expand All @@ -76,6 +70,7 @@ private slots:
static const char* CD_DECRYPTION_TIME_PREFERENCE_KEY;

bool m_isDirty = false;
bool m_initWithAdvanced = false;
bool m_formatCompatibilityDirty = false;
const QScopedPointer<Ui::DatabaseSettingsWidgetEncryption> m_ui;
};
Expand Down
Loading

0 comments on commit 785147c

Please sign in to comment.