Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/keepassxreboot/keepassxc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/Config.cpp')
-rw-r--r--src/core/Config.cpp527
1 files changed, 394 insertions, 133 deletions
diff --git a/src/core/Config.cpp b/src/core/Config.cpp
index 445e587f8..6d55df8c7 100644
--- a/src/core/Config.cpp
+++ b/src/core/Config.cpp
@@ -1,6 +1,6 @@
/*
+ * Copyright (C) 2020 KeePassXC Team <team@keepassxc.org>
* Copyright (C) 2011 Felix Geyer <debfx@fobos.de>
- * Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,40 +17,209 @@
*/
#include "Config.h"
+#include "Global.h"
#include <QCoreApplication>
#include <QDir>
+#include <QHash>
#include <QSettings>
+#include <QSize>
#include <QStandardPaths>
#include <QTemporaryFile>
-/*
- * Map of configuration file settings that are either deprecated, or have
- * had their name changed. Entries in the map are of the form
- * {oldName, newName}
- * Set newName to empty string to remove the setting from the file.
- */
-static const QMap<QString, QString> deprecationMap = {
- // >2.3.4
- {QStringLiteral("security/hidepassworddetails"), QStringLiteral("security/HidePasswordPreviewPanel")},
- // >2.3.4
- {QStringLiteral("GUI/HideDetailsView"), QStringLiteral("GUI/HidePreviewPanel")},
- // >2.3.4
- {QStringLiteral("GUI/DetailSplitterState"), QStringLiteral("GUI/PreviewSplitterState")},
- // >2.3.4
- {QStringLiteral("security/IconDownloadFallbackToGoogle"), QStringLiteral("security/IconDownloadFallback")},
-};
+#define CONFIG_VERSION 1
+#define QS QStringLiteral
-Config* Config::m_instance(nullptr);
+enum ConfigType
+{
+ Local,
+ Roaming
+};
-QVariant Config::get(const QString& key)
+struct ConfigDirective
{
- return m_settings->value(key, m_defaults.value(key));
-}
+ QString name;
+ ConfigType type;
+ QVariant defaultValue;
+};
+
+// clang-format off
+
+/**
+ * Map of legal config values, their type and default value.
+ */
+static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
+ // General
+ {Config::SingleInstance,{QS("SingleInstance"), Roaming, true}},
+ {Config::RememberLastDatabases,{QS("RememberLastDatabases"), Roaming, true}},
+ {Config::NumberOfRememberedLastDatabases,{QS("NumberOfRememberedLastDatabases"), Roaming, 5}},
+ {Config::RememberLastKeyFiles,{QS("RememberLastKeyFiles"), Roaming, true}},
+ {Config::OpenPreviousDatabasesOnStartup,{QS("OpenPreviousDatabasesOnStartup"), Roaming, true}},
+ {Config::AutoSaveAfterEveryChange,{QS("AutoSaveAfterEveryChange"), Roaming, true}},
+ {Config::AutoReloadOnChange,{QS("AutoReloadOnChange"), Roaming, true}},
+ {Config::AutoSaveOnExit,{QS("AutoSaveOnExit"), Roaming, true}},
+ {Config::BackupBeforeSave,{QS("BackupBeforeSave"), Roaming, false}},
+ {Config::UseAtomicSaves,{QS("UseAtomicSaves"), Roaming, true}},
+ {Config::SearchLimitGroup,{QS("SearchLimitGroup"), Roaming, false}},
+ {Config::MinimizeOnOpenUrl,{QS("MinimizeOnOpenUrl"), Roaming, false}},
+ {Config::HideWindowOnCopy,{QS("HideWindowOnCopy"), Roaming, false}},
+ {Config::MinimizeOnCopy,{QS("MinimizeOnCopy"), Roaming, true}},
+ {Config::MinimizeAfterUnlock,{QS("MinimizeAfterUnlock"), Roaming, false}},
+ {Config::DropToBackgroundOnCopy,{QS("DropToBackgroundOnCopy"), Roaming, false}},
+ {Config::UseGroupIconOnEntryCreation,{QS("UseGroupIconOnEntryCreation"), Roaming, true}},
+ {Config::AutoTypeEntryTitleMatch,{QS("AutoTypeEntryTitleMatch"), Roaming, true}},
+ {Config::AutoTypeEntryURLMatch,{QS("AutoTypeEntryURLMatch"), Roaming, true}},
+ {Config::AutoTypeDelay,{QS("AutoTypeDelay"), Roaming, 25}},
+ {Config::AutoTypeStartDelay,{QS("AutoTypeStartDelay"), Roaming, 500}},
+ {Config::GlobalAutoTypeKey,{QS("GlobalAutoTypeKey"), Roaming, 0}},
+ {Config::GlobalAutoTypeModifiers,{QS("GlobalAutoTypeModifiers"), Roaming, 0}},
+ {Config::TrackNonDataChanges,{QS("TrackNonDataChanges"), Roaming, false}},
+ {Config::FaviconDownloadTimeout,{QS("FaviconDownloadTimeout"), Roaming, 10}},
+ {Config::UpdateCheckMessageShown,{QS("UpdateCheckMessageShown"), Roaming, false}},
+ {Config::UseTouchID,{QS("UseTouchID"), Roaming, false}},
+
+ {Config::LastDatabases, {QS("LastDatabases"), Local, {}}},
+ {Config::LastKeyFiles, {QS("LastKeyFiles"), Local, {}}},
+ {Config::LastChallengeResponse, {QS("LastChallengeResponse"), Local, {}}},
+ {Config::LastActiveDatabase, {QS("LastActiveDatabase"), Local, {}}},
+ {Config::LastOpenedDatabases, {QS("LastOpenedDatabases"), Local, {}}},
+ {Config::LastDir, {QS("LastDir"), Local, QDir::homePath()}},
+ {Config::LastAttachmentDir, {QS("LastAttachmentDir"), Local, {}}},
+
+ // GUI
+ {Config::GUI_Language, {QS("GUI/Language"), Roaming, QS("system")}},
+ {Config::GUI_HideToolbar, {QS("GUI/HideToolbar"), Roaming, false}},
+ {Config::GUI_MovableToolbar, {QS("GUI/MovableToolbar"), Roaming, false}},
+ {Config::GUI_HidePreviewPanel, {QS("GUI/HidePreviewPanel"), Roaming, false}},
+ {Config::GUI_ToolButtonStyle, {QS("GUI/ToolButtonStyle"), Roaming, Qt::ToolButtonIconOnly}},
+ {Config::GUI_ShowTrayIcon, {QS("GUI/ShowTrayIcon"), Roaming, false}},
+ {Config::GUI_TrayIconAppearance, {QS("GUI/TrayIconAppearance"), Roaming, {}}},
+ {Config::GUI_MinimizeToTray, {QS("GUI/MinimizeToTray"), Roaming, false}},
+ {Config::GUI_MinimizeOnStartup, {QS("GUI/MinimizeOnStartup"), Roaming, false}},
+ {Config::GUI_MinimizeOnClose, {QS("GUI/MinimizeOnClose"), Roaming, false}},
+ {Config::GUI_HideUsernames, {QS("GUI/HideUsernames"), Roaming, false}},
+ {Config::GUI_AdvancedSettings, {QS("GUI/AdvancedSettings"), Roaming, false}},
+ {Config::GUI_MonospaceNotes, {QS("GUI/MonospaceNotes"), Roaming, false}},
+ {Config::GUI_ApplicationTheme, {QS("GUI/ApplicationTheme"), Roaming, QS("auto")}},
+ {Config::GUI_CompactMode, {QS("GUI/CompactMode"), Roaming, false}},
+ {Config::GUI_CheckForUpdates, {QS("GUI/CheckForUpdates"), Roaming, true}},
+ {Config::GUI_CheckForUpdatesNextCheck, {QS("GUI/CheckForUpdatesNextCheck"), Local, 0}},
+ {Config::GUI_CheckForUpdatesIncludeBetas, {QS("GUI/CheckForUpdatesIncludeBetas"), Roaming, false}},
+
+ {Config::GUI_MainWindowGeometry, {QS("GUI/MainWindowGeometry"), Local, {}}},
+ {Config::GUI_MainWindowState, {QS("GUI/MainWindowState"), Local, {}}},
+ {Config::GUI_ListViewState, {QS("GUI/ListViewState"), Local, {}}},
+ {Config::GUI_SearchViewState, {QS("GUI/SearchViewState"), Local, {}}},
+ {Config::GUI_SplitterState, {QS("GUI/SplitterState"), Local, {}}},
+ {Config::GUI_PreviewSplitterState, {QS("GUI/PreviewSplitterState"), Local, {}}},
+ {Config::GUI_AutoTypeSelectDialogSize, {QS("GUI/AutoTypeSelectDialogSize"), Local, QSize(600, 250)}},
+
+ // Security
+ {Config::Security_ClearClipboard, {QS("Security/ClearClipboard"), Roaming, true}},
+ {Config::Security_ClearClipboardTimeout, {QS("Security/ClearClipboardTimeout"), Roaming, 10}},
+ {Config::Security_ClearSearch, {QS("Security/ClearSearch"), Roaming, true}},
+ {Config::Security_ClearSearchTimeout, {QS("Security/ClearSearchTimeout"), Roaming, 5}},
+ {Config::Security_HideNotes, {QS("Security/Security_HideNotes"), Roaming, false}},
+ {Config::Security_LockDatabaseIdle, {QS("Security/LockDatabaseIdle"), Roaming, false}},
+ {Config::Security_LockDatabaseIdleSeconds, {QS("Security/LockDatabaseIdleSeconds"), Roaming, 240}},
+ {Config::Security_LockDatabaseMinimize, {QS("Security/LockDatabaseMinimize"), Roaming, false}},
+ {Config::Security_LockDatabaseScreenLock, {QS("Security/LockDatabaseScreenLock"), Roaming, true}},
+ {Config::Security_RelockAutoType, {QS("Security/RelockAutoType"), Roaming, false}},
+ {Config::Security_PasswordsRepeatVisible, {QS("Security/PasswordsRepeatVisible"), Roaming, true}},
+ {Config::Security_PasswordsHidden, {QS("Security/PasswordsHidden"), Roaming, true}},
+ {Config::Security_PasswordEmptyPlaceholder, {QS("Security/PasswordEmptyPlaceholder"), Roaming, false}},
+ {Config::Security_HidePasswordPreviewPanel, {QS("Security/HidePasswordPreviewPanel"), Roaming, true}},
+ {Config::Security_AutoTypeAsk, {QS("Security/AutotypeAsk"), Roaming, true}},
+ {Config::Security_IconDownloadFallback, {QS("Security/IconDownloadFallback"), Roaming, false}},
+ {Config::Security_ResetTouchId, {QS("Security/ResetTouchId"), Roaming, false}},
+ {Config::Security_ResetTouchIdTimeout, {QS("Security/ResetTouchIdTimeout"), Roaming, 30}},
+ {Config::Security_ResetTouchIdScreenlock,{QS("Security/ResetTouchIdScreenlock"), Roaming, true}},
+
+ // Browser
+ {Config::Browser_Enabled, {QS("Browser/Enabled"), Roaming, false}},
+ {Config::Browser_ShowNotification, {QS("Browser/ShowNotification"), Roaming, true}},
+ {Config::Browser_BestMatchOnly, {QS("Browser/BestMatchOnly"), Roaming, false}},
+ {Config::Browser_UnlockDatabase, {QS("Browser/UnlockDatabase"), Roaming, true}},
+ {Config::Browser_MatchUrlScheme, {QS("Browser/MatchUrlScheme"), Roaming, true}},
+ {Config::Browser_SortByUsername, {QS("Browser/SortByUsername"), Roaming, false}},
+ {Config::Browser_SupportBrowserProxy, {QS("Browser/SupportBrowserProxy"), Roaming, true}},
+ {Config::Browser_UseCustomProxy, {QS("Browser/UseCustomProxy"), Roaming, false}},
+ {Config::Browser_CustomProxyLocation, {QS("Browser/CustomProxyLocation"), Roaming, {}}},
+ {Config::Browser_UpdateBinaryPath, {QS("Browser/UpdateBinaryPath"), Roaming, true}},
+ {Config::Browser_AllowExpiredCredentials, {QS("Browser/AllowExpiredCredentials"), Roaming, false}},
+ {Config::Browser_AlwaysAllowAccess, {QS("Browser/AlwaysAllowAccess"), Roaming, false}},
+ {Config::Browser_AlwaysAllowUpdate, {QS("Browser/AlwaysAllowUpdate"), Roaming, false}},
+ {Config::Browser_HttpAuthPermission, {QS("Browser/HttpAuthPermission"), Roaming, false}},
+ {Config::Browser_SearchInAllDatabases, {QS("Browser/SearchInAllDatabases"), Roaming, false}},
+ {Config::Browser_SupportKphFields, {QS("Browser/SupportKphFields"), Roaming, true}},
+ {Config::Browser_NoMigrationPrompt, {QS("Browser/NoMigrationPrompt"), Roaming, false}},
+ {Config::Browser_UseCustomBrowser, {QS("Browser/UseCustomBrowser"), Local, false}},
+ {Config::Browser_CustomBrowserType, {QS("Browser/CustomBrowserType"), Local, -1}},
+ {Config::Browser_CustomBrowserLocation, {QS("Browser/CustomBrowserLocation"), Local, {}}},
+#ifdef QT_DEBUG
+ {Config::Browser_CustomExtensionId, {QS("Browser/CustomExtensionId"), Local, {}}},
+#endif
+
+ // SSHAgent
+ {Config::SSHAgent_Enabled, {QS("SSHAgent/Enabled"), Roaming, false}},
+ {Config::SSHAgent_UseOpenSSH, {QS("SSHAgent/UseOpenSSH"), Roaming, false}},
+ {Config::SSHAgent_AuthSockOverride, {QS("SSHAgent/AuthSockOverride"), Local, {}}},
-QVariant Config::get(const QString& key, const QVariant& defaultValue)
+ // FdoSecrets
+ {Config::FdoSecrets_Enabled, {QS("FdoSecrets/Enabled"), Roaming, false}},
+ {Config::FdoSecrets_ShowNotification, {QS("FdoSecrets/ShowNotification"), Roaming, true}},
+ {Config::FdoSecrets_NoConfirmDeleteItem, {QS("FdoSecrets/NoConfirmDeleteItem"), Roaming, false}},
+
+ // KeeShare
+ {Config::KeeShare_QuietSuccess, {QS("KeeShare/QuietSuccess"), Roaming, false}},
+ {Config::KeeShare_Own, {QS("KeeShare/Own"), Roaming, {}}},
+ {Config::KeeShare_Foreign, {QS("KeeShare/Foreign"), Roaming, {}}},
+ {Config::KeeShare_Active, {QS("KeeShare/Active"), Roaming, {}}},
+ {Config::KeeShare_LastDir, {QS("KeeShare/LastDir"), Local, QDir::homePath()}},
+ {Config::KeeShare_LastKeyDir, {QS("KeeShare/LastKeyDir"), Local, QDir::homePath()}},
+ {Config::KeeShare_LastShareDir, {QS("KeeShare/LastShareDir"), Local, QDir::homePath()}},
+
+ // PasswordGenerator
+ {Config::PasswordGenerator_LowerCase, {QS("PasswordGenerator/LowerCase"), Roaming, true}},
+ {Config::PasswordGenerator_UpperCase, {QS("PasswordGenerator/UpperCase"), Roaming, true}},
+ {Config::PasswordGenerator_Numbers, {QS("PasswordGenerator/Numbers"), Roaming, true}},
+ {Config::PasswordGenerator_EASCII, {QS("PasswordGenerator/EASCII"), Roaming, false}},
+ {Config::PasswordGenerator_AdvancedMode, {QS("PasswordGenerator/AdvancedMode"), Roaming, false}},
+ {Config::PasswordGenerator_SpecialChars, {QS("PasswordGenerator/SpecialChars"), Roaming, true}},
+ {Config::PasswordGenerator_Braces, {QS("PasswordGenerator/Braces"), Roaming, false}},
+ {Config::PasswordGenerator_Punctuation, {QS("PasswordGenerator/Punctuation"), Roaming, false}},
+ {Config::PasswordGenerator_Quotes, {QS("PasswordGenerator/Quotes"), Roaming, false}},
+ {Config::PasswordGenerator_Dashes, {QS("PasswordGenerator/Dashes"), Roaming, false}},
+ {Config::PasswordGenerator_Math, {QS("PasswordGenerator/Math"), Roaming, false}},
+ {Config::PasswordGenerator_Logograms, {QS("PasswordGenerator/Logograms"), Roaming, false}},
+ {Config::PasswordGenerator_AdditionalChars, {QS("PasswordGenerator/AdditionalChars"), Roaming, {}}},
+ {Config::PasswordGenerator_ExcludedChars, {QS("PasswordGenerator/ExcludedChars"), Roaming, {}}},
+ {Config::PasswordGenerator_ExcludeAlike, {QS("PasswordGenerator/ExcludeAlike"), Roaming, true}},
+ {Config::PasswordGenerator_EnsureEvery, {QS("PasswordGenerator/EnsureEvery"), Roaming, true}},
+ {Config::PasswordGenerator_Length, {QS("PasswordGenerator/Length"), Roaming, 20}},
+ {Config::PasswordGenerator_WordCount, {QS("PasswordGenerator/WordCount"), Roaming, 7}},
+ {Config::PasswordGenerator_WordSeparator, {QS("PasswordGenerator/WordSeparator"), Roaming, QS(" ")}},
+ {Config::PasswordGenerator_WordList, {QS("PasswordGenerator/WordList"), Roaming, QS("eff_large.wordlist")}},
+ {Config::PasswordGenerator_WordCase, {QS("PasswordGenerator/WordCase"), Roaming, 0}},
+ {Config::PasswordGenerator_Type, {QS("PasswordGenerator/Type"), Roaming, 0}},
+
+ // Messages
+ {Config::Messages_NoLegacyKeyFileWarning, {QS("Messages/NoLegacyKeyFileWarning"), Roaming, false}},
+ {Config::Messages_Qt55CompatibilityWarning, {QS("Messages/Qt55CompatibilityWarning"), Local, false}},
+ {Config::Messages_HidePreReleaseWarning, {QS("Messages/HidePreReleaseWarning"), Local, {}}}};
+
+// clang-format on
+
+QPointer<Config> Config::m_instance(nullptr);
+
+QVariant Config::get(ConfigKey key)
{
- return m_settings->value(key, defaultValue);
+ auto cfg = configStrings[key];
+ auto defaultValue = configStrings[key].defaultValue;
+ if (m_localSettings && cfg.type == Local) {
+ return m_localSettings->value(cfg.name, defaultValue);
+ }
+ return m_settings->value(cfg.name, defaultValue);
}
bool Config::hasAccessError()
@@ -63,18 +232,32 @@ QString Config::getFileName()
return m_settings->fileName();
}
-void Config::set(const QString& key, const QVariant& value)
+void Config::set(ConfigKey key, const QVariant& value)
{
- if (m_settings->contains(key) && m_settings->value(key) == value) {
+ if (get(key) == value) {
return;
}
- const bool surpressSignal = !m_settings->contains(key) && m_defaults.value(key) == value;
- m_settings->setValue(key, value);
+ auto cfg = configStrings[key];
+ if (cfg.type == Local && m_localSettings) {
+ m_localSettings->setValue(cfg.name, value);
+ } else {
+ m_settings->setValue(cfg.name, value);
+ }
- if (!surpressSignal) {
- emit changed(key);
+ emit changed(key);
+}
+
+void Config::remove(ConfigKey key)
+{
+ auto cfg = configStrings[key];
+ if (cfg.type == Local && m_localSettings) {
+ m_localSettings->remove(cfg.name);
+ } else {
+ m_settings->remove(cfg.name);
}
+
+ emit changed(key);
}
/**
@@ -87,38 +270,153 @@ void Config::set(const QString& key, const QVariant& value)
void Config::sync()
{
m_settings->sync();
+ if (m_localSettings) {
+ m_localSettings->sync();
+ }
}
void Config::resetToDefaults()
{
- for (const auto& setting : m_defaults.keys()) {
- m_settings->setValue(setting, m_defaults.value(setting));
+ m_settings->clear();
+ if (m_localSettings) {
+ m_localSettings->clear();
}
}
-void Config::upgrade()
+/**
+ * Map of configuration file settings that are either deprecated, or have
+ * had their name changed to their new config enum values.
+ *
+ * Set a value to Deleted to remove the setting.
+ */
+static const QHash<QString, Config::ConfigKey> deprecationMap = {
+ // 2.3.4
+ {QS("security/hidepassworddetails"), Config::Security_HidePasswordPreviewPanel},
+ {QS("GUI/HideDetailsView"), Config::GUI_HidePreviewPanel},
+ {QS("GUI/DetailSplitterState"), Config::GUI_PreviewSplitterState},
+ {QS("security/IconDownloadFallbackToGoogle"), Config::Security_IconDownloadFallback},
+
+ // 2.6.0
+ {QS("IgnoreGroupExpansion"), Config::TrackNonDataChanges},
+ {QS("security/autotypeask"), Config::Security_AutoTypeAsk},
+ {QS("security/clearclipboard"), Config::Security_ClearClipboard},
+ {QS("security/clearclipboardtimeout"), Config::Security_ClearClipboardTimeout},
+ {QS("security/clearsearch"), Config::Security_ClearSearch},
+ {QS("security/clearsearchtimeout"), Config::Security_ClearSearchTimeout},
+ {QS("security/lockdatabaseidle"), Config::Security_LockDatabaseIdle},
+ {QS("security/lockdatabaseidlesec"), Config::Security_LockDatabaseIdleSeconds},
+ {QS("security/lockdatabaseminimize"), Config::Security_LockDatabaseMinimize},
+ {QS("security/lockdatabasescreenlock"), Config::Security_LockDatabaseScreenLock},
+ {QS("security/relockautotype"), Config::Security_RelockAutoType},
+ {QS("security/IconDownloadFallback"), Config::Security_IconDownloadFallback},
+ {QS("security/passwordscleartext"), Config::Security_PasswordsHidden},
+ {QS("security/passwordemptynodots"), Config::Security_PasswordEmptyPlaceholder},
+ {QS("security/HidePasswordPreviewPanel"), Config::Security_HidePasswordPreviewPanel},
+ {QS("security/passwordsrepeat"), Config::Security_PasswordsRepeatVisible},
+ {QS("security/hidenotes"), Config::Security_HideNotes},
+ {QS("security/resettouchid"), Config::Security_ResetTouchId},
+ {QS("security/resettouchidtimeout"), Config::Security_ResetTouchIdTimeout},
+ {QS("security/resettouchidscreenlock"), Config::Security_ResetTouchIdScreenlock},
+ {QS("KeeShare/Settings.own"), Config::KeeShare_Own},
+ {QS("KeeShare/Settings.foreign"), Config::KeeShare_Foreign},
+ {QS("KeeShare/Settings.active"), Config::KeeShare_Active},
+ {QS("SSHAgent"), Config::SSHAgent_Enabled},
+ {QS("SSHAgentOpenSSH"), Config::SSHAgent_UseOpenSSH},
+ {QS("SSHAuthSockOverride"), Config::SSHAgent_AuthSockOverride},
+ {QS("generator/LowerCase"), Config::PasswordGenerator_LowerCase},
+ {QS("generator/UpperCase"), Config::PasswordGenerator_UpperCase},
+ {QS("generator/Numbers"), Config::PasswordGenerator_Numbers},
+ {QS("generator/EASCII"), Config::PasswordGenerator_EASCII},
+ {QS("generator/AdvancedMode"), Config::PasswordGenerator_AdvancedMode},
+ {QS("generator/SpecialChars"), Config::PasswordGenerator_SpecialChars},
+ {QS("generator/AdditionalChars"), Config::PasswordGenerator_AdditionalChars},
+ {QS("generator/Braces"), Config::PasswordGenerator_Braces},
+ {QS("generator/Punctuation"), Config::PasswordGenerator_Punctuation},
+ {QS("generator/Quotes"), Config::PasswordGenerator_Quotes},
+ {QS("generator/Dashes"), Config::PasswordGenerator_Dashes},
+ {QS("generator/Math"), Config::PasswordGenerator_Math},
+ {QS("generator/Logograms"), Config::PasswordGenerator_Logograms},
+ {QS("generator/ExcludedChars"), Config::PasswordGenerator_ExcludedChars},
+ {QS("generator/ExcludeAlike"), Config::PasswordGenerator_ExcludeAlike},
+ {QS("generator/EnsureEvery"), Config::PasswordGenerator_EnsureEvery},
+ {QS("generator/Length"), Config::PasswordGenerator_Length},
+ {QS("generator/WordCount"), Config::PasswordGenerator_WordCount},
+ {QS("generator/WordSeparator"), Config::PasswordGenerator_WordSeparator},
+ {QS("generator/WordList"), Config::PasswordGenerator_WordList},
+ {QS("generator/WordCase"), Config::PasswordGenerator_WordCase},
+ {QS("generator/Type"), Config::PasswordGenerator_Type},
+ {QS("QtErrorMessageShown"), Config::Messages_Qt55CompatibilityWarning},
+ {QS("GUI/HidePasswords"), Config::Deleted},
+ {QS("GUI/DarkTrayIcon"), Config::Deleted}};
+
+/**
+ * Migrate settings from previous versions.
+ */
+void Config::migrate()
{
- const auto keys = deprecationMap.keys();
- for (const auto& setting : keys) {
+ int previousVersion = m_settings->value("ConfigVersion").toInt();
+ if (CONFIG_VERSION <= previousVersion) {
+ return;
+ }
+
+ // Update renamed keys and drop obsolete keys
+ for (const auto& setting : deprecationMap.keys()) {
+ QVariant value;
if (m_settings->contains(setting)) {
- if (!deprecationMap.value(setting).isEmpty()) {
- // Add entry with new name and old entry's value
- m_settings->setValue(deprecationMap.value(setting), m_settings->value(setting));
+ if (setting == QS("IgnoreGroupExpansion") || setting == QS("security/passwordsrepeat")
+ || setting == QS("security/passwordscleartext") || setting == QS("security/passwordemptynodots")) {
+ // Keep user's original setting for boolean settings whose meanings were reversed
+ value = !m_settings->value(setting).toBool();
+ } else {
+ value = m_settings->value(setting);
}
m_settings->remove(setting);
+ } else if (m_localSettings && m_localSettings->contains(setting)) {
+ value = m_localSettings->value(setting);
+ m_localSettings->remove(setting);
+ } else {
+ continue;
+ }
+
+ if (deprecationMap[setting] == Config::Deleted) {
+ continue;
}
+
+ set(deprecationMap[setting], value);
}
- // > 2.3.4
- if (m_settings->value("AutoSaveAfterEveryChange").toBool()) {
- m_settings->setValue("AutoSaveOnExit", true);
+ // Move local settings to separate file
+ if (m_localSettings) {
+ for (const auto& setting : asConst(configStrings)) {
+ if (setting.type == Local && m_settings->contains(setting.name)) {
+ m_localSettings->setValue(setting.name, m_settings->value(setting.name));
+ m_settings->remove(setting.name);
+ }
+ }
}
- // Setting defaults for 'hide window on copy' behavior, keeping the user's original setting
- if (m_settings->value("HideWindowOnCopy").isNull()) {
- m_settings->setValue("HideWindowOnCopy", m_settings->value("MinimizeOnCopy").toBool());
- m_settings->setValue("MinimizeOnCopy", true);
+ // Detailed version migrations
+
+ // pre 2.6.0 (no versioned configs)
+ if (previousVersion < 1) {
+
+ // 2.3.4
+ if (get(AutoSaveAfterEveryChange).toBool()) {
+ set(AutoSaveOnExit, true);
+ }
+
+ // Setting defaults for 'hide window on copy' behavior, keeping the user's original setting
+ if (get(HideWindowOnCopy).isNull()) {
+ set(HideWindowOnCopy, get(MinimizeOnCopy).toBool());
+ set(MinimizeOnCopy, true);
+ }
+
+ // Reset database columns if upgrading from pre 2.6.0
+ remove(GUI_ListViewState);
}
+
+ m_settings->setValue("ConfigVersion", CONFIG_VERSION);
+ sync();
}
Config::Config(const QString& fileName, QObject* parent)
@@ -130,108 +428,65 @@ Config::Config(const QString& fileName, QObject* parent)
Config::Config(QObject* parent)
: QObject(parent)
{
- // Check if portable config is present. If not, find it in user's directory
- QString portablePath = QCoreApplication::applicationDirPath() + "/keepassxc.ini";
- if (QFile::exists(portablePath)) {
- init(portablePath);
- } else {
- QString userPath;
- QString homePath = QDir::homePath();
-
-#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
- // we can't use QStandardPaths on X11 as it uses XDG_DATA_HOME instead of XDG_CONFIG_HOME
- QByteArray env = qgetenv("XDG_CONFIG_HOME");
- if (env.isEmpty()) {
- userPath = homePath;
- userPath += "/.config";
- } else if (env[0] == '/') {
- userPath = QFile::decodeName(env);
- } else {
- userPath = homePath;
- userPath += '/';
- userPath += QFile::decodeName(env);
- }
+ // Check if we are running in portable mode, if so store the config files local to the app
+ auto portablePath = QCoreApplication::applicationDirPath().append("/%1");
+ if (QFile::exists(portablePath.arg(".portable"))) {
+ init(portablePath.arg("config/keepassxc.ini"), portablePath.arg("config/keepassxc_local.ini"));
+ return;
+ }
+
+ QString configPath;
+ QString localConfigPath;
- userPath += "/keepassxc/";
+#if defined(Q_OS_WIN)
+ configPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
+ localConfigPath = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation);
+#elif defined(Q_OS_MACOS)
+ configPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
+ localConfigPath = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
#else
- userPath = QDir::fromNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
- // storageLocation() appends the application name ("/keepassxc") to the end
- userPath += "/";
+ // On case-sensitive Operating Systems, force use of lowercase app directories
+ configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/keepassxc";
+ localConfigPath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/keepassxc";
#endif
+ configPath += "/keepassxc";
+ localConfigPath += "/keepassxc";
+
#ifdef QT_DEBUG
- userPath += "keepassxc_debug.ini";
-#else
- userPath += "keepassxc.ini";
+ configPath += "_debug";
+ localConfigPath += "_debug";
#endif
- init(userPath);
- }
+ configPath += ".ini";
+ localConfigPath += ".ini";
+
+ init(QDir::toNativeSeparators(configPath), QDir::toNativeSeparators(localConfigPath));
}
Config::~Config()
{
}
-void Config::init(const QString& fileName)
+void Config::init(const QString& configFileName, const QString& localConfigFileName)
{
- m_settings.reset(new QSettings(fileName, QSettings::IniFormat));
- upgrade();
- connect(qApp, &QCoreApplication::aboutToQuit, this, &Config::sync);
+ // Upgrade from previous KeePassXC version which stores its config
+ // in AppData/Local on Windows instead of AppData/Roaming.
+ // Move file to correct location before continuing.
+ if (!localConfigFileName.isEmpty() && QFile::exists(localConfigFileName) && !QFile::exists(configFileName)) {
+ QDir().mkpath(QFileInfo(configFileName).absolutePath());
+ QFile::copy(localConfigFileName, configFileName);
+ QFile::remove(localConfigFileName);
+ QDir().rmdir(QFileInfo(localConfigFileName).absolutePath());
+ }
+
+ m_settings.reset(new QSettings(configFileName, QSettings::IniFormat));
+ if (!localConfigFileName.isEmpty() && configFileName != localConfigFileName) {
+ m_localSettings.reset(new QSettings(localConfigFileName, QSettings::IniFormat));
+ }
- m_defaults.insert("SingleInstance", true);
- m_defaults.insert("RememberLastDatabases", true);
- m_defaults.insert("NumberOfRememberedLastDatabases", 5);
- m_defaults.insert("RememberLastKeyFiles", true);
- m_defaults.insert("OpenPreviousDatabasesOnStartup", true);
- m_defaults.insert("AutoSaveAfterEveryChange", true);
- m_defaults.insert("AutoReloadOnChange", true);
- m_defaults.insert("AutoSaveOnExit", true);
- m_defaults.insert("BackupBeforeSave", false);
- m_defaults.insert("UseAtomicSaves", true);
- m_defaults.insert("SearchLimitGroup", false);
- m_defaults.insert("MinimizeOnOpenUrl", false);
- m_defaults.insert("HideWindowOnCopy", false);
- m_defaults.insert("MinimizeOnCopy", true);
- m_defaults.insert("MinimizeAfterUnlock", false);
- m_defaults.insert("DropToBackgroundOnCopy", false);
- m_defaults.insert("UseGroupIconOnEntryCreation", false);
- m_defaults.insert("AutoTypeEntryTitleMatch", true);
- m_defaults.insert("AutoTypeEntryURLMatch", true);
- m_defaults.insert("AutoTypeDelay", 25);
- m_defaults.insert("AutoTypeStartDelay", 500);
- m_defaults.insert("UseGroupIconOnEntryCreation", true);
- m_defaults.insert("IgnoreGroupExpansion", true);
- m_defaults.insert("FaviconDownloadTimeout", 10);
- m_defaults.insert("security/clearclipboard", true);
- m_defaults.insert("security/clearclipboardtimeout", 10);
- m_defaults.insert("security/clearsearch", true);
- m_defaults.insert("security/clearsearchtimeout", 5);
- m_defaults.insert("security/lockdatabaseidle", false);
- m_defaults.insert("security/lockdatabaseidlesec", 240);
- m_defaults.insert("security/lockdatabaseminimize", false);
- m_defaults.insert("security/lockdatabasescreenlock", true);
- m_defaults.insert("security/passwordsrepeat", false);
- m_defaults.insert("security/passwordscleartext", false);
- m_defaults.insert("security/passwordemptynodots", true);
- m_defaults.insert("security/HidePasswordPreviewPanel", true);
- m_defaults.insert("security/autotypeask", true);
- m_defaults.insert("security/IconDownloadFallback", false);
- m_defaults.insert("security/resettouchid", false);
- m_defaults.insert("security/resettouchidtimeout", 30);
- m_defaults.insert("security/resettouchidscreenlock", true);
- m_defaults.insert("GUI/Language", "system");
- m_defaults.insert("GUI/HideToolbar", false);
- m_defaults.insert("GUI/MovableToolbar", false);
- m_defaults.insert("GUI/ToolButtonStyle", Qt::ToolButtonIconOnly);
- m_defaults.insert("GUI/ShowTrayIcon", false);
- m_defaults.insert("GUI/DarkTrayIcon", false);
- m_defaults.insert("GUI/MinimizeToTray", false);
- m_defaults.insert("GUI/MinimizeOnClose", false);
- m_defaults.insert("GUI/HideUsernames", false);
- m_defaults.insert("GUI/HidePasswords", true);
- m_defaults.insert("GUI/AdvancedSettings", false);
- m_defaults.insert("GUI/MonospaceNotes", false);
+ migrate();
+ connect(qApp, &QCoreApplication::aboutToQuit, this, &Config::sync);
}
Config* Config::instance()
@@ -245,13 +500,17 @@ Config* Config::instance()
void Config::createConfigFromFile(const QString& file)
{
- Q_ASSERT(!m_instance);
+ if (m_instance) {
+ delete m_instance;
+ }
m_instance = new Config(file, qApp);
}
void Config::createTempFileInstance()
{
- Q_ASSERT(!m_instance);
+ if (m_instance) {
+ delete m_instance;
+ }
auto* tmpFile = new QTemporaryFile();
bool openResult = tmpFile->open();
Q_ASSERT(openResult);
@@ -259,3 +518,5 @@ void Config::createTempFileInstance()
m_instance = new Config(tmpFile->fileName(), qApp);
tmpFile->setParent(m_instance);
}
+
+#undef QS