Skip to content

Commit 4132a7e

Browse files
committed
Support full DB unlock in single instance mode
Closes #2089
1 parent dcdd599 commit 4132a7e

File tree

4 files changed

+47
-22
lines changed

4 files changed

+47
-22
lines changed

src/gui/Application.cpp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ enum Application::SocketCmd : quint32
5151
{
5252
OpenFiles = 1,
5353
LockAll,
54+
Unlock,
5455
};
5556

5657
Application::Application(int& argc, char** argv)
@@ -327,8 +328,7 @@ void Application::socketReadyRead()
327328
}
328329

329330
SocketCmd id;
330-
// manual reinterpret_cast not needed for Qt 5.14+
331-
in >> reinterpret_cast<typename std::underlying_type<SocketCmd>::type&>(id);
331+
in >> id;
332332

333333
switch (id) {
334334
case SocketCmd::OpenFiles: {
@@ -345,17 +345,18 @@ void Application::socketReadyRead()
345345
case SocketCmd::LockAll:
346346
getMainWindow()->lockAllDatabases();
347347
break;
348+
case SocketCmd::Unlock:
349+
QString filename, password, keyfile;
350+
in >> filename >> password >> keyfile;
351+
emit openFile(filename, password, keyfile);
352+
break;
348353
}
349354

350355
socket->deleteLater();
351356
}
352357

353358
bool Application::isAlreadyRunning() const
354359
{
355-
#ifdef QT_DEBUG
356-
// In DEBUG mode we can run unlimited instances
357-
return false;
358-
#endif
359360
return config()->get(Config::SingleInstance).toBool() && m_alreadyRunning;
360361
}
361362

@@ -392,7 +393,7 @@ bool Application::sendSocketCommand(SocketCmd id, const std::function<void(QData
392393
*/
393394
bool Application::sendFileNamesToRunningInstance(const QStringList& fileNames)
394395
{
395-
return this->sendSocketCommand(SocketCmd::OpenFiles, [fileNames](QDataStream& out) { out << fileNames; });
396+
return this->sendSocketCommand(SocketCmd::OpenFiles, [&](QDataStream& out) { out << fileNames; });
396397
}
397398

398399
/**
@@ -405,6 +406,17 @@ bool Application::sendLockToInstance()
405406
return this->sendSocketCommand(SocketCmd::LockAll, [](QDataStream&) { /* No Data */ });
406407
}
407408

409+
/**
410+
* Open and unlock a database file in the running instance
411+
*
412+
* @return true if the instance receives the request
413+
*/
414+
bool Application::sendUnlockToInstance(const QString& filename, const QString& password, const QString& keyfile)
415+
{
416+
return this->sendSocketCommand(SocketCmd::Unlock,
417+
[&](QDataStream& out) { out << filename << password << keyfile; });
418+
}
419+
408420
bool Application::isDarkTheme() const
409421
{
410422
return m_darkTheme;

src/gui/Application.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,12 @@ class Application : public QApplication
5353

5454
bool sendFileNamesToRunningInstance(const QStringList& fileNames);
5555
bool sendLockToInstance();
56+
bool sendUnlockToInstance(const QString& filename, const QString& password = {}, const QString& keyfile = {});
5657

5758
void restart();
5859

5960
signals:
60-
void openFile(const QString& filename);
61+
void openFile(const QString& filename, const QString& password = {}, const QString& keyfile = {});
6162
void anotherInstanceStarted();
6263
void applicationActivated();
6364
void quitSignalReceived();

src/gui/MainWindow.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -661,8 +661,8 @@ MainWindow::MainWindow()
661661

662662
connect(qApp, SIGNAL(anotherInstanceStarted()), this, SLOT(bringToFront()));
663663
connect(qApp, SIGNAL(applicationActivated()), this, SLOT(bringToFront()));
664-
connect(qApp, SIGNAL(openFile(QString)), this, SLOT(openDatabase(QString)));
665664
connect(qApp, SIGNAL(quitSignalReceived()), this, SLOT(appExit()), Qt::DirectConnection);
665+
connect(static_cast<Application*>(qApp), &Application::openFile, this, &MainWindow::openDatabase);
666666

667667
// Setup the status bar
668668
statusBar()->setFixedHeight(24);

src/main.cpp

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,18 @@ Q_IMPORT_PLUGIN(QXcbIntegrationPlugin)
4949
#include <windows.h>
5050
#endif
5151

52+
namespace
53+
{
54+
QString promptPassword()
55+
{
56+
// we always need consume a line of STDIN if --pw-stdin is set to clear out the
57+
// buffer for native messaging, even if the specified file does not exist
58+
QTextStream out(stdout, QIODevice::WriteOnly);
59+
out << QObject::tr("Database password: ") << Qt::flush;
60+
return Utils::getPassword();
61+
}
62+
} // namespace
63+
5264
int main(int argc, char** argv)
5365
{
5466
QT_REQUIRE_VERSION(argc, argv, QT_VERSION_STR)
@@ -140,9 +152,14 @@ int main(int argc, char** argv)
140152
}
141153
}
142154
#endif
155+
Utils::setDefaultTextStreams();
156+
157+
const bool pwstdin = parser.isSet(pwstdinOption);
158+
const QString keyfile = parser.value(keyfileOption);
143159

144160
// Process single instance and early exit if already running
145161
if (app.isAlreadyRunning()) {
162+
qWarning() << QObject::tr("Another instance of KeePassXC is already running.").toUtf8().constData();
146163
if (parser.isSet(lockOption)) {
147164
if (app.sendLockToInstance()) {
148165
qInfo() << QObject::tr("Databases have been locked.").toUtf8().constData();
@@ -151,11 +168,13 @@ int main(int argc, char** argv)
151168
return EXIT_FAILURE;
152169
}
153170
} else {
154-
if (!fileNames.isEmpty()) {
155-
app.sendFileNamesToRunningInstance(fileNames);
171+
for (const QString& filename : fileNames) {
172+
QString password;
173+
if (pwstdin) {
174+
password = promptPassword();
175+
}
176+
app.sendUnlockToInstance(filename, password, keyfile);
156177
}
157-
158-
qWarning() << QObject::tr("Another instance of KeePassXC is already running.").toUtf8().constData();
159178
}
160179
return EXIT_SUCCESS;
161180
}
@@ -176,8 +195,6 @@ int main(int argc, char** argv)
176195
return EXIT_FAILURE;
177196
}
178197

179-
Utils::setDefaultTextStreams();
180-
181198
// Apply the configured theme before creating any GUI elements
182199
app.applyTheme();
183200

@@ -195,17 +212,12 @@ int main(int argc, char** argv)
195212
// This ensures any top-level windows (Main Window, Modal Dialogs, etc.) are excluded from screenshots
196213
mainWindow.setAllowScreenCapture(parser.isSet(allowScreenCaptureOption));
197214

198-
const bool pwstdin = parser.isSet(pwstdinOption);
199215
for (const QString& filename : fileNames) {
200216
QString password;
201217
if (pwstdin) {
202-
// we always need consume a line of STDIN if --pw-stdin is set to clear out the
203-
// buffer for native messaging, even if the specified file does not exist
204-
QTextStream out(stdout, QIODevice::WriteOnly);
205-
out << QObject::tr("Database password: ") << Qt::flush;
206-
password = Utils::getPassword();
218+
password = promptPassword();
207219
}
208-
mainWindow.openDatabase(filename, password, parser.value(keyfileOption));
220+
mainWindow.openDatabase(filename, password, keyfile);
209221
}
210222

211223
// start minimized if configured

0 commit comments

Comments
 (0)