From 3e4cb4a1c77c08bbe5f1e49131d0a11baf3dba8b Mon Sep 17 00:00:00 2001 From: Nick Bolton Date: Sun, 11 Aug 2024 00:58:24 +0100 Subject: [PATCH] Add reset settings menu action and env var (#7435) * Add reset settings menu action and env var * Delete profile and config dirs, reduce duplication with TLS dir and various other paths, fixed bug in new client dialog, move TLS arg to server * Better filename * Make method const * Update ChangeLog * Remove include * Make param const * Stop core process on reset * Fixed: reset menu action causes config to be pulled from app/server config * Center main window in middle of screen --- .env.example | 3 + ChangeLog | 1 + src/gui/src/MainWindow.cpp | 58 ++++-- src/gui/src/MainWindow.h | 4 + src/gui/src/MainWindowBase.ui | 8 + src/gui/src/main.cpp | 17 ++ src/lib/common/constants.h | 6 + src/lib/gui/config/AppConfig.cpp | 10 +- src/lib/gui/config/AppConfig.h | 36 ++-- src/lib/gui/config/ConfigScopes.cpp | 13 +- src/lib/gui/config/ConfigScopes.h | 4 +- src/lib/gui/config/IConfigScopes.h | 4 +- src/lib/gui/config/ServerConfigDialogState.h | 38 ++++ src/lib/gui/core/CoreProcess.cpp | 174 ++++++++++-------- src/lib/gui/core/CoreProcess.h | 10 +- src/lib/gui/core/ServerConnection.cpp | 18 +- src/lib/gui/core/ServerConnection.h | 3 + src/lib/gui/diagnostic.cpp | 67 +++++++ src/lib/gui/diagnostic.h | 26 +++ src/lib/gui/dotenv.cpp | 13 +- src/lib/gui/messages.cpp | 13 ++ src/lib/gui/messages.h | 2 + src/lib/gui/paths.h | 67 +++++++ src/lib/gui/proxy/QSettingsProxy.h | 2 +- src/lib/gui/tls/TlsCertificate.cpp | 43 ++--- src/lib/gui/tls/TlsCertificate.h | 1 - src/lib/gui/tls/TlsUtility.cpp | 17 +- src/lib/gui/tls/TlsUtility.h | 5 +- src/lib/license/ILicense.h | 32 ++++ src/lib/license/License.h | 7 +- .../net/InverseSockets/SecureServerSocket.cpp | 4 +- .../net/InverseSockets/SecureServerSocket.h | 2 +- .../unittests/gui/config/AppConfigTests.cpp | 6 +- .../gui/config/ConfigScopesTests.cpp | 39 ++-- .../unittests/gui/core/CoreProcessTests.cpp | 22 ++- .../gui/core/ServerConnectionTests.cpp | 10 +- .../gui/dialogs/SettingsDialogTests.cpp | 2 +- 37 files changed, 559 insertions(+), 228 deletions(-) create mode 100644 src/lib/gui/config/ServerConfigDialogState.h create mode 100644 src/lib/gui/diagnostic.cpp create mode 100644 src/lib/gui/diagnostic.h create mode 100644 src/lib/gui/paths.h create mode 100644 src/lib/license/ILicense.h diff --git a/.env.example b/.env.example index 99db1f1e6..94435f396 100644 --- a/.env.example +++ b/.env.example @@ -21,6 +21,9 @@ # Enable verbose logging in the GUI (always off by default) # SYNERGY_GUI_VERBOSE=true +# Reset all settings and delete all data on startup +# SYNERGY_RESET_ALL=true + # # Build # diff --git a/ChangeLog b/ChangeLog index 882ad9b0b..92b594290 100644 --- a/ChangeLog +++ b/ChangeLog @@ -77,6 +77,7 @@ Enhancements: - #7431 Improve handling of Qt-related warnings and errors - #7432 Only show close to tray reminder when not quitting the app - #7434 Show dark logo in dark mode and improve .env loader +- #7435 Add reset settings menu action and env var # 1.14.6 diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp index b8a7a4d80..c0ca769ea 100644 --- a/src/gui/src/MainWindow.cpp +++ b/src/gui/src/MainWindow.cpp @@ -21,12 +21,14 @@ #include "AboutDialog.h" #include "ActivationDialog.h" #include "ServerConfigDialog.h" +#include "common/constants.h" #include "gui/Logger.h" #include "gui/TrayIcon.h" #include "gui/VersionChecker.h" #include "gui/config/ConfigScopes.h" #include "gui/constants.h" #include "gui/core/CoreProcess.h" +#include "gui/diagnostic.h" #include "gui/dialogs/SettingsDialog.h" #include "gui/license/LicenseHandler.h" #include "gui/license/license_notices.h" @@ -76,13 +78,15 @@ MainWindow::MainWindow(ConfigScopes &configScopes, AppConfig &appConfig) : m_ConfigScopes(configScopes), m_AppConfig(appConfig), m_ServerConfig(appConfig, *this), - m_CoreProcess(appConfig, m_ServerConfig), - m_ServerConnection(this, appConfig, m_ServerConfig), + m_CoreProcess(appConfig, m_ServerConfig, m_LicenseHandler.license()), + m_ServerConnection( + this, appConfig, m_ServerConfig, m_ServerConfigDialogState), m_ClientConnection(this, appConfig), m_TlsUtility(appConfig, m_LicenseHandler.license()), m_WindowSaveTimer(this) { setupUi(this); + createMenuBar(); setupControls(); connectSlots(); @@ -90,15 +94,7 @@ MainWindow::MainWindow(ConfigScopes &configScopes, AppConfig &appConfig) emit created(); } -MainWindow::~MainWindow() { - try { - saveWindow(); - } catch (const std::exception &e) { - qFatal("failed to save window on main window close: %s", e.what()); - } - - m_CoreProcess.cleanup(); -} +MainWindow::~MainWindow() { m_CoreProcess.cleanup(); } void MainWindow::restoreWindow() { @@ -112,6 +108,11 @@ void MainWindow::restoreWindow() { if (windowPosition.has_value()) { qDebug("restoring main window position"); move(windowPosition.value()); + } else { + // center main window in middle of screen + const auto screen = QGuiApplication::primaryScreen(); + QRect screenGeometry = screen->geometry(); + move(screenGeometry.center() - rect().center()); } // give the window chance to restore its size and position before the window @@ -144,7 +145,6 @@ void MainWindow::setupControls() { m_pActionActivate->setVisible(false); } - createMenuBar(); secureSocket(false); updateLocalFingerprint(); @@ -273,7 +273,11 @@ void MainWindow::connectSlots() { [this]() { showAndActivate(); }); } -void MainWindow::onAppAboutToQuit() { m_ConfigScopes.save(); } +void MainWindow::onAppAboutToQuit() { + if (m_SaveOnExit) { + m_ConfigScopes.save(); + } +} void MainWindow::onCreated() { @@ -398,6 +402,19 @@ void MainWindow::on_m_pActionTestCriticalError_triggered() const { qCritical("test critical error"); } +void MainWindow::on_m_pActionClearSettings_triggered() { + if (!messages::showClearSettings(this)) { + qDebug("clear settings cancelled"); + return; + } + + m_CoreProcess.stop(); + + m_Quitting = true; + m_SaveOnExit = false; + diagnostic::clearSettings(m_ConfigScopes, true); +} + bool MainWindow::on_m_pActionSave_triggered() { QString fileName = QFileDialog::getSaveFileName(this, QString("Save configuration as...")); @@ -505,10 +522,12 @@ void MainWindow::on_m_pButtonConnectToClient_clicked() { void MainWindow::onWindowSaveTimerTimeout() { saveWindow(); } void MainWindow::onServerConnectionConfigureClient(const QString &clientName) { + m_ServerConfigDialogState.setVisible(true); ServerConfigDialog dialog(this, m_ServerConfig, m_AppConfig); if (dialog.addClient(clientName) && dialog.exec() == QDialog::Accepted) { m_CoreProcess.restart(); } + m_ServerConfigDialogState.setVisible(false); } ////////////////////////////////////////////////////////////////////////////// @@ -592,22 +611,21 @@ void MainWindow::createMenuBar() { m_pMenuFile->addAction(m_pActionSave); m_pMenuFile->addSeparator(); m_pMenuFile->addAction(m_pActionQuit); + m_pMenuEdit->addAction(m_pActionSettings); + m_pMenuWindow->addAction(m_pActionMinimize); m_pMenuWindow->addAction(m_pActionRestore); + m_pMenuHelp->addAction(m_pActionAbout); m_pMenuHelp->addAction(m_pActionHelp); + m_pMenuFile->addSeparator(); + m_pMenuHelp->addAction(m_pActionClearSettings); -#ifndef NDEBUG - // always enable test menu in debug mode. - const auto enableTestMenu = true; -#else - // only enable test menu in release build if env var is true. const auto enableTestMenu = strToTrue(qEnvironmentVariable("SYNERGY_TEST_MENU")); -#endif - if (enableTestMenu) { + if (enableTestMenu || kDebugBuild) { auto testMenu = new QMenu("Test", m_pMenuBar); m_pMenuBar->addMenu(testMenu); testMenu->addAction(m_pActionTestFatalError); diff --git a/src/gui/src/MainWindow.h b/src/gui/src/MainWindow.h index 6e396f710..7fb2426e2 100644 --- a/src/gui/src/MainWindow.h +++ b/src/gui/src/MainWindow.h @@ -32,6 +32,7 @@ #include "gui/VersionChecker.h" #include "gui/config/AppConfig.h" #include "gui/config/ConfigScopes.h" +#include "gui/config/ServerConfigDialogState.h" #include "gui/core/ClientConnection.h" #include "gui/core/CoreProcess.h" #include "gui/core/ServerConnection.h" @@ -130,6 +131,7 @@ private slots: void on_m_pActionStopCore_triggered(); void on_m_pActionTestFatalError_triggered() const; void on_m_pActionTestCriticalError_triggered() const; + void on_m_pActionClearSettings_triggered(); void on_m_pLineEditHostname_returnPressed(); void on_m_pLineEditClientIp_returnPressed(); void on_m_pLineEditHostname_textChanged(const QString &text); @@ -194,6 +196,8 @@ private: bool m_SaveWindow = false; LicenseHandler m_LicenseHandler; bool m_Quitting = false; + synergy::gui::config::ServerConfigDialogState m_ServerConfigDialogState; + bool m_SaveOnExit = true; synergy::gui::ConfigScopes &m_ConfigScopes; AppConfig &m_AppConfig; diff --git a/src/gui/src/MainWindowBase.ui b/src/gui/src/MainWindowBase.ui index 8083d5235..23d000550 100644 --- a/src/gui/src/MainWindowBase.ui +++ b/src/gui/src/MainWindowBase.ui @@ -667,6 +667,14 @@ QAction::TextHeuristicRole + + + Clear settings + + + QAction::TextHeuristicRole + + diff --git a/src/gui/src/main.cpp b/src/gui/src/main.cpp index 02159d720..370825c04 100644 --- a/src/gui/src/main.cpp +++ b/src/gui/src/main.cpp @@ -25,8 +25,10 @@ #include "gui/Logger.h" #include "gui/config/AppConfig.h" #include "gui/config/ConfigScopes.h" +#include "gui/diagnostic.h" #include "gui/dotenv.h" #include "gui/messages.h" +#include "gui/string_utils.h" #include #include @@ -34,6 +36,7 @@ #include #include #include +#include #if defined(Q_OS_MAC) #include @@ -53,6 +56,11 @@ QString getSystemSettingPath(); bool checkMacAssistiveDevices(); #endif +bool hasArg(const QString &arg, const QStringList &args) { + return std::ranges::any_of( + args, [&arg](const QString &a) { return a == arg; }); +} + int main(int argc, char *argv[]) { #if defined(Q_OS_MAC) @@ -96,6 +104,15 @@ int main(int argc, char *argv[]) { qRegisterMetaType("Edition"); ConfigScopes configScopes; + + // --no-reset + QStringList arguments = QCoreApplication::arguments(); + const auto noReset = hasArg("--no-reset", arguments); + const auto resetEnvVar = strToTrue(qEnvironmentVariable("SYNERGY_RESET_ALL")); + if (resetEnvVar && !noReset) { + diagnostic::clearSettings(configScopes, false); + } + AppConfig appConfig(configScopes); QObject::connect( diff --git a/src/lib/common/constants.h b/src/lib/common/constants.h index 0378cb693..1438e7138 100644 --- a/src/lib/common/constants.h +++ b/src/lib/common/constants.h @@ -30,3 +30,9 @@ const auto kVersionGitSha = GIT_SHA_SHORT; #else const auto kVersionGitSha = ""; #endif + +#ifndef NDEBUG +const auto kDebugBuild = true; +#else +const auto kDebugBuild = false; +#endif diff --git a/src/lib/gui/config/AppConfig.cpp b/src/lib/gui/config/AppConfig.cpp index ae7046407..869f329ab 100644 --- a/src/lib/gui/config/AppConfig.cpp +++ b/src/lib/gui/config/AppConfig.cpp @@ -100,7 +100,8 @@ AppConfig::AppConfig( synergy::gui::IConfigScopes &scopes, std::shared_ptr deps) : m_Scopes(scopes), m_pDeps(deps), - m_ScreenName(deps->hostname()) { + m_ScreenName(deps->hostname()), + m_TlsCertPath(deps->defaultTlsCertPath()) { determineScope(); recall(); } @@ -314,13 +315,6 @@ void AppConfig::recallElevateMode() { m_ElevateMode = static_cast(elevateMode.toInt()); } -QString AppConfig::defaultTlsCertPath() const { - QDir path(m_pDeps->profileDir()); - path = path.filePath("SSL"); - path = path.filePath("Synergy.pem"); - return path.absolutePath(); -} - QString AppConfig::settingName(Setting name) { auto index = static_cast(name); return m_SettingsName[index]; diff --git a/src/lib/gui/config/AppConfig.h b/src/lib/gui/config/AppConfig.h index 07503c17b..5577ec924 100644 --- a/src/lib/gui/config/AppConfig.h +++ b/src/lib/gui/config/AppConfig.h @@ -21,7 +21,7 @@ #include "ElevateMode.h" #include "IAppConfig.h" #include "IConfigScopes.h" -#include "gui/core/CoreTool.h" +#include "gui/paths.h" #include #include @@ -116,11 +116,10 @@ private: public: struct Deps { virtual ~Deps() = default; - virtual QString profileDir() const { return m_coreTool.getProfileDir(); } + virtual QString defaultTlsCertPath() const { + return synergy::gui::paths::defaultTlsCertPath(); + } virtual QString hostname() const { return QHostInfo::localHostName(); } - - private: - [[no_unique_address]] CoreTool m_coreTool; }; explicit AppConfig( @@ -293,9 +292,16 @@ private: */ QString defaultTlsCertPath() const; - synergy::gui::IConfigScopes &m_Scopes; - std::shared_ptr m_pDeps; - QString m_ScreenName; + static const char m_CoreServerName[]; + static const char m_CoreClientName[]; + static const char m_LogDir[]; + + /// @brief Contains the string values of the settings names that will be saved + static const char *const m_SettingsName[]; + + /// @brief Core config filename (not the Qt settings filename) + static const char m_ConfigFilename[]; + int m_Port = 24800; QString m_Interface = ""; int m_LogLevel = 0; @@ -324,7 +330,6 @@ private: bool m_EnableService = synergy::gui::kDefaultProcessMode == ProcessMode::kService; bool m_CloseToTray = true; - QString m_TlsCertPath = defaultTlsCertPath(); int m_TlsKeyLength = synergy::gui::kDefaultTlsKeyLength; std::optional m_MainWindowSize; std::optional m_MainWindowPosition; @@ -338,15 +343,10 @@ private: */ bool m_TlsChanged = false; - static const char m_CoreServerName[]; - static const char m_CoreClientName[]; - static const char m_LogDir[]; - - /// @brief Contains the string values of the settings names that will be saved - static const char *const m_SettingsName[]; - - /// @brief Core config filename (not the Qt settings filename) - static const char m_ConfigFilename[]; + synergy::gui::IConfigScopes &m_Scopes; + std::shared_ptr m_pDeps; + QString m_ScreenName; + QString m_TlsCertPath; signals: void tlsChanged(); diff --git a/src/lib/gui/config/ConfigScopes.cpp b/src/lib/gui/config/ConfigScopes.cpp index 90b3cde23..f352adf44 100644 --- a/src/lib/gui/config/ConfigScopes.cpp +++ b/src/lib/gui/config/ConfigScopes.cpp @@ -54,11 +54,18 @@ ConfigScopes::ConfigScopes(std::shared_ptr deps) m_pSystemSettingsProxy->loadSystem(); } +void ConfigScopes::clear() const { + m_pUserSettingsProxy->clear(); + m_pSystemSettingsProxy->clear(); +} + void ConfigScopes::signalReady() { emit ready(); } -void ConfigScopes::save() { - qDebug("emitting config saving signal"); - emit saving(); +void ConfigScopes::save(bool emitSaving) { + if (emitSaving) { + qDebug("emitting config saving signal"); + emit saving(); + } qDebug("writing config to filesystem"); m_pUserSettingsProxy->sync(); diff --git a/src/lib/gui/config/ConfigScopes.h b/src/lib/gui/config/ConfigScopes.h index 25307e1c8..ac8ad8758 100644 --- a/src/lib/gui/config/ConfigScopes.h +++ b/src/lib/gui/config/ConfigScopes.h @@ -42,8 +42,10 @@ public: explicit ConfigScopes(std::shared_ptr deps = std::make_shared()); ~ConfigScopes() override = default; + void clear() const; + void signalReady() override; - void save() override; + void save(bool emitSaving = true) override; bool scopeContains( const QString &name, Scope scope = Scope::Current) const override; bool isActiveScopeWritable() const override; diff --git a/src/lib/gui/config/IConfigScopes.h b/src/lib/gui/config/IConfigScopes.h index a6b9e409b..af56a5773 100644 --- a/src/lib/gui/config/IConfigScopes.h +++ b/src/lib/gui/config/IConfigScopes.h @@ -48,8 +48,10 @@ public: * @brief Signals to listeners to save and calls `sync` on underlying Qt * config. * + * @param emitSaving Whether to emit the saving signal which typically + * triggers listeners to write their current state to the config. */ - virtual void save() = 0; + virtual void save(bool emitSaving = true) = 0; /** * @brief Check a scope for a config value (default is current scope). diff --git a/src/lib/gui/config/ServerConfigDialogState.h b/src/lib/gui/config/ServerConfigDialogState.h new file mode 100644 index 000000000..39dfd57f0 --- /dev/null +++ b/src/lib/gui/config/ServerConfigDialogState.h @@ -0,0 +1,38 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2021 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +namespace synergy::gui::config { + +/** + * @brief Represents the state of the server config dialog. + * + * Future design consideration: Once moving the server config dialog to the GUI + * lib, we can probably just pass a reference to that rather than needing an + * object to track it's state. + */ +class ServerConfigDialogState { +public: + bool isVisible() const { return m_isVisible; } + void setVisible(bool isVisible) { m_isVisible = isVisible; } + +private: + bool m_isVisible = false; +}; + +} // namespace synergy::gui::config diff --git a/src/lib/gui/core/CoreProcess.cpp b/src/lib/gui/core/CoreProcess.cpp index 4b8f2a0fa..ef4f024d7 100644 --- a/src/lib/gui/core/CoreProcess.cpp +++ b/src/lib/gui/core/CoreProcess.cpp @@ -20,6 +20,8 @@ #include "constants.h" #include "gui/config/IAppConfig.h" #include "gui/core/CoreTool.h" +#include "gui/paths.h" +#include "tls/TlsUtility.h" #if defined(Q_OS_MAC) #include "OSXHelpers.h" @@ -37,7 +39,7 @@ namespace synergy::gui { const int kRetryDelay = 1000; -const auto kLastConfigFilename = "LastConfig.cfg"; +const auto kServerConfigFilename = "synergy-server.conf"; const auto kLineSplitRegex = QRegularExpression("\r|\n|\r\n"); // @@ -135,9 +137,10 @@ QString CoreProcess::Deps::getProfileRoot() const { CoreProcess::CoreProcess( IAppConfig &appConfig, IServerConfig &serverConfig, - std::shared_ptr deps) + const license::ILicense &license, std::shared_ptr deps) : m_appConfig(appConfig), m_serverConfig(serverConfig), + m_license(license), m_pDeps(deps) { connect( @@ -339,65 +342,19 @@ void CoreProcess::start(std::optional processModeOption) { setConnectionState(ConnectionState::Connecting); - QString app; - QStringList args; - - args << "-f" - << "--no-tray" - << "--debug" << m_appConfig.logLevelText(); - - args << "--name" << m_appConfig.screenName(); - if (processMode == ProcessMode::kDesktop) { m_pDeps->process().create(); - } else { - // tell client/server to talk to daemon through ipc. - args << "--ipc"; - -#if defined(Q_OS_WIN) - // tell the client/server to shut down when a ms windows desk - // is switched; this is because we may need to elevate or not - // based on which desk the user is in (login always needs - // elevation, where as default desk does not). - // Note that this is only enabled when synergy is set to elevate - // 'as needed' (e.g. on a UAC dialog popup) in order to prevent - // unnecessary restarts when synergy was started elevated or - // when it is not allowed to elevate. In these cases restarting - // the server is fruitless. - if (m_appConfig.elevateMode() == ElevateMode::kAutomatic) { - args << "--stop-on-desk-switch"; - } -#endif } -#ifndef Q_OS_LINUX + QString app; + QStringList args; + addGenericArgs(args, processMode); - if (m_serverConfig.enableDragAndDrop()) { - args << "--enable-drag-drop"; - } - -#endif - - if (m_appConfig.tlsEnabled()) { - args << "--enable-crypto"; - args << "--tls-cert" << m_appConfig.tlsCertPath(); - } - -#if defined(Q_OS_WIN) - // on windows, the profile directory changes depending on the user that - // launched the process (e.g. when launched with elevation). setting the - // profile dir on launch ensures it uses the same profile dir is used - // no matter how its relaunched. - args << "--profile-dir" << m_pDeps->getProfileRoot(); -#endif - - if (m_appConfig.preventSleep()) { - args << "--prevent-sleep"; - } - - if ((mode() == Mode::Client && !clientArgs(args, app)) || - (mode() == Mode::Server && !serverArgs(args, app))) { - qDebug("failed to get args for core process, aborting start"); + if (mode() == Mode::Server && !addServerArgs(args, app)) { + qDebug("failed to add server args for core process, aborting start"); + return; + } else if (mode() == Mode::Client && !addClientArgs(args, app)) { + qDebug("failed to add client args for core process, aborting start"); return; } @@ -483,7 +440,62 @@ void CoreProcess::cleanup() { m_pDeps->ipcClient().disconnectFromHost(); } -bool CoreProcess::serverArgs(QStringList &args, QString &app) { +bool CoreProcess::addGenericArgs( + QStringList &args, const ProcessMode processMode) const { + args << "-f" + << "--no-tray" + << "--debug" << m_appConfig.logLevelText(); + + args << "--name" << m_appConfig.screenName(); + + if (processMode != ProcessMode::kDesktop) { + // tell client/server to talk to daemon through ipc. + args << "--ipc"; + +#if defined(Q_OS_WIN) + // tell the client/server to shut down when a ms windows desk + // is switched; this is because we may need to elevate or not + // based on which desk the user is in (login always needs + // elevation, where as default desk does not). + // Note that this is only enabled when synergy is set to elevate + // 'as needed' (e.g. on a UAC dialog popup) in order to prevent + // unnecessary restarts when synergy was started elevated or + // when it is not allowed to elevate. In these cases restarting + // the server is fruitless. + if (m_appConfig.elevateMode() == ElevateMode::kAutomatic) { + args << "--stop-on-desk-switch"; + } +#endif + } + +#ifndef Q_OS_LINUX + + if (m_serverConfig.enableDragAndDrop()) { + args << "--enable-drag-drop"; + } + +#endif + + if (m_appConfig.tlsEnabled()) { + args << "--enable-crypto"; + } + +#if defined(Q_OS_WIN) + // on windows, the profile directory changes depending on the user that + // launched the process (e.g. when launched with elevation). setting the + // profile dir on launch ensures it uses the same profile dir is used + // no matter how its relaunched. + args << "--profile-dir" << m_pDeps->getProfileRoot(); +#endif + + if (m_appConfig.preventSleep()) { + args << "--prevent-sleep"; + } + + return true; +} + +bool CoreProcess::addServerArgs(QStringList &args, QString &app) { app = m_pDeps->appPath(m_appConfig.coreServerName()); if (!m_pDeps->fileExists(app)) { @@ -497,7 +509,7 @@ bool CoreProcess::serverArgs(QStringList &args, QString &app) { args << "--log" << m_appConfig.logFilename(); } - QString configFilename = persistConfig(); + QString configFilename = persistServerConfig(); if (configFilename.isEmpty()) { qFatal("config file name empty for server args"); return false; @@ -526,10 +538,22 @@ bool CoreProcess::serverArgs(QStringList &args, QString &app) { args << "--serial-key" << m_appConfig.serialKey(); } + // bizarrely, the tls cert path arg was being given to the core client. + // since it's not clear why (it is only needed for the server), this has now + // been moved to server args. + if (m_appConfig.tlsEnabled()) { + TlsUtility tlsUtility(m_appConfig, m_license); + if (!tlsUtility.persistCertificate()) { + qCritical("failed to persist tls certificate"); + return false; + } + args << "--tls-cert" << m_appConfig.tlsCertPath(); + } + return true; } -bool CoreProcess::clientArgs(QStringList &args, QString &app) { +bool CoreProcess::addClientArgs(QStringList &args, QString &app) { app = m_pDeps->appPath(m_appConfig.coreClientName()); if (!m_pDeps->fileExists(app)) { @@ -568,35 +592,25 @@ bool CoreProcess::clientArgs(QStringList &args, QString &app) { return true; } -QString CoreProcess::persistConfig() const { +QString CoreProcess::persistServerConfig() const { QString configFullPath; if (m_appConfig.useExternalConfig()) { return m_appConfig.configFile(); } - for (auto path : - {QStandardPaths::AppDataLocation, QStandardPaths::AppConfigLocation}) { - auto configDirPath = QStandardPaths::writableLocation(path); - if (!QDir().mkpath(configDirPath)) { - qWarning("failed to create config folder: %s", qPrintable(configDirPath)); - continue; - } + const auto configDir = paths::configDir(true); + const auto configDirPath = configDir.absolutePath(); - QFile configFile(configDirPath + "/" + kLastConfigFilename); - if (!configFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { - qWarning( - "failed to open core config file: %s", - qPrintable(configFile.fileName())); - continue; - } - - m_serverConfig.save(configFile); - configFile.close(); - return configFile.fileName(); + QFile configFile(configDirPath + "/" + kServerConfigFilename); + if (!configFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + qFatal( + "failed to open core config file for write: %s", + qPrintable(configFile.fileName())); } - qFatal("failed to persist config file"); - return ""; + m_serverConfig.save(configFile); + configFile.close(); + return configFile.fileName(); } QString CoreProcess::modeString() const { diff --git a/src/lib/gui/core/CoreProcess.h b/src/lib/gui/core/CoreProcess.h index 197f4a2f8..eb134d1f6 100644 --- a/src/lib/gui/core/CoreProcess.h +++ b/src/lib/gui/core/CoreProcess.h @@ -21,6 +21,7 @@ #include "gui/config/IServerConfig.h" #include "gui/ipc/QIpcClient.h" #include "gui/proxy/QProcessProxy.h" +#include "license/License.h" #include #include @@ -58,6 +59,7 @@ public: explicit CoreProcess( IAppConfig &appConfig, IServerConfig &serverConfig, + const license::ILicense &license, std::shared_ptr deps = std::make_shared()); void extracted(QString &app, QStringList &args); @@ -98,9 +100,10 @@ private: void startService(const QString &app, const QStringList &args); void stopDesktop() const; void stopService(); - bool serverArgs(QStringList &args, QString &app); - bool clientArgs(QStringList &args, QString &app); - QString persistConfig() const; + bool addGenericArgs(QStringList &args, const ProcessMode processMode) const; + bool addServerArgs(QStringList &args, QString &app); + bool addClientArgs(QStringList &args, QString &app); + QString persistServerConfig() const; QString modeString() const; QString processModeString() const; void setConnectionState(ConnectionState state); @@ -117,6 +120,7 @@ private: IAppConfig &m_appConfig; IServerConfig &m_serverConfig; + const license::ILicense &m_license; std::shared_ptr m_pDeps; QString m_address; ProcessState m_processState = ProcessState::Stopped; diff --git a/src/lib/gui/core/ServerConnection.cpp b/src/lib/gui/core/ServerConnection.cpp index 6591c8b76..40fc3ee97 100644 --- a/src/lib/gui/core/ServerConnection.cpp +++ b/src/lib/gui/core/ServerConnection.cpp @@ -18,6 +18,7 @@ #include "ServerConnection.h" #include "ServerMessage.h" +#include "gui/config/ServerConfigDialogState.h" #include "messages.h" #include @@ -40,10 +41,12 @@ messages::NewClientPromptResult ServerConnection::Deps::showNewClientPrompt( ServerConnection::ServerConnection( QWidget *parent, IAppConfig &appConfig, IServerConfig &serverConfig, + const config::ServerConfigDialogState &serverConfigDialogState, std::shared_ptr deps) : m_pParent(parent), m_appConfig(appConfig), m_serverConfig(serverConfig), + m_serverConfigDialogState(serverConfigDialogState), m_pDeps(deps) {} void ServerConnection::handleLogLine(const QString &logLine) { @@ -53,6 +56,16 @@ void ServerConnection::handleLogLine(const QString &logLine) { return; } + if (m_messageShowing) { + qDebug("new client message already shown, skipping for now"); + return; + } + + if (m_serverConfigDialogState.isVisible()) { + qDebug("server config dialog visible, skipping new client prompt"); + return; + } + if (m_appConfig.useExternalConfig()) { qDebug("external config enabled, skipping new client prompt"); return; @@ -75,11 +88,6 @@ void ServerConnection::handleNewClient(const QString &clientName) { m_receivedClients.append(clientName); - if (m_messageShowing) { - qDebug("new client message already shown, skipping"); - return; - } - if (m_serverConfig.isFull()) { qDebug( "server config full, skipping new client prompt for: %s", diff --git a/src/lib/gui/core/ServerConnection.h b/src/lib/gui/core/ServerConnection.h index 67fafe06a..e6899389d 100644 --- a/src/lib/gui/core/ServerConnection.h +++ b/src/lib/gui/core/ServerConnection.h @@ -22,6 +22,7 @@ #include "gui/config/IAppConfig.h" #include "gui/config/IServerConfig.h" +#include "gui/config/ServerConfigDialogState.h" #include "gui/messages.h" namespace synergy::gui { @@ -39,6 +40,7 @@ public: explicit ServerConnection( QWidget *parent, IAppConfig &appConfig, IServerConfig &serverConfig, + const config::ServerConfigDialogState &serverConfigDialogState, std::shared_ptr deps = std::make_shared()); void handleLogLine(const QString &logLine); @@ -52,6 +54,7 @@ private: QWidget *m_pParent; IAppConfig &m_appConfig; IServerConfig &m_serverConfig; + const config::ServerConfigDialogState &m_serverConfigDialogState; std::shared_ptr m_pDeps; QStringList m_receivedClients; bool m_messageShowing = false; diff --git a/src/lib/gui/diagnostic.cpp b/src/lib/gui/diagnostic.cpp new file mode 100644 index 000000000..4dfff7f66 --- /dev/null +++ b/src/lib/gui/diagnostic.cpp @@ -0,0 +1,67 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2024 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "diagnostic.h" + +#include "config/ConfigScopes.h" +#include "paths.h" + +#include +#include +#include + +namespace synergy::gui::diagnostic { + +void restart() { + QString program = QCoreApplication::applicationFilePath(); + QStringList arguments = QCoreApplication::arguments(); + + // prevent infinite reset loop when env var set. + arguments << "--no-reset"; + + qInfo("launching new process: %s", qPrintable(program)); + QProcess::startDetached(program, arguments); + + qDebug("exiting current process"); + QApplication::exit(); +} + +void clearSettings(ConfigScopes &scopes, bool enableRestart) { + qDebug("clearing settings"); + scopes.clear(); + + // save but do not emit saving signal which will prevent the current state of + // the app config and server configs from being applied. + scopes.save(false); + + auto configDir = paths::configDir(); + qDebug("removing config dir: %s", qPrintable(configDir.absolutePath())); + configDir.removeRecursively(); + + auto profileDir = paths::coreProfileDir(); + qDebug("removing profile dir: %s", qPrintable(profileDir.absolutePath())); + profileDir.removeRecursively(); + + if (enableRestart) { + qDebug("restarting"); + restart(); + } else { + qDebug("skipping restart"); + } +} + +} // namespace synergy::gui::diagnostic diff --git a/src/lib/gui/diagnostic.h b/src/lib/gui/diagnostic.h new file mode 100644 index 000000000..6ad338f4e --- /dev/null +++ b/src/lib/gui/diagnostic.h @@ -0,0 +1,26 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2024 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "gui/config/ConfigScopes.h" + +namespace synergy::gui::diagnostic { + +void clearSettings(ConfigScopes &scopes, bool enableRestart); + +} diff --git a/src/lib/gui/dotenv.cpp b/src/lib/gui/dotenv.cpp index c4d885ac8..e986509df 100644 --- a/src/lib/gui/dotenv.cpp +++ b/src/lib/gui/dotenv.cpp @@ -17,6 +17,8 @@ #include "dotenv.h" +#include "paths.h" + #include #include #include @@ -55,17 +57,10 @@ void dotenv(const QString &filename) { "no %s file in dir: %s", qPrintable(filename), qPrintable(fileInfo.absolutePath())); - // if nothing in current dir, then try the app data dir. + // if nothing in current dir, then try the config dir. // this makes it a bit easier for engineers in the field to have an easily // predictable location for the .env file. - QDir configDir( - QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation)); - - // HACK: since we have the org name set to the app name, the config dir is - // confusing. make this simple by using the org dir instead. - // use `filePath("..")` instead of `cdUp` to avoid the existence check. - QDir orgDir = configDir.filePath(".."); - orgDir = orgDir.absolutePath(); + const auto orgDir = paths::configDir(); filePath = orgDir.filePath(filename); if (!open(file, filePath)) { diff --git a/src/lib/gui/messages.cpp b/src/lib/gui/messages.cpp index 36e413a45..56ac6f28c 100644 --- a/src/lib/gui/messages.cpp +++ b/src/lib/gui/messages.cpp @@ -249,4 +249,17 @@ showNewClientPrompt(QWidget *parent, const QString &clientName) { } } +bool showClearSettings(QWidget *parent) { + QMessageBox message(parent); + message.addButton(QObject::tr("Cancel"), QMessageBox::RejectRole); + const auto clear = + message.addButton(QObject::tr("Clear settings"), QMessageBox::AcceptRole); + message.setText( + "

Are you sure you want to clear all settings and restart Synergy?

" + "

This action cannot be undone.

"); + message.exec(); + + return message.clickedButton() == clear; +} + } // namespace synergy::gui::messages diff --git a/src/lib/gui/messages.h b/src/lib/gui/messages.h index 9c20f3f11..18a82be2a 100644 --- a/src/lib/gui/messages.h +++ b/src/lib/gui/messages.h @@ -46,4 +46,6 @@ void showClientConnectError( NewClientPromptResult showNewClientPrompt(QWidget *parent, const QString &clientName); +bool showClearSettings(QWidget *parent); + } // namespace synergy::gui::messages diff --git a/src/lib/gui/paths.h b/src/lib/gui/paths.h new file mode 100644 index 000000000..796ba7eca --- /dev/null +++ b/src/lib/gui/paths.h @@ -0,0 +1,67 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2024 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "core/CoreTool.h" + +#include +#include +#include + +const auto kCertificateFilename = "Synergy.pem"; +const auto kSslDir = "SSL"; + +namespace synergy::gui::paths { + +/** + * @brief Gets the org config dir (parent of app config dir). + */ +inline QDir configDir(const bool persist = false) { + const QDir configDir( + QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation)); + + // HACK: since we have the org name set to the app name, the config dir is + // confusing. make this simple by using the org dir instead. + // use `filePath("..")` instead of `cdUp` to avoid the existence check. + const QDir orgDir = configDir.filePath(".."); + + if (persist) { + const auto orgDirPath = orgDir.absolutePath(); + if (!QDir().mkpath(orgDirPath)) { + qFatal("failed to persist config dir: %s", qPrintable(orgDirPath)); + } + } + + return orgDir.absolutePath(); +} + +/** + * @brief Uses the Core tool to get the profile dir. + */ +inline QDir coreProfileDir() { + CoreTool coreTool; + return QDir(coreTool.getProfileDir()); +} + +inline QString defaultTlsCertPath() { + const auto root = coreProfileDir(); + const auto sslDirPath = QDir(root.filePath(kSslDir)); + return sslDirPath.filePath(kCertificateFilename); +} + +} // namespace synergy::gui::paths diff --git a/src/lib/gui/proxy/QSettingsProxy.h b/src/lib/gui/proxy/QSettingsProxy.h index 51ff1ce9e..fb54bb1fe 100644 --- a/src/lib/gui/proxy/QSettingsProxy.h +++ b/src/lib/gui/proxy/QSettingsProxy.h @@ -29,7 +29,7 @@ public: virtual void loadUser(); virtual void loadSystem(); - + virtual void clear() { m_pSettings->clear(); } virtual void sync() { m_pSettings->sync(); } virtual int beginReadArray(const QString &prefix); virtual void beginWriteArray(const QString &prefix); diff --git a/src/lib/gui/tls/TlsCertificate.cpp b/src/lib/gui/tls/TlsCertificate.cpp index a9267c471..bcc89d0d4 100644 --- a/src/lib/gui/tls/TlsCertificate.cpp +++ b/src/lib/gui/tls/TlsCertificate.cpp @@ -18,18 +18,16 @@ #include "TlsCertificate.h" #include "TlsFingerprint.h" +#include "gui/paths.h" #include #include #include -#include static const char *const kCertificateKeyLength = "rsa:"; static const char *const kCertificateHashAlgorithm = "-sha256"; static const char *const kCertificateLifetime = "365"; static const char *const kCertificateSubjectInfo = "/CN=Synergy"; -static const char *const kCertificateFilename = "Synergy.pem"; -static const char *const kSslDir = "SSL"; #if defined(Q_OS_WIN) static const char *const kWinOpenSslDir = "OpenSSL"; @@ -39,6 +37,8 @@ static const char *const kConfigFile = "synergy.conf"; static const char *const kUnixOpenSslCommand = "openssl"; #endif +using namespace synergy::gui; + #if defined(Q_OS_WIN) namespace synergy::gui { @@ -87,12 +87,7 @@ using namespace synergy::gui; #endif -TlsCertificate::TlsCertificate(QObject *parent) : QObject(parent) { - m_profileDir = m_coreTool.getProfileDir(); - if (m_profileDir.isEmpty()) { - qCritical("empty profile directory result"); - } -} +TlsCertificate::TlsCertificate(QObject *parent) : QObject(parent) {} bool TlsCertificate::runTool(const QStringList &args) { QString program; @@ -157,21 +152,17 @@ bool TlsCertificate::runTool(const QStringList &args) { } bool TlsCertificate::generateCertificate(const QString &path, int keyLength) { - QString sslDirPath = - QString("%1%2%3").arg(m_profileDir).arg(QDir::separator()).arg(kSslDir); + qDebug("generating tls certificate: %s", qUtf8Printable(path)); - QString defaultPath = QString("%1%2%3") - .arg(sslDirPath) - .arg(QDir::separator()) - .arg(kCertificateFilename); + QFileInfo info(path); + QDir dir(info.absolutePath()); + if (!dir.exists() && !dir.mkpath(".")) { + qCritical("failed to create directory for tls certificate"); + return false; + } QString keySize = kCertificateKeyLength + QString::number(keyLength); - const QString pathToUse = - QDir::cleanPath(path.isEmpty() ? defaultPath : path); - - qDebug("generating tls certificate: %s", qUtf8Printable(pathToUse)); - QStringList arguments; // self signed certificate @@ -179,7 +170,7 @@ bool TlsCertificate::generateCertificate(const QString &path, int keyLength) { arguments.append("-x509"); arguments.append("-nodes"); - // valide duration + // valid duration arguments.append("-days"); arguments.append(kCertificateLifetime); @@ -193,22 +184,18 @@ bool TlsCertificate::generateCertificate(const QString &path, int keyLength) { arguments.append("-newkey"); arguments.append(keySize); - if (QDir sslDir(sslDirPath); !sslDir.exists()) { - sslDir.mkpath("."); - } - // key output filename arguments.append("-keyout"); - arguments.append(pathToUse); + arguments.append(path); // certificate output filename arguments.append("-out"); - arguments.append(pathToUse); + arguments.append(path); if (runTool(arguments)) { qDebug("tls certificate generated"); - return generateFingerprint(pathToUse); + return generateFingerprint(path); } else { qCritical("failed to generate tls certificate"); return false; diff --git a/src/lib/gui/tls/TlsCertificate.h b/src/lib/gui/tls/TlsCertificate.h index dbb5a858e..86823d5a0 100644 --- a/src/lib/gui/tls/TlsCertificate.h +++ b/src/lib/gui/tls/TlsCertificate.h @@ -35,7 +35,6 @@ private: bool generateFingerprint(const QString &certificateFilename); private: - QString m_profileDir; QString m_toolStdout; [[no_unique_address]] CoreTool m_coreTool; }; diff --git a/src/lib/gui/tls/TlsUtility.cpp b/src/lib/gui/tls/TlsUtility.cpp index a30526dfc..ebe20a423 100644 --- a/src/lib/gui/tls/TlsUtility.cpp +++ b/src/lib/gui/tls/TlsUtility.cpp @@ -20,12 +20,13 @@ #include "TlsCertificate.h" #include "constants.h" +#include #include namespace synergy::gui { TlsUtility::TlsUtility( - const IAppConfig &appConfig, const license::License &license) + const IAppConfig &appConfig, const license::ILicense &license) : m_appConfig(appConfig), m_license(license) {} @@ -48,10 +49,20 @@ bool TlsUtility::generateCertificate() { return false; } - auto path = m_appConfig.tlsCertPath(); auto length = m_appConfig.tlsKeyLength(); - return m_certificate.generateCertificate(path, length); + return m_certificate.generateCertificate(m_appConfig.tlsCertPath(), length); +} + +bool TlsUtility::persistCertificate() { + qDebug("persisting tls certificate"); + + if (QFile::exists(m_appConfig.tlsCertPath())) { + qDebug("tls certificate already exists"); + return true; + } + + return generateCertificate(); } } // namespace synergy::gui diff --git a/src/lib/gui/tls/TlsUtility.h b/src/lib/gui/tls/TlsUtility.h index 4c0ecb819..575039801 100644 --- a/src/lib/gui/tls/TlsUtility.h +++ b/src/lib/gui/tls/TlsUtility.h @@ -31,9 +31,10 @@ class TlsUtility : public QObject { public: explicit TlsUtility( - const IAppConfig &appConfig, const license::License &license); + const IAppConfig &appConfig, const license::ILicense &license); bool generateCertificate(); + bool persistCertificate(); /** * @brief Combines the availability and the enabled status of TLS. @@ -51,7 +52,7 @@ public: private: const IAppConfig &m_appConfig; - const license::License &m_license; + const license::ILicense &m_license; TlsCertificate m_certificate; }; diff --git a/src/lib/license/ILicense.h b/src/lib/license/ILicense.h new file mode 100644 index 000000000..f6d699e9b --- /dev/null +++ b/src/lib/license/ILicense.h @@ -0,0 +1,32 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2016 Symless Ltd. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +class Server; +class LicenseHandler; +class LicenseTests; + +namespace synergy::license { + +class ILicense { +public: + virtual ~ILicense() = default; + virtual bool isTlsAvailable() const = 0; +}; + +} // namespace synergy::license diff --git a/src/lib/license/License.h b/src/lib/license/License.h index 18576166b..83ce3f84d 100644 --- a/src/lib/license/License.h +++ b/src/lib/license/License.h @@ -17,6 +17,7 @@ #pragma once +#include "ILicense.h" #include "SerialKey.h" #include @@ -30,7 +31,7 @@ class LicenseTests; namespace synergy::license { -class License { +class License : public ILicense { friend class ::Server; friend class ::LicenseHandler; friend class ::LicenseTests; @@ -44,18 +45,20 @@ class License { public: explicit License(const SerialKey &serialKey); explicit License(const std::string &hexString); + ~License() override = default; friend bool operator==(License const &lhs, License const &rhs) { return lhs.m_serialKey == rhs.m_serialKey; } + bool isTlsAvailable() const override; + bool isValid() const { return m_serialKey.isValid; } bool isExpiringSoon() const; bool isExpired() const; bool isTrial() const; bool isSubscription() const; bool isTimeLimited() const; - bool isTlsAvailable() const; days daysLeft() const; Edition productEdition() const; std::string productName() const; diff --git a/src/lib/net/InverseSockets/SecureServerSocket.cpp b/src/lib/net/InverseSockets/SecureServerSocket.cpp index de2c46f92..49f393d58 100644 --- a/src/lib/net/InverseSockets/SecureServerSocket.cpp +++ b/src/lib/net/InverseSockets/SecureServerSocket.cpp @@ -40,7 +40,7 @@ IDataSocket *SecureServerSocket::accept() { socket->initSsl(true); setListeningJob(); - auto certificateFilename = getCertifcateFileName(); + auto certificateFilename = getCertificateFileName(); if (socket->loadCertificates(certificateFilename)) { socket->secureAccept(); } else { @@ -64,7 +64,7 @@ IDataSocket *SecureServerSocket::accept() { return dynamic_cast(socket); } -std::string SecureServerSocket::getCertifcateFileName() const { +std::string SecureServerSocket::getCertificateFileName() const { // if the tls cert option is set use that for the certificate file auto certificateFilename = ArgParser::argsBase().m_tlsCertFile; diff --git a/src/lib/net/InverseSockets/SecureServerSocket.h b/src/lib/net/InverseSockets/SecureServerSocket.h index 62ff32b97..bc150dc9c 100644 --- a/src/lib/net/InverseSockets/SecureServerSocket.h +++ b/src/lib/net/InverseSockets/SecureServerSocket.h @@ -27,5 +27,5 @@ public: IDataSocket *accept() override; private: - std::string getCertifcateFileName() const; + std::string getCertificateFileName() const; }; diff --git a/src/test/unittests/gui/config/AppConfigTests.cpp b/src/test/unittests/gui/config/AppConfigTests.cpp index bd5a242c7..3d335a636 100644 --- a/src/test/unittests/gui/config/AppConfigTests.cpp +++ b/src/test/unittests/gui/config/AppConfigTests.cpp @@ -48,12 +48,12 @@ public: MOCK_METHOD(bool, isActiveScopeWritable, (), (const, override)); MOCK_METHOD(const QSettingsProxy &, activeSettings, (), (const, override)); MOCK_METHOD(QSettingsProxy &, activeSettings, (), (override)); - MOCK_METHOD(void, save, (), (override)); + MOCK_METHOD(void, save, (bool), (override)); }; struct DepsMock : public AppConfig::Deps { DepsMock() { - ON_CALL(*this, profileDir()).WillByDefault(Return("stub")); + ON_CALL(*this, defaultTlsCertPath()).WillByDefault(Return("stub")); ON_CALL(*this, hostname()).WillByDefault(Return("stub")); } @@ -61,7 +61,7 @@ struct DepsMock : public AppConfig::Deps { return std::make_shared>(); } - MOCK_METHOD(QString, profileDir, (), (const, override)); + MOCK_METHOD(QString, defaultTlsCertPath, (), (const, override)); MOCK_METHOD(QString, hostname, (), (const, override)); }; diff --git a/src/test/unittests/gui/config/ConfigScopesTests.cpp b/src/test/unittests/gui/config/ConfigScopesTests.cpp index 8662c4066..87f4c5fc9 100644 --- a/src/test/unittests/gui/config/ConfigScopesTests.cpp +++ b/src/test/unittests/gui/config/ConfigScopesTests.cpp @@ -63,8 +63,7 @@ struct DepsMock : public ConfigScopes::Deps { } // namespace TEST(ConfigScopesTests, ctor_callsMakeUserSettings) { - std::shared_ptr> deps = - std::make_shared>(); + auto deps = std::make_shared>(); EXPECT_CALL(*deps, makeUserSettings()).Times(1); @@ -72,8 +71,7 @@ TEST(ConfigScopesTests, ctor_callsMakeUserSettings) { } TEST(ConfigScopesTests, ctor_callsMakeSystemSettings) { - std::shared_ptr> deps = - std::make_shared>(); + auto deps = std::make_shared>(); EXPECT_CALL(*deps, makeSystemSettings()).Times(1); @@ -81,8 +79,7 @@ TEST(ConfigScopesTests, ctor_callsMakeSystemSettings) { } TEST(ConfigScopesTests, save_syncsBothScopes) { - std::shared_ptr> deps = - std::make_shared>(); + auto deps = std::make_shared>(); ConfigScopes configScopes(deps); @@ -93,8 +90,7 @@ TEST(ConfigScopesTests, save_syncsBothScopes) { } TEST(ConfigScopesTests, activeSettings_returnsUserSettingsByDefault) { - std::shared_ptr> deps = - std::make_shared>(); + auto deps = std::make_shared>(); ConfigScopes configScopes(deps); @@ -102,8 +98,7 @@ TEST(ConfigScopesTests, activeSettings_returnsUserSettingsByDefault) { } TEST(ConfigScopesTests, activeSettings_returnsSystemSettingsWhenSystemScope) { - std::shared_ptr> deps = - std::make_shared>(); + auto deps = std::make_shared>(); ConfigScopes configScopes(deps); configScopes.setActiveScope(ConfigScopes::Scope::System); @@ -112,8 +107,7 @@ TEST(ConfigScopesTests, activeSettings_returnsSystemSettingsWhenSystemScope) { } TEST(ConfigScopesTests, setActiveScope_setsCurrentScope) { - std::shared_ptr> deps = - std::make_shared>(); + auto deps = std::make_shared>(); ConfigScopes configScopes(deps); @@ -125,8 +119,7 @@ TEST(ConfigScopesTests, setActiveScope_setsCurrentScope) { TEST( ConfigScopesTests, isActiveScopeWritable_returnsTrueWhenUserSettingsWritable) { - std::shared_ptr> deps = - std::make_shared>(); + auto deps = std::make_shared>(); ConfigScopes configScopes(deps); @@ -138,8 +131,7 @@ TEST( TEST( ConfigScopesTests, scopeContains_byDefault_returnsTrueWhenUserSettingsContainsKey) { - std::shared_ptr> deps = - std::make_shared>(); + auto deps = std::make_shared>(); ON_CALL(*deps->m_pUserSettings, contains(_)).WillByDefault(Return(true)); @@ -151,8 +143,7 @@ TEST( TEST( ConfigScopesTests, scopeContains_userScope_returnsTrueWhenUserSettingsContainsKey) { - std::shared_ptr> deps = - std::make_shared>(); + auto deps = std::make_shared>(); ON_CALL(*deps->m_pUserSettings, contains(_)).WillByDefault(Return(true)); @@ -164,8 +155,7 @@ TEST( TEST( ConfigScopesTests, scopeContains_systemScope_returnsTrueWhenSystemSettingsContainsKey) { - std::shared_ptr> deps = - std::make_shared>(); + auto deps = std::make_shared>(); ON_CALL(*deps->m_pSystemSettings, contains(_)).WillByDefault(Return(true)); @@ -175,8 +165,7 @@ TEST( } TEST(ConfigScopesTests, activeFilePath_returnsUserSettingsFileNameByDefault) { - std::shared_ptr> deps = - std::make_shared>(); + auto deps = std::make_shared>(); ON_CALL(*deps->m_pUserSettings, fileName()).WillByDefault(Return("test")); ConfigScopes configScopes(deps); @@ -185,8 +174,7 @@ TEST(ConfigScopesTests, activeFilePath_returnsUserSettingsFileNameByDefault) { } TEST(ConfigScopesTests, getFromScope_byDefault_returnsValueFromActiveSettings) { - std::shared_ptr> deps = - std::make_shared>(); + auto deps = std::make_shared>(); ON_CALL(*deps->m_pUserSettings, value(_, _)).WillByDefault(Return("test")); ConfigScopes configScopes(deps); @@ -195,8 +183,7 @@ TEST(ConfigScopesTests, getFromScope_byDefault_returnsValueFromActiveSettings) { } TEST(ConfigScopesTests, setInScope_byDefault_setsValueInActiveSettings) { - std::shared_ptr> deps = - std::make_shared>(); + auto deps = std::make_shared>(); ConfigScopes configScopes(deps); diff --git a/src/test/unittests/gui/core/CoreProcessTests.cpp b/src/test/unittests/gui/core/CoreProcessTests.cpp index 610e921fb..3209497c6 100644 --- a/src/test/unittests/gui/core/CoreProcessTests.cpp +++ b/src/test/unittests/gui/core/CoreProcessTests.cpp @@ -19,6 +19,7 @@ #include "gui/core/CoreProcess.h" #include "gui/ipc/IQIpcClient.h" #include "gui/proxy/QProcessProxy.h" +#include "license/ILicense.h" #include "shared/gui/mocks/AppConfigMock.h" #include "shared/gui/mocks/ServerConfigMock.h" @@ -27,10 +28,8 @@ #include using namespace synergy::gui; -using ::testing::_; -using ::testing::NiceMock; -using ::testing::Return; -using ::testing::ReturnRef; +using namespace synergy::license; +using namespace testing; namespace { @@ -92,12 +91,23 @@ public: NiceMock m_ipcClient; }; -class CoreProcessTests : public ::testing::Test { +class LicenseMock : public ILicense { public: - CoreProcessTests() : m_coreProcess(m_appConfig, m_serverConfig, m_pDeps) {} + LicenseMock() { + ON_CALL(*this, isTlsAvailable()).WillByDefault(Return(true)); + } + + MOCK_METHOD(bool, isTlsAvailable, (), (const, override)); +}; + +class CoreProcessTests : public Test { +public: + CoreProcessTests() + : m_coreProcess(m_appConfig, m_serverConfig, m_license, m_pDeps) {} NiceMock m_appConfig; NiceMock m_serverConfig; + NiceMock m_license; std::shared_ptr> m_pDeps = std::make_shared>(); CoreProcess m_coreProcess; diff --git a/src/test/unittests/gui/core/ServerConnectionTests.cpp b/src/test/unittests/gui/core/ServerConnectionTests.cpp index 5a6d19569..1442afb4c 100644 --- a/src/test/unittests/gui/core/ServerConnectionTests.cpp +++ b/src/test/unittests/gui/core/ServerConnectionTests.cpp @@ -15,6 +15,7 @@ * along with this program. If not, see . */ +#include "gui/config/ServerConfigDialogState.h" #include "gui/core/ServerConnection.h" #include "shared/gui/mocks/AppConfigMock.h" @@ -45,11 +46,12 @@ public: std::shared_ptr m_pDeps = std::make_shared>(); NiceMock m_appConfig; NiceMock m_serverConfig; + config::ServerConfigDialogState m_serverConfigDialogState; }; TEST_F(ServerConnectionTests, handleLogLine_newClient_shouldShowPrompt) { ServerConnection serverConnection( - nullptr, m_appConfig, m_serverConfig, m_pDeps); + nullptr, m_appConfig, m_serverConfig, m_serverConfigDialogState, m_pDeps); QString clientName = "test client"; EXPECT_CALL(*m_pDeps, showNewClientPrompt(_, clientName)); @@ -59,7 +61,7 @@ TEST_F(ServerConnectionTests, handleLogLine_newClient_shouldShowPrompt) { TEST_F(ServerConnectionTests, handleLogLine_ignoredClient_shouldNotShowPrompt) { ServerConnection serverConnection( - nullptr, m_appConfig, m_serverConfig, m_pDeps); + nullptr, m_appConfig, m_serverConfig, m_serverConfigDialogState, m_pDeps); ON_CALL(*m_pDeps, showNewClientPrompt(_, _)) .WillByDefault(testing::Return(messages::NewClientPromptResult::Ignore)); serverConnection.handleLogLine(R"(unrecognised client name "stub")"); @@ -72,7 +74,7 @@ TEST_F(ServerConnectionTests, handleLogLine_ignoredClient_shouldNotShowPrompt) { TEST_F( ServerConnectionTests, handleLogLine_serverConfigFull_shouldNotShowPrompt) { ServerConnection serverConnection( - nullptr, m_appConfig, m_serverConfig, m_pDeps); + nullptr, m_appConfig, m_serverConfig, m_serverConfigDialogState, m_pDeps); ON_CALL(m_serverConfig, isFull()).WillByDefault(testing::Return(true)); EXPECT_CALL(*m_pDeps, showNewClientPrompt(_, _)).Times(0); @@ -82,7 +84,7 @@ TEST_F( TEST_F(ServerConnectionTests, handleLogLine_screenExists_shouldNotShowPrompt) { ServerConnection serverConnection( - nullptr, m_appConfig, m_serverConfig, m_pDeps); + nullptr, m_appConfig, m_serverConfig, m_serverConfigDialogState, m_pDeps); ON_CALL(m_serverConfig, screenExists(_)).WillByDefault(testing::Return(true)); EXPECT_CALL(*m_pDeps, showNewClientPrompt(_, _)).Times(0); diff --git a/src/test/unittests/gui/dialogs/SettingsDialogTests.cpp b/src/test/unittests/gui/dialogs/SettingsDialogTests.cpp index ce08d2601..60eab9868 100644 --- a/src/test/unittests/gui/dialogs/SettingsDialogTests.cpp +++ b/src/test/unittests/gui/dialogs/SettingsDialogTests.cpp @@ -39,7 +39,7 @@ TEST(SettingsDialogTests, ctor_getsScreenName) { serialKey.isValid = true; License license(serialKey); auto cpDeps = std::make_shared(); - CoreProcess coreProcess(appConfig, serverConfig, cpDeps); + CoreProcess coreProcess(appConfig, serverConfig, license, cpDeps); EXPECT_CALL(appConfig, screenName()).Times(1);