Add command line option to lock open databases (#6511)

Closes #6126
This commit is contained in:
wundrweapon 2021-05-15 09:48:59 -04:00 committed by GitHub
parent cc6f5c3226
commit 60adcacaaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 79 additions and 11 deletions

View File

@ -307,13 +307,26 @@ void Application::socketReadyRead()
}
QStringList fileNames;
in >> fileNames;
for (const QString& fileName : asConst(fileNames)) {
const QFileInfo fInfo(fileName);
if (fInfo.isFile() && fInfo.suffix().toLower() == "kdbx") {
emit openFile(fileName);
quint32 id;
in >> id;
// TODO: move constants to enum
switch (id) {
case 1:
in >> fileNames;
for (const QString& fileName : asConst(fileNames)) {
const QFileInfo fInfo(fileName);
if (fInfo.isFile() && fInfo.suffix().toLower() == "kdbx") {
emit openFile(fileName);
}
}
break;
case 2:
getMainWindow()->lockAllDatabases();
break;
}
socket->deleteLater();
}
@ -326,6 +339,12 @@ bool Application::isAlreadyRunning() const
return config()->get(Config::SingleInstance).toBool() && m_alreadyRunning;
}
/**
* Send to-open file names to the running UI instance
*
* @param fileNames - list of file names to open
* @return true if all operations succeeded (connection made, data sent, connection closed)
*/
bool Application::sendFileNamesToRunningInstance(const QStringList& fileNames)
{
QLocalSocket client;
@ -338,13 +357,48 @@ bool Application::sendFileNamesToRunningInstance(const QStringList& fileNames)
QByteArray data;
QDataStream out(&data, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_0);
out << quint32(0) << fileNames;
out << quint32(0); // reserve space for block size
out << quint32(1); // ID for file name send. TODO: move to enum
out << fileNames; // send file names to be opened
out.device()->seek(0);
out << quint32(data.size() - sizeof(quint32));
out << quint32(data.size() - sizeof(quint32)); // replace the previous constant 0 with block size
const bool writeOk = client.write(data) != -1 && client.waitForBytesWritten(WaitTimeoutMSec);
client.disconnectFromServer();
const bool disconnected = client.waitForDisconnected(WaitTimeoutMSec);
const bool disconnected =
client.state() == QLocalSocket::UnconnectedState || client.waitForDisconnected(WaitTimeoutMSec);
return writeOk && disconnected;
}
/**
* Locks all open databases in the running instance
*
* @return true if the "please lock" signal was sent successfully
*/
bool Application::sendLockToInstance()
{
// Make a connection to avoid SIGSEGV
QLocalSocket client;
client.connectToServer(m_socketName);
const bool connected = client.waitForConnected(WaitTimeoutMSec);
if (!connected) {
return false;
}
// Send lock signal
QByteArray data;
QDataStream out(&data, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_0);
out << quint32(0); // reserve space for block size
out << quint32(2); // ID for database lock. TODO: move to enum
out.device()->seek(0);
out << quint32(data.size() - sizeof(quint32)); // replace the previous constant 0 with block size
// Finish gracefully
const bool writeOk = client.write(data) != -1 && client.waitForBytesWritten(WaitTimeoutMSec);
client.disconnectFromServer();
const bool disconnected =
client.state() == QLocalSocket::UnconnectedState || client.waitForConnected(WaitTimeoutMSec);
return writeOk && disconnected;
}

View File

@ -50,6 +50,7 @@ public:
bool isDarkTheme() const;
bool sendFileNamesToRunningInstance(const QStringList& fileNames);
bool sendLockToInstance();
void restart();

View File

@ -71,6 +71,7 @@ int main(int argc, char** argv)
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 lockOption("lock", QObject::tr("lock all open databases"));
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 allowScreenCaptureOption("allow-screencapture",
@ -81,6 +82,7 @@ int main(int argc, char** argv)
QCommandLineOption debugInfoOption(QStringList() << "debug-info", QObject::tr("Displays debugging information."));
parser.addOption(configOption);
parser.addOption(localConfigOption);
parser.addOption(lockOption);
parser.addOption(keyfileOption);
parser.addOption(pwstdinOption);
parser.addOption(debugInfoOption);
@ -110,12 +112,23 @@ int main(int argc, char** argv)
}
// Process single instance and early exit if already running
// FIXME: this is a *mess* and it is entirely my fault. --wundrweapon
const QStringList fileNames = parser.positionalArguments();
if (app.isAlreadyRunning()) {
if (!fileNames.isEmpty()) {
app.sendFileNamesToRunningInstance(fileNames);
if (parser.isSet(lockOption)) {
if (app.sendLockToInstance()) {
qInfo() << QObject::tr("Locked databases.").toUtf8().constData();
} else {
qWarning() << QObject::tr("Database failed to lock.").toUtf8().constData();
return EXIT_FAILURE;
}
} else {
if (!fileNames.isEmpty()) {
app.sendFileNamesToRunningInstance(fileNames);
}
qWarning() << QObject::tr("Another instance of KeePassXC is already running.").toUtf8().constData();
}
qWarning() << QObject::tr("Another instance of KeePassXC is already running.").toUtf8().constData();
return EXIT_SUCCESS;
}