diff --git a/src/lib/client/Client.cpp b/src/lib/client/Client.cpp index 64a2a95cc..5952013f7 100644 --- a/src/lib/client/Client.cpp +++ b/src/lib/client/Client.cpp @@ -14,7 +14,6 @@ #include "base/NetworkProtocol.h" #include "client/ServerProxy.h" #include "common/Settings.h" -#include "deskflow/ipc/CoreIpc.h" #include "deskflow/Clipboard.h" #include "deskflow/IPlatformScreen.h" #include "deskflow/PacketStreamFilter.h" @@ -22,11 +21,14 @@ #include "deskflow/ProtocolUtil.h" #include "deskflow/Screen.h" #include "deskflow/StreamChunker.h" +#include "deskflow/ipc/CoreIpc.h" #include "net/IDataSocket.h" #include "net/ISocketFactory.h" #include "net/SecureSocket.h" #include "net/TCPSocket.h" +#include + #include #include @@ -133,8 +135,11 @@ void Client::disconnect(const char *msg) } } -void Client::refuseConnection(const char *msg) +void Client::refuseConnection(deskflow::core::ConnectionRefusal reason, const char *msg) { + const auto metaEnum = QMetaEnum::fromType(); + ipcSendToClient("connectionRefused", metaEnum.valueToKey(static_cast(reason))); + cleanup(); if (msg) { diff --git a/src/lib/client/Client.h b/src/lib/client/Client.h index 7249ac284..f2f892a36 100644 --- a/src/lib/client/Client.h +++ b/src/lib/client/Client.h @@ -11,6 +11,7 @@ #include "deskflow/IClient.h" #include "base/EventTypes.h" +#include "common/Enums.h" #include "deskflow/IClipboard.h" #include "net/NetworkAddress.h" @@ -88,7 +89,7 @@ public: Disconnects from the server with an optional error message. Unlike disconnect this function doesn't try to use other ip addresses */ - void refuseConnection(const char *msg); + void refuseConnection(deskflow::core::ConnectionRefusal reason, const char *msg); //! Notify of handshake complete /*! diff --git a/src/lib/client/ServerProxy.cpp b/src/lib/client/ServerProxy.cpp index d2e38860e..600f05697 100644 --- a/src/lib/client/ServerProxy.cpp +++ b/src/lib/client/ServerProxy.cpp @@ -124,6 +124,7 @@ void ServerProxy::handleData() ServerProxy::ConnectionResult ServerProxy::parseHandshakeMessage(const uint8_t *code) { using enum ConnectionResult; + using enum deskflow::core::ConnectionRefusal; if (memcmp(code, kMsgQInfo, 4) == 0) { queryInfo(); @@ -168,25 +169,25 @@ ServerProxy::ConnectionResult ServerProxy::parseHandshakeMessage(const uint8_t * int32_t minor; ProtocolUtil::readf(m_stream, kMsgEIncompatible + 4, &major, &minor); LOG_ERR("server has incompatible version %d.%d", major, minor); - m_client->refuseConnection("server has incompatible version"); + m_client->refuseConnection(IncompatibleVersion, "server has incompatible version"); return Disconnect; } else if (memcmp(code, kMsgEBusy, 4) == 0) { LOG_ERR("server already has a connected client with name \"%s\"", m_client->getName().c_str()); - m_client->refuseConnection("server already has a connected client with our name"); + m_client->refuseConnection(AlreadyConnected, "server already has a connected client with our name"); return Disconnect; } else if (memcmp(code, kMsgEUnknown, 4) == 0) { LOG_ERR("server refused client with name \"%s\"", m_client->getName().c_str()); - m_client->refuseConnection("server refused client with our name"); + m_client->refuseConnection(UnknownClient, "server refused client with our name"); return Disconnect; } else if (memcmp(code, kMsgEBad, 4) == 0) { LOG_ERR("server disconnected due to a protocol error"); - m_client->refuseConnection("server reported a protocol error"); + m_client->refuseConnection(ProtocolError, "server reported a protocol error"); return Disconnect; } else if (memcmp(code, kMsgDLanguageSynchronisation, 4) == 0) { setServerLanguages(); diff --git a/src/lib/common/Enums.h b/src/lib/common/Enums.h index b9af3c698..7daf1eb77 100644 --- a/src/lib/common/Enums.h +++ b/src/lib/common/Enums.h @@ -43,4 +43,14 @@ enum class ConnectionState Listening }; Q_ENUM_NS(ConnectionState) + +enum class ConnectionRefusal +{ + IncompatibleVersion, + AlreadyConnected, + UnknownClient, + ProtocolError +}; +Q_ENUM_NS(ConnectionRefusal) + } // namespace deskflow::core diff --git a/src/lib/deskflow/ipc/IpcServer.cpp b/src/lib/deskflow/ipc/IpcServer.cpp index 131c1d93d..39eff2971 100644 --- a/src/lib/deskflow/ipc/IpcServer.cpp +++ b/src/lib/deskflow/ipc/IpcServer.cpp @@ -7,6 +7,7 @@ #include "IpcServer.h" #include "base/Log.h" +#include "common/VersionInfo.h" #include #include @@ -110,8 +111,21 @@ void IpcServer::processMessage(QLocalSocket *clientSocket, const QString &messag } if (const auto &command = parts.at(0); command == "hello") { + const auto versionId = QStringLiteral("%1+%2").arg(kVersion, kVersionGitSha); + const auto clientVersion = parts.size() >= 2 ? parts.at(1) : QString(); + if (clientVersion != versionId) { + LOG_ERR( + "ipc client version mismatch (client: %s, server: %s)", + clientVersion.isEmpty() ? "unknown" : clientVersion.toUtf8().constData(), versionId.toUtf8().constData() + ); + writeToClientSocket(clientSocket, "error"); + clientSocket->flush(); + clientSocket->disconnectFromServer(); + return; + } + LOG_DEBUG("ipc server got hello message, sending hello back"); - writeToClientSocket(clientSocket, "hello"); + writeToClientSocket(clientSocket, QString("hello=%1").arg(versionId)); // Replay messages that were queued before any clients connected. LOG_DEBUG1("ipc server replaying %d pending messages", m_pendingMessages.size()); diff --git a/src/lib/gui/CMakeLists.txt b/src/lib/gui/CMakeLists.txt index 5d46fea13..e3f7bd9e7 100644 --- a/src/lib/gui/CMakeLists.txt +++ b/src/lib/gui/CMakeLists.txt @@ -39,7 +39,6 @@ add_library(${target} STATIC TlsUtility.h VersionChecker.cpp VersionChecker.h - config/IServerConfig.h config/Screen.cpp config/Screen.h config/ScreenConfig.cpp @@ -48,16 +47,10 @@ add_library(${target} STATIC config/ScreenList.h config/ServerConfig.cpp config/ServerConfig.h - core/ClientConnection.cpp - core/ClientConnection.h core/CoreProcess.cpp core/CoreProcess.h core/NetworkMonitor.cpp core/NetworkMonitor.h - core/ServerConnection.cpp - core/ServerConnection.h - core/ServerMessage.cpp - core/ServerMessage.h dialogs/AboutDialog.cpp dialogs/AboutDialog.h dialogs/AboutDialog.ui diff --git a/src/lib/gui/MainWindow.cpp b/src/lib/gui/MainWindow.cpp index f2f396740..bd8b7177a 100644 --- a/src/lib/gui/MainWindow.cpp +++ b/src/lib/gui/MainWindow.cpp @@ -58,8 +58,6 @@ using namespace deskflow::gui; MainWindow::MainWindow() : ui{std::make_unique()}, m_coreProcess(m_serverConfig), - m_serverConnection(this, m_serverConfig), - m_clientConnection(this), m_trayIcon{new QSystemTrayIcon(this)}, m_guiDupeChecker{new QLocalServer(this)}, m_daemonIpcClient{new ipc::DaemonIpcClient(this)}, @@ -269,15 +267,11 @@ void MainWindow::connectSlots() if (!deskflow::platform::isMac()) connect(m_trayIcon, &QSystemTrayIcon::activated, this, &MainWindow::trayIconActivated); - connect(&m_serverConnection, &ServerConnection::configureClient, this, &MainWindow::serverConnectionConfigureClient); - connect(&m_serverConnection, &ServerConnection::clientsChanged, this, &MainWindow::serverClientsChanged); connect(&m_coreProcess, &CoreProcess::connectedClientsChanged, this, &MainWindow::serverClientsChanged); - connect( - &m_serverConnection, &ServerConnection::requestNewClientPrompt, this, &MainWindow::handleNewClientPromptRequest - ); - - connect(&m_clientConnection, &ClientConnection::requestShowError, this, &MainWindow::showClientError); - connect(&m_clientConnection, &ClientConnection::updateTimeoutDelay, this, &MainWindow::updateTimeoutDelay); + connect(&m_coreProcess, &CoreProcess::unrecognisedClient, this, &MainWindow::handleUnrecognisedClient); + connect(&m_coreProcess, &CoreProcess::connectionRefused, this, &MainWindow::handleConnectionRefused); + connect(&m_coreProcess, &CoreProcess::retryIn, this, &MainWindow::updateTimeoutDelay); + connect(&m_coreProcess, &CoreProcess::peerFingerprint, this, &MainWindow::handlePeerFingerprint); if (Settings::value(Settings::Gui::AutoStartCore).toBool()) { connect(ui->btnToggleCore, &QPushButton::clicked, m_actionStopCore, &QAction::trigger, Qt::UniqueConnection); @@ -430,8 +424,6 @@ void MainWindow::clearSettings() m_networkMonitor->stopMonitoring(); disconnect(&m_coreProcess, nullptr, this, nullptr); - disconnect(&m_serverConnection, nullptr, this, nullptr); - disconnect(&m_clientConnection, nullptr, this, nullptr); disconnect(&m_versionChecker, nullptr, this, nullptr); disconnect(m_guiDupeChecker, nullptr, this, nullptr); disconnect(m_trayIcon, nullptr, this, nullptr); @@ -598,12 +590,12 @@ void MainWindow::updateNetworkInfo() void MainWindow::serverConnectionConfigureClient(const QString &clientName) { - m_serverConnection.serverConfigDialogVisible(true); + m_serverConfigDialogVisible = true; ServerConfigDialog dialog(this, m_serverConfig); if (dialog.addClient(clientName) && dialog.exec() == QDialog::Accepted) { m_coreProcess.restart(); } - m_serverConnection.serverConfigDialogVisible(false); + m_serverConfigDialogVisible = false; } ////////////////////////////////////////////////////////////////////////////// @@ -755,35 +747,64 @@ void MainWindow::setTrayIcon() void MainWindow::handleLogLine(const QString &line) { m_logDock->appendLine(line); - updateFromLogLine(line); } -void MainWindow::updateFromLogLine(const QString &line) +void MainWindow::handleUnrecognisedClient(const QString &clientName) { - checkConnected(line); - checkFingerprint(line); -} - -void MainWindow::checkConnected(const QString &line) -{ - if (ui->rbModeServer->isChecked()) { - m_serverConnection.handleLogLine(line); - } else { - m_clientConnection.handleLogLine(line); + if (m_ignoredClients.contains(clientName)) { + qDebug("ignoring %s:", qPrintable(clientName)); + return; } -} -void MainWindow::checkFingerprint(const QString &line) -{ - static const auto tlsPeerMessage = QStringLiteral("peer fingerprint: "); - static const qsizetype msgLen = QString(tlsPeerMessage).length(); - - const qsizetype midStart = line.indexOf(tlsPeerMessage); - if (midStart == -1) + if (m_newClientPromptShowing || m_serverConfigDialogVisible) return; - const auto sha256Text = line.mid(midStart + msgLen).remove(':'); + if (Settings::value(Settings::Server::ExternalConfig).toBool()) + return; + if (m_serverConfig.isFull() || m_serverConfig.screenExists(clientName)) + return; + + m_newClientPromptShowing = true; + + showAndActivate(); + + if (deskflow::gui::messages::showNewClientPrompt(this, clientName)) { + serverConnectionConfigureClient(clientName); + } else { + m_ignoredClients.insert(clientName); + } + + m_newClientPromptShowing = false; +} + +void MainWindow::handleConnectionRefused(deskflow::core::ConnectionRefusal reason) +{ + if (reason != deskflow::core::ConnectionRefusal::AlreadyConnected) + return; + + if (!isVisible() || m_clientErrorVisible) + return; + + m_clientErrorVisible = true; + showAndActivate(); + + const auto address = Settings::value(Settings::Client::RemoteHost).toString(); + QMessageBox::warning( + this, tr("%1 Connection Error").arg(kAppName), + tr("

Failed to connect to the server '%1'.

" + "

A Client with your name is already connected to the server.

" + "Please ensure that you're using a unique name and that only a " + "single instance of the client process is running.

") + .arg(address) + ); + + m_clientErrorVisible = false; +} + +void MainWindow::handlePeerFingerprint(const QString &fingerprint) +{ + const auto sha256Text = QString(fingerprint).remove(':'); const Fingerprint sha256 = {QCryptographicHash::Sha256, QByteArray::fromHex(sha256Text.toLatin1())}; const bool isClient = m_coreProcess.mode() == CoreMode::Client; @@ -959,7 +980,7 @@ void MainWindow::changeEvent(QEvent *e) updateModeControlLabels(); updateNetworkInfo(); updateStatus(); - serverClientsChanged(m_serverConnection.connectedClients()); + serverClientsChanged({}); updateText(); } } @@ -1167,34 +1188,6 @@ void MainWindow::remoteHostChanged(const QString &newRemoteHost) } } -void MainWindow::showClientError(deskflow::client::ErrorType error, const QString &address) -{ - if (!isVisible() || m_clientErrorVisible || error != deskflow::client::ErrorType::AlreadyConnected) - return; - - m_clientErrorVisible = true; - - showAndActivate(); - - QMessageBox::warning( - this, tr("%1 Connection Error").arg(kAppName), - tr("

Failed to connect to the server '%1'.

" - "

A Client with your name is already connected to the server.

" - "Please ensure that you're using a unique name and that only a " - "single instance of the client process is running.

") - .arg(address) - ); - - m_clientErrorVisible = false; -} - -void MainWindow::handleNewClientPromptRequest(const QString &clientName) -{ - showAndActivate(); - bool result = deskflow::gui::messages::showNewClientPrompt(this, clientName); - m_serverConnection.handleNewClientResult(clientName, result); -} - void MainWindow::updateIpLabel(const QStringList &addresses) { if (m_coreProcess.mode() != CoreMode::Server) { diff --git a/src/lib/gui/MainWindow.h b/src/lib/gui/MainWindow.h index 21c688f70..fbac2fcc8 100644 --- a/src/lib/gui/MainWindow.h +++ b/src/lib/gui/MainWindow.h @@ -16,10 +16,8 @@ #include "VersionChecker.h" #include "config/ServerConfig.h" -#include "gui/core/ClientConnection.h" #include "gui/core/CoreProcess.h" #include "gui/core/NetworkMonitor.h" -#include "gui/core/ServerConnection.h" #include "net/Fingerprint.h" #ifdef Q_OS_MACOS @@ -118,9 +116,9 @@ private: void setupTrayIcon(); void applyConfig(); void setTrayIcon(); - void updateFromLogLine(const QString &line); - void checkConnected(const QString &line); - void checkFingerprint(const QString &line); + void handleUnrecognisedClient(const QString &clientName); + void handleConnectionRefused(deskflow::core::ConnectionRefusal reason); + void handlePeerFingerprint(const QString &fingerprint); void closeEvent(QCloseEvent *event) override; void secureSocket(bool secureSocket); void connectSlots(); @@ -140,17 +138,10 @@ private: void daemonIpcClientConnectionFailed(); void toggleCanRunCore(bool enableButtons); void remoteHostChanged(const QString &newRemoteHost); - void handleNewClientPromptRequest(const QString &clientName); void updateIpLabel(const QStringList &addresses); void updateTimeoutDelay(int newDelay); bool canRunCore() const; - /** - * @brief showClientError - * @param error Error Type - * @param address - */ - void showClientError(deskflow::client::ErrorType error, const QString &address); /** * @brief trustedFingerprintDatabase get the FingerprintDatabase for the trusted clients or trusted servers. @@ -177,8 +168,9 @@ private: bool m_clientErrorVisible = false; ServerConfig m_serverConfig; deskflow::gui::CoreProcess m_coreProcess; - deskflow::gui::ServerConnection m_serverConnection; - deskflow::gui::ClientConnection m_clientConnection; + QSet m_ignoredClients; + bool m_newClientPromptShowing = false; + bool m_serverConfigDialogVisible = false; QSize m_expandedSize = QSize(); QStringList m_checkedClients; QStringList m_checkedServers; diff --git a/src/lib/gui/config/IServerConfig.h b/src/lib/gui/config/IServerConfig.h deleted file mode 100644 index 940918305..000000000 --- a/src/lib/gui/config/IServerConfig.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2024 Symless Ltd. - * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception - */ - -#pragma once - -#include -#include - -#include "ScreenList.h" - -namespace deskflow::gui { - -// TODO: Remove this class, when the ServerConnectionTests are ported to QTests -class IServerConfig -{ -public: - virtual ~IServerConfig() = default; - virtual bool isFull() const = 0; - virtual bool screenExists(const QString &screenName) const = 0; - virtual bool save(const QString &fileName) const = 0; - virtual void save(QFile &file) const = 0; - virtual const ScreenList &screens() const = 0; -}; - -} // namespace deskflow::gui diff --git a/src/lib/gui/config/ServerConfig.h b/src/lib/gui/config/ServerConfig.h index ca6f70cf6..80e86966b 100644 --- a/src/lib/gui/config/ServerConfig.h +++ b/src/lib/gui/config/ServerConfig.h @@ -9,7 +9,6 @@ #include "base/NetworkProtocol.h" #include "gui/Hotkey.h" -#include "gui/config/IServerConfig.h" #include "gui/config/ScreenConfig.h" #include "gui/config/ScreenList.h" @@ -31,21 +30,18 @@ const auto kDefaultProtocol = NetworkProtocol::Barrier; } // namespace deskflow::gui -class ServerConfig : public ScreenConfig, public deskflow::gui::IServerConfig +class ServerConfig : public ScreenConfig { friend class ServerConfigDialog; friend QTextStream &operator<<(QTextStream &outStream, const ServerConfig &config); public: explicit ServerConfig(int columns = kDefaultColumns, int rows = kDefaultRows); - ~ServerConfig() override = default; + ~ServerConfig() = default; bool operator==(const ServerConfig &sc) const; - // - // Overrides - // - const ScreenList &screens() const override + const ScreenList &screens() const { return m_Screens; } @@ -131,17 +127,10 @@ public: } static size_t defaultClipboardSharingSize(); - // - // Overrides - // - bool save(const QString &fileName) const override; - bool screenExists(const QString &screenName) const override; - void save(QFile &file) const override; - bool isFull() const override; - - // - // New methods - // + bool save(const QString &fileName) const; + bool screenExists(const QString &screenName) const; + void save(QFile &file) const; + bool isFull() const; void commit(); int numScreens() const; QString getServerName() const; diff --git a/src/lib/gui/core/ClientConnection.cpp b/src/lib/gui/core/ClientConnection.cpp deleted file mode 100644 index 499cc1e0e..000000000 --- a/src/lib/gui/core/ClientConnection.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2025 Deskflow Developers - * SPDX-FileCopyrightText: (C) 2021 Symless Ltd. - * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception - */ - -#include "ClientConnection.h" - -#include "common/Settings.h" - -#include - -namespace deskflow::gui { - -void ClientConnection::handleLogLine(const QString &logLine) -{ - if (logLine.contains("disconnected from server")) { - m_supressMessage = false; - return; - } - - if (logLine.contains("retry in ") && Settings::value(Settings::Client::DynamicConnectionRetry).toBool()) { - auto line = logLine.mid(logLine.indexOf("in ") + 3); - int seconds = line.mid(0, line.indexOf(" ")).toInt(); - Q_EMIT updateTimeoutDelay(seconds); - return; - } - if (logLine.contains("connected to server")) { - m_supressMessage = true; - return; - } - - if (logLine.contains("failed to connect to server")) { - if (m_supressMessage) { - qDebug("message already shown, skipping"); - return; - } - // ignore the message if it's about the server refusing by name as - // this will trigger the server to show an 'add client' dialog. - if (logLine.contains("server refused client with our name")) { - qDebug("ignoring client name refused message"); - return; - } - showMessage(logLine); - } -} - -void ClientConnection::showMessage(const QString &logLine) -{ - using enum deskflow::client::ErrorType; - - if (logLine.isEmpty()) - return; - - const auto address = Settings::value(Settings::Client::RemoteHost).toString(); - auto error = NoError; - - if (logLine.contains("server already has a connected client with our name")) { - error = AlreadyConnected; - } else if (QHostAddress a(address); a.isNull()) { - qDebug("ip not detected, showing hostname error"); - error = HostnameError; - } else { - qDebug("ip detected, showing generic error"); - error = GenericError; - } - - if (error == NoError) - return; - - Q_EMIT requestShowError(error, address); -} - -} // namespace deskflow::gui diff --git a/src/lib/gui/core/ClientConnection.h b/src/lib/gui/core/ClientConnection.h deleted file mode 100644 index 377cbeea0..000000000 --- a/src/lib/gui/core/ClientConnection.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2025 Deskflow Developers - * SPDX-FileCopyrightText: (C) 2021 Symless Ltd. - * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception - */ - -#pragma once - -#include "common/Enums.h" - -#include -#include - -class QWidget; - -namespace deskflow::gui { - -class ClientConnection : public QObject -{ - Q_OBJECT - -public: - explicit ClientConnection(QWidget *parent) : m_pParent(parent) - { - // do nothing - } - - void handleLogLine(const QString &line); - -Q_SIGNALS: - /** - * @brief requestShowError, This signal is emitted when the client - * connection would like the owning process to report an error message - * @param error the type of error being reported - * @param address of the host - */ - void requestShowError(deskflow::client::ErrorType error, const QString &address); - void updateTimeoutDelay(int newTimeout); - -private: - void showMessage(const QString &logLine); - - QWidget *m_pParent; - bool m_supressMessage = false; -}; - -} // namespace deskflow::gui diff --git a/src/lib/gui/core/CoreProcess.cpp b/src/lib/gui/core/CoreProcess.cpp index ef61cbe57..935f36081 100644 --- a/src/lib/gui/core/CoreProcess.cpp +++ b/src/lib/gui/core/CoreProcess.cpp @@ -99,7 +99,7 @@ QString CoreProcess::wrapIpv6(const QString &address) // CoreProcess // -CoreProcess::CoreProcess(const IServerConfig &serverConfig) +CoreProcess::CoreProcess(const ServerConfig &serverConfig) : m_serverConfig(serverConfig), m_daemonIpcClient{new ipc::DaemonIpcClient(this)} { @@ -430,7 +430,7 @@ void CoreProcess::stop(std::optional processModeOption) if (m_coreIpcClient) { m_coreIpcClient->disconnectFromServer(); - delete m_coreIpcClient; + m_coreIpcClient->deleteLater(); m_coreIpcClient = nullptr; } @@ -548,6 +548,22 @@ void CoreProcess::onCoreIpcMessageReceived(const QString &command, const QString m_secureSocketVersion = args; Q_EMIT securityLevelChanged(args); } + } else if (command == "unrecognisedClient") { + Q_EMIT unrecognisedClient(args); + } else if (command == "connectionRefused") { + const auto metaEnum = QMetaEnum::fromType(); + bool ok = false; + const auto reason = + static_cast(metaEnum.keyToValue(args.toUtf8().constData(), &ok)); + if (ok) { + Q_EMIT connectionRefused(reason); + } else { + qWarning("core ipc got unknown connection refusal: %s", args.toUtf8().constData()); + } + } else if (command == "retryIn") { + Q_EMIT retryIn(args.toInt()); + } else if (command == "peerFingerprint") { + Q_EMIT peerFingerprint(args); } } diff --git a/src/lib/gui/core/CoreProcess.h b/src/lib/gui/core/CoreProcess.h index 25abd0ac7..45cfa34be 100644 --- a/src/lib/gui/core/CoreProcess.h +++ b/src/lib/gui/core/CoreProcess.h @@ -10,7 +10,7 @@ #include "common/Enums.h" #include "common/Settings.h" #include "gui/FileTail.h" -#include "gui/config/IServerConfig.h" +#include "gui/config/ServerConfig.h" #include #include @@ -29,8 +29,6 @@ class CoreProcess : public QObject using ConnectionState = deskflow::core::ConnectionState; using ProcessMode = Settings::ProcessMode; using ProcessState = deskflow::core::ProcessState; - using IServerConfig = deskflow::gui::IServerConfig; - Q_OBJECT public: @@ -40,7 +38,7 @@ public: StartFailed }; - explicit CoreProcess(const IServerConfig &serverConfig); + explicit CoreProcess(const ServerConfig &serverConfig); void start(std::optional processMode = std::nullopt); void stop(std::optional processMode = std::nullopt); @@ -91,6 +89,10 @@ Q_SIGNALS: void daemonIpcClientConnectionFailed(); void connectedClientsChanged(const QStringList &clients); void securityLevelChanged(QString securityLevel); + void unrecognisedClient(const QString &clientName); + void connectionRefused(deskflow::core::ConnectionRefusal reason); + void retryIn(int seconds); + void peerFingerprint(const QString &fingerprint); private Q_SLOTS: void onProcessFinished(int exitCode, QProcess::ExitStatus); @@ -116,7 +118,7 @@ private: static QString processStateToString(const CoreProcess::ProcessState state); static QString wrapIpv6(const QString &address); - const IServerConfig &m_serverConfig; + const ServerConfig &m_serverConfig; QString m_address; ProcessState m_processState = ProcessState::Stopped; ConnectionState m_connectionState = ConnectionState::Disconnected; diff --git a/src/lib/gui/core/ServerConnection.cpp b/src/lib/gui/core/ServerConnection.cpp deleted file mode 100644 index f1ba9357d..000000000 --- a/src/lib/gui/core/ServerConnection.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2025 Deskflow Developers - * SPDX-FileCopyrightText: (C) 2021 Symless Ltd. - * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception - */ - -#include "ServerConnection.h" - -#include "ServerMessage.h" -#include "common/Settings.h" - -#include - -namespace deskflow::gui { - -ServerConnection::ServerConnection(QWidget *parent, IServerConfig &serverConfig) - : m_pParent(parent), - m_serverConfig(serverConfig) -{ -} - -void ServerConnection::handleLogLine(const QString &logLine) -{ - ServerMessage message(logLine); - const auto &clientName = message.getClientName(); - - if (m_ignoredClients.contains(clientName)) { - qDebug("ignoring %s:", qPrintable(clientName)); - return; - } - - if (message.isDisconnectedMessage()) { - m_connectedClients.remove(clientName); - Q_EMIT clientsChanged(connectedClients()); - return; - } - - if (message.isConnectedMessage()) { - m_connectedClients.insert(clientName); - Q_EMIT clientsChanged(connectedClients()); - return; - } - - if (!message.isNewClientMessage()) { - return; - } - - if (m_messageShowing) { - qDebug("new client message already shown, skipping for now"); - return; - } - - if (m_serverConfigDialogVisible) { - qDebug("server config dialog visible, skipping new client prompt"); - return; - } - - if (Settings::value(Settings::Server::ExternalConfig).toBool()) { - qDebug("external config enabled, skipping new client prompt"); - return; - } - - if (m_connectedClients.contains(clientName)) { - qDebug("already got request, skipping new client prompt for: %s", qPrintable(clientName)); - return; - } - - handleNewClient(clientName); -} - -void ServerConnection::handleNewClient(const QString &clientName) -{ - if (m_serverConfig.isFull()) { - qDebug("server config full, skipping new client prompt for: %s", qPrintable(clientName)); - return; - } - - if (m_serverConfig.screenExists(clientName)) { - qDebug("client already added, skipping new client prompt for: %s", qPrintable(clientName)); - return; - } - - m_messageShowing = true; - Q_EMIT requestNewClientPrompt(clientName); -} - -void ServerConnection::handleNewClientResult(const QString &clientName, bool acceptClient) -{ - m_messageShowing = false; - if (!acceptClient) { - qDebug("declined dialog, ignoring client: %s", qPrintable(clientName)); - m_ignoredClients.insert(clientName); - return; - } - - qDebug("accepted dialog, adding client: %s", qPrintable(clientName)); - Q_EMIT configureClient(clientName); - m_connectedClients.insert(clientName); - Q_EMIT clientsChanged(connectedClients()); -} - -QStringList ServerConnection::connectedClients() const -{ - return QStringList(m_connectedClients.begin(), m_connectedClients.end()); -} - -} // namespace deskflow::gui diff --git a/src/lib/gui/core/ServerConnection.h b/src/lib/gui/core/ServerConnection.h deleted file mode 100644 index fa656479f..000000000 --- a/src/lib/gui/core/ServerConnection.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2025 Deskflow Developers - * SPDX-FileCopyrightText: (C) 2021 Symless Ltd. - * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception - */ - -#pragma once - -#include - -#include "gui/Messages.h" -#include "gui/config/IServerConfig.h" - -namespace deskflow::gui { - -class ServerConnection : public QObject -{ - Q_OBJECT - using IServerConfig = deskflow::gui::IServerConfig; - -public: - explicit ServerConnection(QWidget *parent, IServerConfig &serverConfig); - void handleLogLine(const QString &logLine); - void serverConfigDialogVisible(bool visible) - { - m_serverConfigDialogVisible = visible; - } - - QStringList connectedClients() const; - void handleNewClientResult(const QString &clientName, bool acceptClient); - -Q_SIGNALS: - void requestNewClientPrompt(const QString &clientName); - void configureClient(const QString &clientName); - void clientsChanged(const QStringList &clients); - -private: - void handleNewClient(const QString &clientName); - - QWidget *m_pParent; - IServerConfig &m_serverConfig; - QSet m_connectedClients; - QSet m_ignoredClients; - bool m_messageShowing = false; - bool m_serverConfigDialogVisible = false; -}; - -} // namespace deskflow::gui diff --git a/src/lib/gui/core/ServerMessage.cpp b/src/lib/gui/core/ServerMessage.cpp deleted file mode 100644 index f29308f88..000000000 --- a/src/lib/gui/core/ServerMessage.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2021 Symless Ltd. - * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception - */ - -#include "ServerMessage.h" - -namespace deskflow::gui { - -ServerMessage::ServerMessage(const QString &message) : m_message(message), m_clientName(parseClientName(message)) -{ - // do nothing -} - -bool ServerMessage::isNewClientMessage() const -{ - return m_message.contains("unrecognised client name"); -} - -bool ServerMessage::isExitMessage() const -{ - return m_message.contains("process exited"); -} - -bool ServerMessage::isConnectedMessage() const -{ - return m_message.contains("has connected"); -} - -bool ServerMessage::isDisconnectedMessage() const -{ - return m_message.contains("has disconnected"); -} - -const QString &ServerMessage::getClientName() const -{ - return m_clientName; -} - -QString ServerMessage::parseClientName(const QString &line) const -{ - QString clientName("Unknown"); - - auto nameStart = line.indexOf('"') + 1; - - if (auto nameEnd = line.indexOf('"', nameStart); nameEnd > nameStart) { - clientName = line.mid(nameStart, nameEnd - nameStart); - } - - return clientName; -} - -} // namespace deskflow::gui diff --git a/src/lib/gui/core/ServerMessage.h b/src/lib/gui/core/ServerMessage.h deleted file mode 100644 index f08cbad64..000000000 --- a/src/lib/gui/core/ServerMessage.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2021 Symless Ltd. - * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception - */ - -#pragma once - -#include - -namespace deskflow::gui { - -class ServerMessage -{ - QString m_message; - QString m_clientName; - -public: - explicit ServerMessage(const QString &message); - - bool isNewClientMessage() const; - bool isExitMessage() const; - bool isConnectedMessage() const; - bool isDisconnectedMessage() const; - - const QString &getClientName() const; - -private: - QString parseClientName(const QString &line) const; -}; - -} // namespace deskflow::gui diff --git a/src/lib/gui/dialogs/SettingsDialog.cpp b/src/lib/gui/dialogs/SettingsDialog.cpp index 12409e378..b18623b4e 100644 --- a/src/lib/gui/dialogs/SettingsDialog.cpp +++ b/src/lib/gui/dialogs/SettingsDialog.cpp @@ -23,7 +23,7 @@ using namespace deskflow::gui; -SettingsDialog::SettingsDialog(QWidget *parent, const IServerConfig &serverConfig) +SettingsDialog::SettingsDialog(QWidget *parent, const ServerConfig &serverConfig) : QDialog(parent), ui{std::make_unique()}, m_serverConfig(serverConfig) diff --git a/src/lib/gui/dialogs/SettingsDialog.h b/src/lib/gui/dialogs/SettingsDialog.h index a20bb6ea2..92075919c 100644 --- a/src/lib/gui/dialogs/SettingsDialog.h +++ b/src/lib/gui/dialogs/SettingsDialog.h @@ -9,7 +9,7 @@ #pragma once #include -#include "gui/config/IServerConfig.h" +#include "gui/config/ServerConfig.h" namespace Ui { class SettingsDialog; @@ -17,13 +17,11 @@ class SettingsDialog; class SettingsDialog : public QDialog { - using IServerConfig = deskflow::gui::IServerConfig; - Q_OBJECT public: void extracted(); - SettingsDialog(QWidget *parent, const IServerConfig &serverConfig); + SettingsDialog(QWidget *parent, const ServerConfig &serverConfig); ~SettingsDialog() override; Q_SIGNALS: @@ -86,5 +84,5 @@ private: bool m_interfaceSetOnLoad = false; std::unique_ptr ui; - const IServerConfig &m_serverConfig; + const ServerConfig &m_serverConfig; }; diff --git a/src/lib/gui/ipc/IpcClient.cpp b/src/lib/gui/ipc/IpcClient.cpp index 1dfdd482b..644d94705 100644 --- a/src/lib/gui/ipc/IpcClient.cpp +++ b/src/lib/gui/ipc/IpcClient.cpp @@ -6,15 +6,14 @@ #include "IpcClient.h" +#include "common/VersionInfo.h" + #include #include #include namespace deskflow::gui::ipc { -const auto kTimeout = 1000; -const auto kRetryLimit = 3; - IpcClient::IpcClient(QObject *parent, const QString &socketName) : QObject(parent), m_socket{new QLocalSocket(this)}, @@ -48,6 +47,8 @@ void IpcClient::connectToServer() void IpcClient::attemptConnection() { + const auto kRetryLimit = 3; + if (m_retryCount >= kRetryLimit) { qWarning() << "ipc client failed to connect after" << kRetryLimit << "attempts"; m_state = State::Unconnected; @@ -67,8 +68,9 @@ void IpcClient::attemptConnection() connect( m_socket, &QLocalSocket::connected, this, [this] { - m_socket->write("hello\n"); - qDebug() << "ipc client sent hello"; + const auto versionId = QStringLiteral("%1+%2").arg(kVersion, kVersionGitSha); + m_socket->write(QString("hello=%1\n").arg(versionId).toUtf8()); + qDebug() << "ipc client sent hello with version:" << versionId; }, Qt::SingleShotConnection ); @@ -141,10 +143,8 @@ void IpcClient::handleReadyRead() continue; } - if (m_state == State::Connecting && parts.at(0) == "hello") { - m_state = State::Connected; - qDebug() << "ipc client connected"; - Q_EMIT connected(); + if (m_state == State::Connecting) { + handleHandshakeMessage(parts); continue; } @@ -156,6 +156,26 @@ void IpcClient::handleReadyRead() } } +void IpcClient::handleHandshakeMessage(const QStringList &parts) +{ + if (parts.at(0) != "hello") { + return; + } + + const auto versionId = QStringLiteral("%1+%2").arg(kVersion, kVersionGitSha); + const auto serverVersion = parts.size() >= 2 ? parts.at(1) : QString(); + if (serverVersion != versionId) { + qCritical() << "ipc version mismatch (client:" << versionId << "server:" << serverVersion << ")"; + disconnectFromServer(); + Q_EMIT connectionFailed(); + return; + } + + m_state = State::Connected; + qDebug() << "ipc client connected"; + Q_EMIT connected(); +} + void IpcClient::sendMessage(const QString &message) { if (m_state != State::Connected) { diff --git a/src/lib/gui/ipc/IpcClient.h b/src/lib/gui/ipc/IpcClient.h index 8e4068c5c..1f2b296d6 100644 --- a/src/lib/gui/ipc/IpcClient.h +++ b/src/lib/gui/ipc/IpcClient.h @@ -55,6 +55,7 @@ protected: private: void attemptConnection(); + void handleHandshakeMessage(const QStringList &parts); QLocalSocket *m_socket; State m_state{State::Unconnected}; diff --git a/src/lib/server/Server.cpp b/src/lib/server/Server.cpp index df505ea95..8e55e6b58 100644 --- a/src/lib/server/Server.cpp +++ b/src/lib/server/Server.cpp @@ -11,7 +11,6 @@ #include "base/IEventQueue.h" #include "base/Log.h" #include "deskflow/AppUtil.h" -#include "deskflow/ipc/CoreIpc.h" #include "deskflow/DeskflowException.h" #include "deskflow/IPlatformScreen.h" #include "deskflow/OptionTypes.h" @@ -19,6 +18,7 @@ #include "deskflow/ProtocolTypes.h" #include "deskflow/Screen.h" #include "deskflow/StreamChunker.h" +#include "deskflow/ipc/CoreIpc.h" #include "net/TCPSocket.h" #include "server/ClientListener.h" #include "server/ClientProxy.h" @@ -235,6 +235,7 @@ void Server::adoptClient(BaseClientProxy *client) // name must be in our configuration if (!m_config->isScreen(client->getName())) { LOG_WARN("unrecognised client name \"%s\", check server config", client->getName().c_str()); + ipcSendToClient("unrecognisedClient", QString::fromStdString(client->getName())); closeClient(client, kMsgEUnknown); return; } diff --git a/src/unittests/gui/core/CMakeLists.txt b/src/unittests/gui/core/CMakeLists.txt index 73da17091..0484b134b 100644 --- a/src/unittests/gui/core/CMakeLists.txt +++ b/src/unittests/gui/core/CMakeLists.txt @@ -1,25 +1,9 @@ # SPDX-FileCopyrightText: (C) 2025 Deskflow Developers # SPDX-License-Identifier: MIT -create_test( - NAME ClientConnectionTests - DEPENDS gui - SOURCE ClientConnectionTests.cpp - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/gui" -) - -create_test( - NAME ServerConnectionTests - DEPENDS gui - SOURCE ServerConnectionTests.cpp - WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/gui" -) - - create_test( NAME NetworkMonitorTests DEPENDS gui SOURCE NetworkMonitorTests.cpp WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/src/lib/gui" ) - diff --git a/src/unittests/gui/core/ClientConnectionTests.cpp b/src/unittests/gui/core/ClientConnectionTests.cpp deleted file mode 100644 index 7c25fe90d..000000000 --- a/src/unittests/gui/core/ClientConnectionTests.cpp +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello - * SPDX-FileCopyrightText: (C) 2024 Symless Ltd. - * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception - */ - -#include "ClientConnectionTests.h" - -#include "gui/core/ClientConnection.h" -#include - -#include - -using namespace deskflow::gui; - -void ClientConnectionTests::initTestCase() -{ - QDir dir; - QVERIFY(dir.mkpath(m_settingsPath)); - - QFile oldSettings(m_settingsFile); - if (oldSettings.exists()) - oldSettings.remove(); - - Settings::setSettingsFile(m_settingsFile); - Settings::setStateFile(m_stateFile); -} - -void ClientConnectionTests::handleLogLine_alreadyConnected_showError() -{ - ClientConnection clientConnection(nullptr); - const auto serverName = QStringLiteral("test server"); - Settings::setValue(Settings::Client::RemoteHost, serverName); - - QSignalSpy spy(&clientConnection, &ClientConnection::requestShowError); - QVERIFY(spy.isValid()); - - clientConnection.handleLogLine( - "failed to connect to server\n" - "server already has a connected client with our name" - ); - - QCOMPARE(spy.count(), 1); -} - -void ClientConnectionTests::handleLogLine_withHostname_showError() -{ - ClientConnection clientConnection(nullptr); - const auto serverName = QStringLiteral("test server"); - Settings::setValue(Settings::Client::RemoteHost, serverName); - - QSignalSpy spy(&clientConnection, &ClientConnection::requestShowError); - QVERIFY(spy.isValid()); - - clientConnection.handleLogLine("failed to connect to server"); - - QCOMPARE(spy.count(), 1); -} - -void ClientConnectionTests::handleLogLine_withIpAddress_showError() -{ - ClientConnection clientConnection(nullptr); - const auto serverName = QStringLiteral("1.1.1.1"); - Settings::setValue(Settings::Client::RemoteHost, serverName); - - QSignalSpy spy(&clientConnection, &ClientConnection::requestShowError); - QVERIFY(spy.isValid()); - - clientConnection.handleLogLine("failed to connect to server"); - - QCOMPARE(spy.count(), 1); -} - -void ClientConnectionTests::handleLogLine_serverRefusedClient_shouldNotShowError() -{ - ClientConnection clientConnection(nullptr); - - QSignalSpy spy(&clientConnection, &ClientConnection::requestShowError); - QVERIFY(spy.isValid()); - - clientConnection.handleLogLine( - "failed to connect to server\n" - "server refused client with our name" - ); - - QCOMPARE(spy.count(), 0); -} - -void ClientConnectionTests::handleLogLine_connected_shouldPreventFutureError() -{ - ClientConnection clientConnection(nullptr); - clientConnection.handleLogLine("connected to server"); - - QSignalSpy spy(&clientConnection, &ClientConnection::requestShowError); - QVERIFY(spy.isValid()); - - clientConnection.handleLogLine("failed to connect to server"); - - QCOMPARE(spy.count(), 0); -} - -void ClientConnectionTests::handleLogLine_connectToggled_showAfterDisconnect() -{ - ClientConnection clientConnection(nullptr); - clientConnection.handleLogLine("connected to server"); - - QSignalSpy spy(&clientConnection, &ClientConnection::requestShowError); - QVERIFY(spy.isValid()); - - clientConnection.handleLogLine("failed to connect to server"); - clientConnection.handleLogLine("disconnected from server"); - clientConnection.handleLogLine("failed to connect to server"); - - QCOMPARE(spy.count(), 1); -} - -void ClientConnectionTests::handleLogLine_otherMessage_shouldNotShowError() -{ - ClientConnection clientConnection(nullptr); - - QSignalSpy spy(&clientConnection, &ClientConnection::requestShowError); - QVERIFY(spy.isValid()); - - clientConnection.handleLogLine("hello world"); - - QCOMPARE(spy.count(), 0); -} - -QTEST_MAIN(ClientConnectionTests) diff --git a/src/unittests/gui/core/ClientConnectionTests.h b/src/unittests/gui/core/ClientConnectionTests.h deleted file mode 100644 index 33ff0e3cc..000000000 --- a/src/unittests/gui/core/ClientConnectionTests.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello - * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception - */ - -#include - -class ClientConnectionTests : public QObject -{ - Q_OBJECT -private Q_SLOTS: - // Test are run in order top to bottom - void initTestCase(); - void handleLogLine_alreadyConnected_showError(); - void handleLogLine_withHostname_showError(); - void handleLogLine_withIpAddress_showError(); - void handleLogLine_serverRefusedClient_shouldNotShowError(); - void handleLogLine_connected_shouldPreventFutureError(); - void handleLogLine_connectToggled_showAfterDisconnect(); - void handleLogLine_otherMessage_shouldNotShowError(); - -private: - inline static const QString m_settingsPath = QStringLiteral("tmp/test"); - inline static const QString m_settingsFile = QStringLiteral("%1/Deskflow.conf").arg(m_settingsPath); - inline static const QString m_stateFile = QStringLiteral("%1/Deskflow.state").arg(m_settingsPath); -}; diff --git a/src/unittests/gui/core/ServerConnectionTests.cpp b/src/unittests/gui/core/ServerConnectionTests.cpp deleted file mode 100644 index a40c5583f..000000000 --- a/src/unittests/gui/core/ServerConnectionTests.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello - * SPDX-FileCopyrightText: (C) 2024 Symless Ltd. - * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception - */ - -#include "ServerConnectionTests.h" - -#include "gui/config/ServerConfig.h" -#include "gui/core/ServerConnection.h" -#include - -#include - -using namespace deskflow::gui; - -class FullServerConfig : public ServerConfig -{ -public: - bool isFull() const override - { - return true; - } -}; - -class ScreenExistsServerConfig : public ServerConfig -{ -public: - bool screenExists(const QString &screenName) const override - { - return true; - } -}; - -void ServerConnectionTests::initTestCase() -{ - QDir dir; - QVERIFY(dir.mkpath(m_settingsPath)); - - QFile oldSettings(m_settingsFile); - if (oldSettings.exists()) - oldSettings.remove(); - - Settings::setSettingsFile(m_settingsFile); - Settings::setStateFile(m_stateFile); -} - -void ServerConnectionTests::handleLogLine_newClient_shouldShowPrompt() -{ - ServerConfig m_serverConfig; - ServerConnection serverConnection(nullptr, m_serverConfig); - - QString clientName = "test client"; - - QSignalSpy spy(&serverConnection, &ServerConnection::requestNewClientPrompt); - QVERIFY(spy.isValid()); - - serverConnection.handleLogLine(R"(unrecognised client name "test client")"); - QCOMPARE(spy.count(), 1); -} - -void ServerConnectionTests::handleLogLine_ignoredClient_shouldNotShowPrompt() -{ - ServerConfig m_serverConfig; - ServerConnection serverConnection(nullptr, m_serverConfig); - QString clientName = "test client"; - serverConnection.handleNewClientResult(clientName, false); - - QSignalSpy spy(&serverConnection, &ServerConnection::requestNewClientPrompt); - QVERIFY(spy.isValid()); - - serverConnection.handleLogLine(R"(unrecognised client name "test client")"); - QCOMPARE(spy.count(), 0); -} - -void ServerConnectionTests::handleLogLine_serverConfigFull_shouldNotShowPrompt() -{ - FullServerConfig m_serverConfig; - ServerConnection serverConnection(nullptr, m_serverConfig); - - QSignalSpy spy(&serverConnection, &ServerConnection::requestNewClientPrompt); - QVERIFY(spy.isValid()); - - serverConnection.handleLogLine(R"(unrecognised client name "test client")"); - QCOMPARE(spy.count(), 0); -} - -void ServerConnectionTests::handleLogLine_screenExists_shouldNotShowPrompt() -{ - ScreenExistsServerConfig m_serverConfig; - ServerConnection serverConnection(nullptr, m_serverConfig); - - QSignalSpy spy(&serverConnection, &ServerConnection::requestNewClientPrompt); - QVERIFY(spy.isValid()); - - serverConnection.handleLogLine(R"(unrecognised client name "test client")"); - QCOMPARE(spy.count(), 0); -} - -QTEST_MAIN(ServerConnectionTests) diff --git a/src/unittests/gui/core/ServerConnectionTests.h b/src/unittests/gui/core/ServerConnectionTests.h deleted file mode 100644 index 558775a25..000000000 --- a/src/unittests/gui/core/ServerConnectionTests.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Deskflow -- mouse and keyboard sharing utility - * SPDX-FileCopyrightText: (C) 2025 Chris Rizzitello - * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception - */ - -#include - -class ServerConnectionTests : public QObject -{ - Q_OBJECT -private Q_SLOTS: - // Test are run in order top to bottom - void initTestCase(); - void handleLogLine_newClient_shouldShowPrompt(); - void handleLogLine_ignoredClient_shouldNotShowPrompt(); - void handleLogLine_serverConfigFull_shouldNotShowPrompt(); - void handleLogLine_screenExists_shouldNotShowPrompt(); - -private: - inline static const QString m_settingsPath = QStringLiteral("tmp/test"); - inline static const QString m_settingsFile = QStringLiteral("%1/Deskflow.conf").arg(m_settingsPath); - inline static const QString m_stateFile = QStringLiteral("%1/Deskflow.state").arg(m_settingsPath); -};