mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
Cleanup config initialization, add local config options
* Fix #5313, allow specifying local config path using environment variable and command line flag * Add command line flag `--localconfig <path>` to specify a file path to use for the local configuration settings. * Add environment variable support to set config files paths: `KPXC_CONFIG` and `KPXC_CONFIG_LOCAL` to override default locations. * Reorder startup sequence to load specified config files earlier to allow for theme settings and other early options to be picked up. * Removed old command line option `--pw`, no longer used. * Attempt a fix of application not closing when last window is gone. Only set `QApplication::setQuitOnLastWindowClosed(true)` when tray icon is enabled instead of always.
This commit is contained in:
parent
122051c91c
commit
9886b1075f
@ -455,6 +455,7 @@ p{font-family: "Noto Sans",sans-serif !important}
|
|||||||
blockquote{color:var(--quotecolor) !important}
|
blockquote{color:var(--quotecolor) !important}
|
||||||
.quoteblock{color:var(--textcolor)}
|
.quoteblock{color:var(--textcolor)}
|
||||||
code{color:var(--textcoloralt);background-color: var(--sidebarbackground) !important}
|
code{color:var(--textcoloralt);background-color: var(--sidebarbackground) !important}
|
||||||
|
pre,pre>code{line-height:1.25; color:var(--textcoloralt);}
|
||||||
.keyseq{color:var(--textcoloralt);}
|
.keyseq{color:var(--textcoloralt);}
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,6 +51,8 @@ image::linux_store.png[]
|
|||||||
|
|
||||||
The Snap and Flatpak options are sandboxed applications (more secure). The Native option is installed with the operating system files. Read more about the limitations of these options here: https://keepassxc.org/docs/#faq-appsnap-yubikey[KeePassXC Snap FAQ]
|
The Snap and Flatpak options are sandboxed applications (more secure). The Native option is installed with the operating system files. Read more about the limitations of these options here: https://keepassxc.org/docs/#faq-appsnap-yubikey[KeePassXC Snap FAQ]
|
||||||
|
|
||||||
|
NOTE: KeePassXC stores a configuration file in `~/.cache` to remember window position, recent files, and other local settings. If you mount this folder to a tmpdisk you will lose settings after reboot.
|
||||||
|
|
||||||
=== macOS
|
=== macOS
|
||||||
To install the KeePassXC app on macOS, double click on the downloaded DMG file and use the click and drag option as shown:
|
To install the KeePassXC app on macOS, double click on the downloaded DMG file and use the click and drag option as shown:
|
||||||
|
|
||||||
|
@ -48,4 +48,41 @@ image::compact_mode_comparison.png[]
|
|||||||
|
|
||||||
=== Keyboard Shortcuts
|
=== Keyboard Shortcuts
|
||||||
include::KeyboardShortcuts.adoc[tag=content, leveloffset=+1]
|
include::KeyboardShortcuts.adoc[tag=content, leveloffset=+1]
|
||||||
|
|
||||||
|
// tag::advanced[]
|
||||||
|
=== Command-Line Options
|
||||||
|
You can use the following command line options to tailor the application to your preferences:
|
||||||
|
|
||||||
|
----
|
||||||
|
Usage: keepassxc.exe [options] [filename(s)]
|
||||||
|
KeePassXC - cross-platform password manager
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-?, -h, --help Displays help on commandline options.
|
||||||
|
--help-all Displays help including Qt specific options.
|
||||||
|
-v, --version Displays version information.
|
||||||
|
--config <config> path to a custom config file
|
||||||
|
--localconfig <localconfig> path to a custom local config file
|
||||||
|
--keyfile <keyfile> key file of the database
|
||||||
|
--pw-stdin read password of the database from stdin
|
||||||
|
--debug-info Displays debugging information.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
filename(s) filenames of the password databases to open (*.kdbx)
|
||||||
|
----
|
||||||
|
|
||||||
|
Additionally, the following environment variables may be useful when running the application:
|
||||||
|
|
||||||
|
[grid=rows, frame=none, width=75%]
|
||||||
|
|===
|
||||||
|
|Env Var | Description
|
||||||
|
|
||||||
|
|KPXC_CONFIG | Override default path to roaming configuration file
|
||||||
|
|KPXC_CONFIG_LOCAL | Override default path to local configuration file
|
||||||
|
|SSH_AUTH_SOCKET | Path of the unix file socket that the agent uses for communication with other processes (SSH Agent)
|
||||||
|
|QT_SCALE_FACTOR [numeric] | Defines a global scale factor for the whole application, including point-sized fonts.
|
||||||
|
|QT_SCREEN_SCALE_FACTORS [list] | Specifies scale factors for each screen. See https://doc.qt.io/qt-5/highdpi.html#high-dpi-support-in-qt
|
||||||
|
|QT_SCALE_FACTOR_ROUNDING_POLICY | Control device pixel ratio rounding to the nearest integer. See https://doc.qt.io/qt-5/highdpi.html#high-dpi-support-in-qt
|
||||||
|
|===
|
||||||
|
// end::advanced[]
|
||||||
// end::content[]
|
// end::content[]
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
|
#include <QProcessEnvironment>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
@ -418,49 +419,17 @@ void Config::migrate()
|
|||||||
sync();
|
sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
Config::Config(const QString& fileName, QObject* parent)
|
Config::Config(const QString& configFileName, const QString& localConfigFileName, QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
{
|
{
|
||||||
init(fileName);
|
init(configFileName, localConfigFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
Config::Config(QObject* parent)
|
Config::Config(QObject* parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
{
|
{
|
||||||
// Check if we are running in portable mode, if so store the config files local to the app
|
auto configFiles = defaultConfigFiles();
|
||||||
auto portablePath = QCoreApplication::applicationDirPath().append("/%1");
|
init(configFiles.first, configFiles.second);
|
||||||
if (QFile::exists(portablePath.arg(".portable"))) {
|
|
||||||
init(portablePath.arg("config/keepassxc.ini"), portablePath.arg("config/keepassxc_local.ini"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString configPath;
|
|
||||||
QString localConfigPath;
|
|
||||||
|
|
||||||
#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
|
|
||||||
// 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
|
|
||||||
configPath += "_debug";
|
|
||||||
localConfigPath += "_debug";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
configPath += ".ini";
|
|
||||||
localConfigPath += ".ini";
|
|
||||||
|
|
||||||
init(QDir::toNativeSeparators(configPath), QDir::toNativeSeparators(localConfigPath));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Config::~Config()
|
Config::~Config()
|
||||||
@ -488,6 +457,45 @@ void Config::init(const QString& configFileName, const QString& localConfigFileN
|
|||||||
connect(qApp, &QCoreApplication::aboutToQuit, this, &Config::sync);
|
connect(qApp, &QCoreApplication::aboutToQuit, this, &Config::sync);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QPair<QString, QString> Config::defaultConfigFiles()
|
||||||
|
{
|
||||||
|
// 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"))) {
|
||||||
|
return {portablePath.arg("config/keepassxc.ini"), portablePath.arg("config/keepassxc_local.ini")};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString configPath;
|
||||||
|
QString localConfigPath;
|
||||||
|
|
||||||
|
#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
|
||||||
|
// On case-sensitive Operating Systems, force use of lowercase app directories
|
||||||
|
configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/keepassxc";
|
||||||
|
localConfigPath = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) + "/keepassxc";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QString suffix;
|
||||||
|
#ifdef QT_DEBUG
|
||||||
|
suffix = "_debug";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
configPath += QString("/keepassxc%1.ini").arg(suffix);
|
||||||
|
localConfigPath += QString("/keepassxc%1.ini").arg(suffix);
|
||||||
|
|
||||||
|
// Allow overriding the default location with env vars
|
||||||
|
const auto& env = QProcessEnvironment::systemEnvironment();
|
||||||
|
configPath = env.value("KPXC_CONFIG", configPath);
|
||||||
|
localConfigPath = env.value("KPXC_CONFIG_LOCAL", localConfigPath);
|
||||||
|
|
||||||
|
return {QDir::toNativeSeparators(configPath), QDir::toNativeSeparators(localConfigPath)};
|
||||||
|
}
|
||||||
|
|
||||||
Config* Config::instance()
|
Config* Config::instance()
|
||||||
{
|
{
|
||||||
if (!m_instance) {
|
if (!m_instance) {
|
||||||
@ -497,12 +505,16 @@ Config* Config::instance()
|
|||||||
return m_instance;
|
return m_instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::createConfigFromFile(const QString& file)
|
void Config::createConfigFromFile(const QString& configFileName, const QString& localConfigFileName)
|
||||||
{
|
{
|
||||||
if (m_instance) {
|
if (m_instance) {
|
||||||
delete m_instance;
|
delete m_instance;
|
||||||
}
|
}
|
||||||
m_instance = new Config(file, qApp);
|
|
||||||
|
auto defaultFiles = defaultConfigFiles();
|
||||||
|
m_instance = new Config(configFileName.isEmpty() ? defaultFiles.first : configFileName,
|
||||||
|
localConfigFileName.isEmpty() ? defaultFiles.second : localConfigFileName,
|
||||||
|
qApp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::createTempFileInstance()
|
void Config::createTempFileInstance()
|
||||||
@ -514,7 +526,7 @@ void Config::createTempFileInstance()
|
|||||||
bool openResult = tmpFile->open();
|
bool openResult = tmpFile->open();
|
||||||
Q_ASSERT(openResult);
|
Q_ASSERT(openResult);
|
||||||
Q_UNUSED(openResult);
|
Q_UNUSED(openResult);
|
||||||
m_instance = new Config(tmpFile->fileName(), qApp);
|
m_instance = new Config(tmpFile->fileName(), "", qApp);
|
||||||
tmpFile->setParent(m_instance);
|
tmpFile->setParent(m_instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,17 +198,18 @@ public:
|
|||||||
void resetToDefaults();
|
void resetToDefaults();
|
||||||
|
|
||||||
static Config* instance();
|
static Config* instance();
|
||||||
static void createConfigFromFile(const QString& file);
|
static void createConfigFromFile(const QString& configFileName, const QString& localConfigFileName = {});
|
||||||
static void createTempFileInstance();
|
static void createTempFileInstance();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void changed(ConfigKey key);
|
void changed(ConfigKey key);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Config(const QString& fileName, QObject* parent = nullptr);
|
Config(const QString& configFileName, const QString& localConfigFileName, QObject* parent);
|
||||||
explicit Config(QObject* parent);
|
explicit Config(QObject* parent);
|
||||||
void init(const QString& configFileName, const QString& localConfigFileName = "");
|
void init(const QString& configFileName, const QString& localConfigFileName);
|
||||||
void migrate();
|
void migrate();
|
||||||
|
static QPair<QString, QString> defaultConfigFiles();
|
||||||
|
|
||||||
static QPointer<Config> m_instance;
|
static QPointer<Config> m_instance;
|
||||||
|
|
||||||
|
@ -1269,6 +1269,8 @@ bool MainWindow::saveLastDatabases()
|
|||||||
void MainWindow::updateTrayIcon()
|
void MainWindow::updateTrayIcon()
|
||||||
{
|
{
|
||||||
if (isTrayIconEnabled()) {
|
if (isTrayIconEnabled()) {
|
||||||
|
QApplication::setQuitOnLastWindowClosed(false);
|
||||||
|
|
||||||
if (!m_trayIcon) {
|
if (!m_trayIcon) {
|
||||||
m_trayIcon = new QSystemTrayIcon(this);
|
m_trayIcon = new QSystemTrayIcon(this);
|
||||||
auto* menu = new QMenu(this);
|
auto* menu = new QMenu(this);
|
||||||
@ -1307,6 +1309,8 @@ void MainWindow::updateTrayIcon()
|
|||||||
m_trayIcon->setIcon(resources()->trayIconLocked());
|
m_trayIcon->setIcon(resources()->trayIconLocked());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
QApplication::setQuitOnLastWindowClosed(true);
|
||||||
|
|
||||||
if (m_trayIcon) {
|
if (m_trayIcon) {
|
||||||
m_trayIcon->hide();
|
m_trayIcon->hide();
|
||||||
delete m_trayIcon;
|
delete m_trayIcon;
|
||||||
|
53
src/main.cpp
53
src/main.cpp
@ -56,51 +56,47 @@ int main(int argc, char** argv)
|
|||||||
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
QGuiApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Application app(argc, argv);
|
|
||||||
Application::setApplicationName("KeePassXC");
|
|
||||||
Application::setApplicationVersion(KEEPASSXC_VERSION);
|
|
||||||
app.setProperty("KPXC_QUALIFIED_APPNAME", "org.keepassxc.KeePassXC");
|
|
||||||
app.applyTheme();
|
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
|
|
||||||
QGuiApplication::setDesktopFileName(app.property("KPXC_QUALIFIED_APPNAME").toString() + QStringLiteral(".desktop"));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// don't set organizationName as that changes the return value of
|
|
||||||
// QStandardPaths::writableLocation(QDesktopServices::DataLocation)
|
|
||||||
Bootstrap::bootstrapApplication();
|
|
||||||
|
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
parser.setApplicationDescription(QObject::tr("KeePassXC - cross-platform password manager"));
|
parser.setApplicationDescription(QObject::tr("KeePassXC - cross-platform password manager"));
|
||||||
parser.addPositionalArgument(
|
parser.addPositionalArgument(
|
||||||
"filename", QObject::tr("filenames of the password databases to open (*.kdbx)"), "[filename(s)]");
|
"filename(s)", QObject::tr("filenames of the password databases to open (*.kdbx)"), "[filename(s)]");
|
||||||
|
|
||||||
QCommandLineOption configOption("config", QObject::tr("path to a custom config file"), "config");
|
QCommandLineOption configOption("config", QObject::tr("path to a custom config file"), "config");
|
||||||
|
QCommandLineOption localConfigOption(
|
||||||
|
"localconfig", QObject::tr("path to a custom local config file"), "localconfig");
|
||||||
QCommandLineOption keyfileOption("keyfile", QObject::tr("key file of the database"), "keyfile");
|
QCommandLineOption keyfileOption("keyfile", QObject::tr("key file of the database"), "keyfile");
|
||||||
QCommandLineOption pwstdinOption("pw-stdin", QObject::tr("read password of the database from stdin"));
|
QCommandLineOption pwstdinOption("pw-stdin", QObject::tr("read password of the database from stdin"));
|
||||||
// This is needed under Windows where clients send --parent-window parameter with Native Messaging connect method
|
|
||||||
QCommandLineOption parentWindowOption(QStringList() << "pw"
|
|
||||||
<< "parent-window",
|
|
||||||
QObject::tr("Parent window handle"),
|
|
||||||
"handle");
|
|
||||||
|
|
||||||
QCommandLineOption helpOption = parser.addHelpOption();
|
QCommandLineOption helpOption = parser.addHelpOption();
|
||||||
QCommandLineOption versionOption = parser.addVersionOption();
|
QCommandLineOption versionOption = parser.addVersionOption();
|
||||||
QCommandLineOption debugInfoOption(QStringList() << "debug-info", QObject::tr("Displays debugging information."));
|
QCommandLineOption debugInfoOption(QStringList() << "debug-info", QObject::tr("Displays debugging information."));
|
||||||
parser.addOption(configOption);
|
parser.addOption(configOption);
|
||||||
|
parser.addOption(localConfigOption);
|
||||||
parser.addOption(keyfileOption);
|
parser.addOption(keyfileOption);
|
||||||
parser.addOption(pwstdinOption);
|
parser.addOption(pwstdinOption);
|
||||||
parser.addOption(parentWindowOption);
|
|
||||||
parser.addOption(debugInfoOption);
|
parser.addOption(debugInfoOption);
|
||||||
|
|
||||||
|
Application app(argc, argv);
|
||||||
|
// don't set organizationName as that changes the return value of
|
||||||
|
// QStandardPaths::writableLocation(QDesktopServices::DataLocation)
|
||||||
|
Application::setApplicationName("KeePassXC");
|
||||||
|
Application::setApplicationVersion(KEEPASSXC_VERSION);
|
||||||
|
app.setProperty("KPXC_QUALIFIED_APPNAME", "org.keepassxc.KeePassXC");
|
||||||
|
|
||||||
parser.process(app);
|
parser.process(app);
|
||||||
|
|
||||||
// Don't try and do anything with the application if we're only showing the help / version
|
// Exit early if we're only showing the help / version
|
||||||
if (parser.isSet(versionOption) || parser.isSet(helpOption)) {
|
if (parser.isSet(versionOption) || parser.isSet(helpOption)) {
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QStringList fileNames = parser.positionalArguments();
|
// Process config file options early
|
||||||
|
if (parser.isSet(configOption) || parser.isSet(localConfigOption)) {
|
||||||
|
Config::createConfigFromFile(parser.value(configOption), parser.value(localConfigOption));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process single instance and early exit if already running
|
||||||
|
const QStringList fileNames = parser.positionalArguments();
|
||||||
if (app.isAlreadyRunning()) {
|
if (app.isAlreadyRunning()) {
|
||||||
if (!fileNames.isEmpty()) {
|
if (!fileNames.isEmpty()) {
|
||||||
app.sendFileNamesToRunningInstance(fileNames);
|
app.sendFileNamesToRunningInstance(fileNames);
|
||||||
@ -109,7 +105,14 @@ int main(int argc, char** argv)
|
|||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
QApplication::setQuitOnLastWindowClosed(false);
|
// Apply the configured theme before creating any GUI elements
|
||||||
|
app.applyTheme();
|
||||||
|
|
||||||
|
#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)
|
||||||
|
QGuiApplication::setDesktopFileName(app.property("KPXC_QUALIFIED_APPNAME").toString() + QStringLiteral(".desktop"));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Bootstrap::bootstrapApplication();
|
||||||
|
|
||||||
if (!Crypto::init()) {
|
if (!Crypto::init()) {
|
||||||
QString error = QObject::tr("Fatal error while testing the cryptographic functions.");
|
QString error = QObject::tr("Fatal error while testing the cryptographic functions.");
|
||||||
@ -128,10 +131,6 @@ int main(int argc, char** argv)
|
|||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser.isSet(configOption)) {
|
|
||||||
Config::createConfigFromFile(parser.value(configOption));
|
|
||||||
}
|
|
||||||
|
|
||||||
MainWindow mainWindow;
|
MainWindow mainWindow;
|
||||||
QObject::connect(&app, SIGNAL(anotherInstanceStarted()), &mainWindow, SLOT(bringToFront()));
|
QObject::connect(&app, SIGNAL(anotherInstanceStarted()), &mainWindow, SLOT(bringToFront()));
|
||||||
QObject::connect(&app, SIGNAL(applicationActivated()), &mainWindow, SLOT(bringToFront()));
|
QObject::connect(&app, SIGNAL(applicationActivated()), &mainWindow, SLOT(bringToFront()));
|
||||||
|
Loading…
Reference in New Issue
Block a user