Improve UI design and reduce over-use of #ifdef (#7413)

* Rename `LicenseManager` to `License`

* Rename `LicenseManager` to `License`

* Move License class to gui lib

* Rename license related classes

* Refactor serial key parsing

* Don't fail fast on containers

* Move licensed product name from config to code

* Fixed formatting

* Update code coverage generator and fixed args

* WIP: Converting license to chrono

* WIP: Fixed compile errors, tests failing

* Fixed all serial key and license tests

* Disable verbose logging

* Add missing </p>

* Add missing include

* Revert code coverage config

* Handle parse errors

* Move more classes into the new gui lib and improve license/serial object ownership

* WIP: Fixing signal/slots in MainWindow

* Fixed slot for about to quit

* Rename manual slots to solve auto-connection warnings

* Fixed logging issue

* By default, don't close to tray

* Add .env support and furthe refactor license code, also fixed some copyright dates

* Remove test code

* Fixed memory error in .env parser and refactor more licensing display code

* Fixed color inconsistencies

* Fixed link colors and made log view expand

* Disable server components rather than hiding

* Reset years of blind UI layout fiddling

* Fixed clean Qt task

* Only show notice when time limited

* Fixed main window layout

* Show connected clients

* Set 15 spacing

* Auto connect on start

* More intentional screen size

* Fixed tests related to license

* Tests for expiry notifications

* Reorg tests and remove death test

* Update gtest

* Tests for dotenv parser

* Test command process

* What the heck is that doing there?

* Merge constants headers

* Fixed magic includes

* Remove helper function

* Remove comment

* Remove extern decl

* Update ChangeLog
This commit is contained in:
Nick Bolton 2024-07-26 23:53:52 +01:00 committed by GitHub
parent ce3f8869e7
commit 9315b089c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
143 changed files with 3732 additions and 3680 deletions

View file

@ -2,6 +2,16 @@
# Usage: Copy this .env.example file to .env
#
#
# App
#
# Serial key value to pre-fill the activation dialog
# SYNERGY_TEST_SERIAL_KEY="DEADBEEF"
# Version checker URL to use (useful for testing)
# SYNERGY_VERSION_URL="http://localhost:8787?version=v1"
#
# Build
#

View file

@ -21,6 +21,9 @@ jobs:
timeout-minutes: 10
strategy:
# Build all images even if some fail.
fail-fast: false
matrix:
os:
- name: debian-12-amd64

4
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,4 @@
{
"sonarlint.pathToCompileCommands": "${workspaceFolder}/build/compile_commands.json",
"gcovViewer.buildDirectories": ["${workspaceFolder}/build/src/lib"]
}

58
.vscode/tasks.json vendored
View file

@ -10,6 +10,13 @@
"group": {
"kind": "build",
"isDefault": true
},
"problemMatcher": {
"base": "$gcc",
"fileLocation": ["absolute"]
},
"presentation": {
"revealProblems": "onProblem"
}
},
{
@ -20,6 +27,38 @@
"preset": "${command:cmake.activeBuildPresetName}",
"group": "build"
},
{
"label": "clean-gcda",
"type": "shell",
"command": "find . -name '*.gcda' -delete",
"windows": {
"command": "$null"
},
"presentation": {
"reveal": "silent"
}
},
{
"label": "clean-qt",
"type": "shell",
"command": "rm -r build/src/gui build/src/lib/gui",
"windows": {
"command": "remove-item -recurse build/src/gui,build/src/lib/gui"
}
},
{
"label": "clean-config",
"type": "shell",
"linux": {
"command": "rm -r ~/.config/Synergy/Synergy.conf"
},
"windows": {
"command": "remove-item -recurse $env:APPDATA\\Synergy\\Synergy"
},
"osx": {
"command": "rm -r ~/Library/Application\\ Support/Synergy/Synergy"
}
},
{
"label": "tests",
"dependsOn": ["integtests", "unittests"],
@ -68,25 +107,6 @@
"type": "shell",
"command": "python scripts/daemon.py --stop"
},
{
"label": "clean-gcda",
"type": "shell",
"command": "find . -name '*.gcda' -delete",
"windows": {
"command": "$null"
},
"presentation": {
"reveal": "silent"
}
},
{
"label": "clean-qt",
"type": "shell",
"command": "rm -r build/src/gui",
"windows": {
"command": "remove-item -recurse build/src/gui"
}
},
{
"label": "unittests (current)",
"type": "shell",

View file

@ -59,6 +59,7 @@ Enhancements:
- #7406 Migrate scripts from `requirements.txt` to `pyproject.toml`
- #7407 Implement safer memory use, improve dev env, fixed GUI bugs
- #7412 Reduce GUI compile time by building a GUI library
- #7413 Improve UI design and reduce over-use of `#ifdef`
# 1.14.6

View file

@ -53,6 +53,9 @@ macro(configure_definitions)
if(NOT "$ENV{SYNERGY_PRODUCT_NAME}" STREQUAL "")
set(PRODUCT_NAME $ENV{SYNERGY_PRODUCT_NAME})
endif()
endif()
if(PRODUCT_NAME)
message(STATUS "Product name: ${PRODUCT_NAME}")
add_definitions(-DSYNERGY_PRODUCT_NAME="${PRODUCT_NAME}")
endif()

@ -1 +1 @@
Subproject commit 18f8200e3079b0e54fa00cb7ac55d4c39dcf6da6
Subproject commit e39786088138f2749d64e9e90e0f9902daa77c40

View file

@ -36,7 +36,8 @@ target_link_libraries(
net
platform
synlib
shared
global
license
${libs})
post_config()

View file

@ -28,18 +28,12 @@ file(
src/validators/*
src/widgets/*)
file(GLOB GUI_UI_FILES src/*.ui)
file(GLOB ACTIVATION_FILES src/*Activation* src/*License*)
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
file(GLOB GUI_MAC_SOURCE_FILES src/*.mm)
list(APPEND GUI_SOURCE_FILES ${GUI_MAC_SOURCE_FILES})
endif()
if(NOT ENABLE_LICENSING)
list(REMOVE_ITEM GUI_SOURCE_FILES ${ACTIVATION_FILES})
list(REMOVE_ITEM GUI_UI_FILES ${ACTIVATION_FILES})
endif()
if(WIN32)
set(GUI_RC_FILES res/win/Synergy.rc ${CMAKE_BINARY_DIR}/src/version.rc)
endif()
@ -56,8 +50,9 @@ include_directories(./src)
target_link_libraries(
${target}
shared
gui
global
license
Qt6::Core
Qt6::Widgets
Qt6::Network)

View file

@ -18,21 +18,27 @@
#include "AboutDialog.h"
#include <QDateTime>
#if defined(Q_OS_MAC)
#include "OSXHelpers.h"
#endif
#ifdef GIT_SHA_SHORT
const QString kVersionAppend = GIT_SHA_SHORT;
#else
const QString kVersionAppend;
#endif
AboutDialog::AboutDialog(MainWindow *parent, const AppConfig &config)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
Ui::AboutDialogBase() {
setupUi(this);
m_versionChecker.setApp(parent->appPath(config.coreClientName()));
QString version = SYNERGY_VERSION;
#ifdef GIT_SHA_SHORT
version += " (" GIT_SHA_SHORT ")";
#endif
QString version(SYNERGY_VERSION);
if (!kVersionAppend.isEmpty()) {
version.append(QString(" (%1)").arg(kVersionAppend));
}
m_pLabelSynergyVersion->setText(version);
@ -84,7 +90,7 @@ QString AboutDialog::getImportantDevelopers() const {
// Symless employees
"Kyle Bloom, Daun Chung, Serhii Hadzhylov, "
"Oleksandr Lysytsia, Olena Kutytska, Francisco Magalhães.");
"Oleksandr Lysytsia, Olena Kutytska.");
}
QString AboutDialog::getCopyright() const {

View file

@ -16,45 +16,64 @@
*/
#include "ActivationDialog.h"
#include "gui/license_notices.h"
#include "ui_ActivationDialog.h"
#include "AppConfig.h"
#include "CancelActivationDialog.h"
#include "LicenseManager.h"
#include "MainWindow.h"
#include "shared/EditionType.h"
#include "ui_ActivationDialog.h"
#include "gui/LicenseHandler.h"
#include "gui/constants.h"
#include "gui/license_notices.h"
#include "license/ProductEdition.h"
#include "license/parse_serial_key.h"
#include <QApplication>
#include <QMessageBox>
#include <QThread>
using namespace synergy::gui;
using namespace synergy::license;
ActivationDialog::ActivationDialog(
QWidget *parent, AppConfig &appConfig, LicenseManager &licenseManager)
QWidget *parent, AppConfig &appConfig, LicenseHandler &licenseHandler)
: QDialog(parent),
ui(new Ui::ActivationDialog),
m_appConfig(&appConfig),
m_LicenseManager(&licenseManager) {
ui->setupUi(this);
m_ui(new Ui::ActivationDialog),
m_pAppConfig(&appConfig),
m_licenseHandler(licenseHandler) {
m_ui->setupUi(this);
refreshSerialKey();
time_t currentTime = ::time(0);
if (!m_LicenseManager->serialKey().isExpired(currentTime)) {
ui->m_trialWidget->hide();
if (!m_licenseHandler.license().isExpired()) {
m_ui->m_widgetNotice->hide();
}
const QString envSerialKey = ::getenv("SYNERGY_TEST_SERIAL_KEY");
if (!envSerialKey.isEmpty()) {
qDebug() << "using env test serial key:" << envSerialKey;
m_ui->m_pTextEditSerialKey->setText(envSerialKey);
}
}
void ActivationDialog::refreshSerialKey() {
ui->m_pTextEditSerialKey->setText(m_appConfig->serialKey());
ui->m_pTextEditSerialKey->setFocus();
ui->m_pTextEditSerialKey->moveCursor(QTextCursor::End);
ui->m_trialLabel->setText(
tr(m_LicenseManager->getLicenseNotice().toStdString().c_str()));
m_ui->m_pTextEditSerialKey->setText(m_pAppConfig->serialKey());
m_ui->m_pTextEditSerialKey->setFocus();
m_ui->m_pTextEditSerialKey->moveCursor(QTextCursor::End);
const auto &license = m_licenseHandler.license();
if (license.isTimeLimited()) {
m_ui->m_labelNotice->setText(licenseNotice(license));
}
}
ActivationDialog::~ActivationDialog() { delete ui; }
ActivationDialog::~ActivationDialog() { delete m_ui; }
void ActivationDialog::reject() {
// don't show the cancel confirmation dialog if they've already registered,
// since it's not revent to customers who are changing their serial key.
if (m_LicenseManager->activeEdition() != kUnregistered) {
if (m_licenseHandler.productEdition() != Edition::kUnregistered) {
QDialog::reject();
return;
}
@ -67,56 +86,105 @@ void ActivationDialog::reject() {
}
void ActivationDialog::accept() {
QMessageBox message;
m_appConfig->setActivationHasRun(true);
using Result = LicenseHandler::ChangeSerialKeyResult;
auto serialKey = m_ui->m_pTextEditSerialKey->toPlainText();
try {
SerialKey serialKey(
ui->m_pTextEditSerialKey->toPlainText().trimmed().toStdString());
m_LicenseManager->setSerialKey(serialKey);
} catch (std::exception &e) {
message.critical(
this, "Activation failed",
tr("An error occurred while trying to activate Synergy. "
"<a href=\"https://symless.com/synergy/contact-support?source=gui\" "
"style=\"text-decoration: none; color: #4285F4;\">"
"Please contact the helpdesk</a>, and provide the following "
"information:"
"<br><br>%1")
.arg(e.what()));
refreshSerialKey();
if (serialKey.isEmpty()) {
QMessageBox::information(this, "Activation", "Please enter a serial key.");
return;
}
m_LicenseManager->notifyActivation("serial:" + m_appConfig->serialKey());
Edition edition = m_LicenseManager->activeEdition();
time_t daysLeft = m_LicenseManager->serialKey().daysLeft(::time(0));
if (edition != kUnregistered) {
QString thanksMessage = tr("Thanks for trying %1! %5\n\n%2 day%3 of "
"your trial remain%4")
.arg(m_LicenseManager->getEditionName(edition))
.arg(daysLeft)
.arg((daysLeft == 1) ? "" : "s")
.arg((daysLeft == 1) ? "s" : "");
if (m_appConfig->cryptoAvailable()) {
m_appConfig->generateCertificate();
thanksMessage =
thanksMessage.arg("If you're using SSL, "
"remember to activate all of your devices.");
} else {
thanksMessage = thanksMessage.arg("");
try {
const auto result = m_licenseHandler.changeSerialKey(serialKey);
if (result != Result::kSuccess) {
showResultDialog(result);
return;
}
} catch (const SerialKeyParseError &e) {
showErrorDialog(e.what());
return;
}
if (m_LicenseManager->serialKey().isTrial()) {
message.information(this, "Thanks!", thanksMessage);
} else {
message.information(
this, "Activated!",
tr("Thanks for activating %1!")
.arg(m_LicenseManager->getEditionName(edition)));
showSuccessDialog();
m_pAppConfig->setActivationHasRun(true);
QDialog::accept();
}
void ActivationDialog::showResultDialog(
LicenseHandler::ChangeSerialKeyResult result) {
const QString title = "Activation result";
switch (result) {
using enum LicenseHandler::ChangeSerialKeyResult;
case kUnchanged:
QMessageBox::information(
this, title,
"Heads up, the serial key you entered was the same as last time.");
break;
case kInvalid:
QMessageBox::critical(
this, title,
QString("Invalid serial key. "
R"(Please <a href="%1" style="%2">contact us</a> for help.)")
.arg(kUrlContact)
.arg(kLinkStyleSecondary));
break;
case kExpired:
QMessageBox::warning(
this, title,
QString("Sorry, that serial key has expired. "
R"(Please <a href="%1" style="%1">renew</a> your license.)")
.arg(kUrlPurchase)
.arg(kLinkStyleSecondary));
break;
default:
qFatal("unexpected change serial key result: %d", static_cast<int>(result));
}
}
void ActivationDialog::showSuccessDialog() {
const auto &license = m_licenseHandler.license();
QString title = "Activation successful";
QString message = tr("<p>Thanks for activating %1.</p>")
.arg(m_licenseHandler.productName());
TlsUtility tls(*m_pAppConfig, license);
if (tls.isAvailableAndEnabled()) {
message +=
"<p>To ensure that TLS encryption works correctly, "
"please activate all of your computers with the same serial key.</p>";
}
if (license.isTimeLimited()) {
auto daysLeft = license.daysLeft().count();
if (license.isTrial()) {
title = "Trial started";
message += QString("Your trial will expire in %1 %2.")
.arg(daysLeft)
.arg((daysLeft == 1) ? "day" : "days");
} else if (license.isSubscription()) {
message += QString("Your license will expire in %1 %2.")
.arg(daysLeft)
.arg((daysLeft == 1) ? "day" : "days");
}
}
QDialog::accept();
QMessageBox::information(this, title, message);
}
void ActivationDialog::showErrorDialog(const QString &message) {
QString fullMessage =
QString("<p>There was a problem activating Synergy.</p>"
R"(<p>Please <a href="%1" style="%2">contact us</a> )"
"and provide the following information:</p>"
"%3")
.arg(kUrlContact)
.arg(kLinkStyleSecondary)
.arg(message);
QMessageBox::critical(this, "Activation failed", fullMessage);
}

View file

@ -17,7 +17,8 @@
#pragma once
#include <LicenseManager.h>
#include "gui/LicenseHandler.h"
#include <QDialog>
namespace Ui {
@ -31,8 +32,14 @@ class ActivationDialog : public QDialog {
public:
ActivationDialog(
QWidget *parent, AppConfig &appConfig, LicenseManager &licenseManager);
~ActivationDialog();
QWidget *parent, AppConfig &appConfig, LicenseHandler &licenseHandler);
~ActivationDialog() override;
class ActivationMessageError : public std::runtime_error {
public:
ActivationMessageError()
: std::runtime_error("could not show activation message") {}
};
public slots:
void reject();
@ -42,7 +49,11 @@ protected:
void refreshSerialKey();
private:
Ui::ActivationDialog *ui;
AppConfig *m_appConfig;
LicenseManager *m_LicenseManager;
void showResultDialog(LicenseHandler::ChangeSerialKeyResult result);
void showSuccessDialog();
void showErrorDialog(const QString &message);
Ui::ActivationDialog *m_ui;
AppConfig *m_pAppConfig;
LicenseHandler &m_licenseHandler;
};

View file

@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>477</width>
<width>541</width>
<height>241</height>
</rect>
</property>
@ -29,7 +29,7 @@
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Your serial key is on your &lt;a href=&quot;https://symless.com/synergy/account?source=gui&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#4285f4;&quot;&gt;account&lt;/span&gt;&lt;/a&gt; page. Don't have a license? &lt;a href=&quot;https://symless.com/synergy/purchase?source=gui&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#007af4;&quot;&gt;Purchase Synergy&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;p&gt;Your serial key is on your &lt;a href=&quot;https://symless.com/synergy/account?source=gui&quot; style=&quot;color:#4285f4;&quot;&gt;account&lt;/span&gt;&lt;/a&gt; page. Don't have a license? &lt;a href=&quot;https://symless.com/synergy/purchase?source=gui&quot; style=&quot;color:#4285f4;&quot;&gt;Purchase Synergy&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
@ -51,7 +51,7 @@ p, li { white-space: pre-wrap; }
hr { height: 1px; border-width: 0; }
li.unchecked::marker { content: &quot;\2610&quot;; }
li.checked::marker { content: &quot;\2612&quot;; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Cantarell'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans'; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="acceptRichText">
@ -60,7 +60,7 @@ li.checked::marker { content: &quot;\2612&quot;; }
</widget>
</item>
<item>
<widget class="QWidget" name="m_trialWidget" native="true">
<widget class="QWidget" name="m_widgetNotice" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="leftMargin">
<number>2</number>
@ -75,18 +75,16 @@ li.checked::marker { content: &quot;\2612&quot;; }
<number>8</number>
</property>
<item>
<widget class="QLabel" name="m_trialLabel">
<widget class="QLabel" name="m_labelNotice">
<property name="styleSheet">
<string notr="true">font-size: 13px;
font-weight: 700;
padding: 3px 5px;
<string notr="true">padding: 3px 5px;
border-radius: 3px;
background-color: #EC4C47;
background-color: #3B67D3;
color: #ffffff;
top: 3px;</string>
</property>
<property name="text">
<string/>
<string>m_labelNotice</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
@ -96,7 +94,7 @@ top: 3px;</string>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -112,10 +110,10 @@ top: 3px;</string>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
</property>
</widget>
</item>

View file

@ -19,14 +19,13 @@
#include "AppConfig.h"
#include "Config.h"
#include "SslCertificate.h"
#include "gui/constants.h"
#include <QApplication>
#include <QMessageBox>
#include <QPushButton>
#include <QtCore>
#include <QtNetwork>
#include <QtWidgets/QMessageBox>
#include <qapplication.h>
using synergy::gui::Config;
@ -46,6 +45,7 @@ const char AppConfig::m_LogDir[] = "/var/log/";
const char AppConfig::m_ConfigFilename[] = "synergy.conf";
#endif
// TODO: instead, use key value pair table, which would be less fragile.
const char *const AppConfig::m_SettingsName[] = {
"screenName",
"port",
@ -57,17 +57,17 @@ const char *const AppConfig::m_SettingsName[] = {
"startedBefore",
"elevateMode",
"elevateModeEnum",
"edition",
"cryptoEnabled",
"", // 10 = edition, obsolete (using serial key instead)
"cryptoEnabled", // kTlsEnabled (retain legacy string value)
"autoHide",
"serialKey",
"lastVersion",
"lastExpiringWarningTime",
"", // 15 = lastExpiringWarningTime, obsolete
"activationHasRun",
"minimizeToTray",
"ActivateEmail",
"", // 18 = ActivateEmail, obsolete
"loadFromSystemScope",
"groupServerChecked",
"groupServerChecked", // kServerGroupChecked
"useExternalConfig",
"configFile",
"useInternalConfig",
@ -78,23 +78,20 @@ const char *const AppConfig::m_SettingsName[] = {
"preventSleep",
"languageSync",
"invertScrollDirection",
"guid",
"licenseRegistryUrl",
"", // 31 = guid, obsolete
"", // 32 = licenseRegistryUrl, obsolete
"licenseNextCheck",
"initiateConnectionFromServer",
"clientHostMode",
"serverClientMode",
"initiateConnectionFromServer", // kInvertConnection
"", // 35 = clientHostMode, obsolete
"", // 36 = serverClientMode, obsolete
"serviceEnabled",
"closeToTray"};
static const char *logLevelNames[] = {"INFO", "DEBUG", "DEBUG1", "DEBUG2"};
AppConfig::AppConfig() {
m_Config.registerReceiever(this);
load();
}
AppConfig::AppConfig() { m_Config.registerReceiever(this); }
void AppConfig::load() {
void AppConfig::loadAllScopes() {
m_Config.loadAll();
// User settings exist and the load from system scope variable is true
@ -112,6 +109,8 @@ void AppConfig::load() {
void AppConfig::loadSettings() {
using enum AppConfig::Setting;
qDebug("loading settings");
m_ScreenName =
loadSetting(kScreenName, QHostInfo::localHostName()).toString();
if (m_ScreenName.isEmpty()) {
@ -119,7 +118,7 @@ void AppConfig::loadSettings() {
}
m_Port = loadSetting(kPort, 24800).toInt();
m_Interface = loadSetting(kInterfaceSetting).toString();
m_Interface = loadSetting(kInterface).toString();
m_LogLevel = loadSetting(kLogLevel, 0).toInt();
m_LogToFile = loadSetting(kLogToFile, false).toBool();
m_LogFilename =
@ -130,98 +129,74 @@ void AppConfig::loadSettings() {
QVariant elevateMode = loadSetting(kElevateModeEnum);
if (!elevateMode.isValid()) {
elevateMode = loadSetting(
kElevateModeSetting, QVariant(static_cast<int>(kDefaultElevateMode)));
kElevateMode, QVariant(static_cast<int>(kDefaultElevateMode)));
}
m_ElevateMode = static_cast<ElevateMode>(elevateMode.toInt());
m_ActivateEmail = loadSetting(kActivateEmail, "").toString();
m_CryptoEnabled = loadSetting(kCryptoEnabled, true).toBool();
m_AutoHide = loadSetting(kAutoHide, false).toBool();
m_LastVersion = loadSetting(kLastVersion, "Unknown").toString();
m_LastExpiringWarningTime = loadSetting(kLastExpireWarningTime, 0).toInt();
m_ActivationHasRun = loadSetting(kActivationHasRun, false).toBool();
m_MinimizeToTray = loadSetting(kMinimizeToTray, false).toBool();
m_LoadFromSystemScope =
loadCommonSetting(kLoadSystemSettings, false).toBool();
m_ServerGroupChecked = loadSetting(kGroupServerCheck, false).toBool();
m_ServerGroupChecked = loadSetting(kServerGroupChecked, false).toBool();
m_UseExternalConfig = loadSetting(kUseExternalConfig, false).toBool();
m_ConfigFile =
loadSetting(kConfigFile, QDir::homePath() + "/" + m_ConfigFilename)
.toString();
m_UseInternalConfig = loadSetting(kUseInternalConfig, false).toBool();
m_ClientGroupChecked = loadSetting(kGroupClientCheck, false).toBool();
m_ClientGroupChecked = loadSetting(kClientGroupChecked, false).toBool();
m_ServerHostname = loadSetting(kServerHostname).toString();
m_PreventSleep = loadSetting(kPreventSleep, false).toBool();
m_LanguageSync = loadSetting(kLanguageSync, false).toBool();
m_InvertScrollDirection = loadSetting(kInvertScrollDirection, false).toBool();
m_Guid = loadCommonSetting(kGuid, QUuid::createUuid()).toString();
m_licenseNextCheck = loadCommonSetting(kLicenseNextCheck, 0).toULongLong();
m_ClientHostMode = loadSetting(kClientHostMode, true).toBool();
m_ServerClientMode = loadSetting(kServerClientMode, true).toBool();
m_InitiateConnectionFromServer =
loadSetting(kInitiateConnectionFromServer, false).toBool();
m_InvertConnection = loadSetting(kInvertConnection, false).toBool();
// only change the serial key if the settings being loaded contains a key
bool updateSerial = m_Config.hasSetting(
bool loadSerial = m_Config.hasSetting(
settingName(kLoadSystemSettings), Config::Scope::Current);
// if the setting exists and is not empty
updateSerial = updateSerial &&
!loadSetting(kSerialKey, "").toString().trimmed().isEmpty();
if (updateSerial) {
m_Serialkey = loadSetting(kSerialKey, "").toString().trimmed();
m_Edition = static_cast<Edition>(
loadSetting(kEditionSetting, kUnregistered).toInt());
if (loadSerial) {
const auto &serialKey = loadSetting(kSerialKey, "").toString().trimmed();
if (!serialKey.isEmpty()) {
m_SerialKey = serialKey;
}
}
m_ServiceEnabled = loadSetting(kServiceEnabled, m_ServiceEnabled).toBool();
m_CloseToTray = loadSetting(kCloseToTray, m_CloseToTray).toBool();
m_TlsEnabled = loadSetting(kTlsEnabled, m_TlsEnabled).toBool();
m_TlsCertPath = loadSetting(kTlsCertPath, defaultTlsCertPath()).toString();
m_TlsKeyLength = loadSetting(kTlsKeyLength, m_TlsKeyLength).toString();
try {
// Set the default path of the TLS certificate file in the users DIR
QString certificateFilename =
QString("%1/%2/%3")
.arg(m_CoreInterface.getProfileDir(), "SSL", "Synergy.pem");
m_TlsCertPath = loadSetting(kTlsCertPath, certificateFilename).toString();
m_TlsKeyLength = loadSetting(kTlsKeyLength, "2048").toString();
} catch (const std::exception &e) {
qDebug() << e.what();
qFatal("Failed to get profile dir, unable to configure TLS");
}
if (cryptoEnabled()) {
generateCertificate();
}
applyAppSettings();
emit loaded();
}
void AppConfig::saveSettings() {
using enum Setting;
qDebug("saving settings");
setCommonSetting(kWizardLastRun, m_WizardLastRun);
setCommonSetting(kLoadSystemSettings, m_LoadFromSystemScope);
setCommonSetting(kGroupClientCheck, m_ClientGroupChecked);
setCommonSetting(kGroupServerCheck, m_ServerGroupChecked);
setCommonSetting(kGuid, m_Guid);
setCommonSetting(kClientGroupChecked, m_ClientGroupChecked);
setCommonSetting(kServerGroupChecked, m_ServerGroupChecked);
setCommonSetting(kLicenseNextCheck, m_licenseNextCheck);
if (isWritable()) {
setSetting(kScreenName, m_ScreenName);
setSetting(kPort, m_Port);
setSetting(kInterfaceSetting, m_Interface);
setSetting(kInterface, m_Interface);
setSetting(kLogLevel, m_LogLevel);
setSetting(kLogToFile, m_LogToFile);
setSetting(kLogFilename, m_LogFilename);
setSetting(kStartedBefore, m_StartedBefore);
setSetting(kElevateModeEnum, static_cast<int>(m_ElevateMode));
setSetting(kEditionSetting, m_Edition);
setSetting(kCryptoEnabled, m_CryptoEnabled);
setSetting(kTlsEnabled, m_TlsEnabled);
setSetting(kAutoHide, m_AutoHide);
setSetting(kSerialKey, m_Serialkey);
setSetting(kSerialKey, m_SerialKey);
setSetting(kLastVersion, m_LastVersion);
setSetting(kLastExpireWarningTime, m_LastExpiringWarningTime);
setSetting(kActivationHasRun, m_ActivationHasRun);
setSetting(kMinimizeToTray, m_MinimizeToTray);
setSetting(kUseExternalConfig, m_UseExternalConfig);
@ -231,17 +206,28 @@ void AppConfig::saveSettings() {
setSetting(kPreventSleep, m_PreventSleep);
setSetting(kLanguageSync, m_LanguageSync);
setSetting(kInvertScrollDirection, m_InvertScrollDirection);
setSetting(kClientHostMode, m_ClientHostMode);
setSetting(kServerClientMode, m_ServerClientMode);
setSetting(kInvertConnection, m_InvertConnection);
setSetting(kServiceEnabled, m_ServiceEnabled);
setSetting(kCloseToTray, m_CloseToTray);
// See enum ElevateMode declaration to understand why this setting is bool
setSetting(kElevateModeSetting, m_ElevateMode == ElevateAlways);
setSetting(kElevateMode, m_ElevateMode == ElevateAlways);
}
setModified(false);
applyAppSettings();
saved();
if (m_TlsChanged) {
m_TlsChanged = false;
emit tlsChanged();
}
}
QString AppConfig::defaultTlsCertPath() const {
QDir path(m_CoreInterface.getProfileDir());
path = path.filePath("SSL");
path = path.filePath("Synergy.pem");
return path.absolutePath();
}
QString AppConfig::settingName(Setting name) {
@ -293,13 +279,15 @@ void AppConfig::loadScope(Config::Scope scope) {
}
}
void AppConfig::setDefaultValues() { m_InitiateConnectionFromServer = false; }
void AppConfig::setDefaultValues() { m_InvertConnection = false; }
void AppConfig::setLoadFromSystemScope(bool value) {
if (value) {
qDebug("loading system settings scope");
loadScope(Config::Scope::System);
} else {
qDebug("loading user settings scope");
loadScope(Config::Scope::User);
}
@ -323,59 +311,132 @@ void AppConfig::setSettingModified(T &variable, const T &newValue) {
setModified(true);
}
}
QString AppConfig::logDir() const {
// by default log to home dir
return QDir::home().absolutePath() + "/";
}
void AppConfig::generateCertificate(bool forceGeneration) const {
try {
SslCertificate sslCertificate;
sslCertificate.generateCertificate(
tlsCertPath(), tlsKeyLength(), forceGeneration);
emit sslToggled();
} catch (const std::exception &e) {
qDebug() << e.what();
qFatal("Failed to configure TLS");
void AppConfig::persistLogDir() const {
QDir dir = logDir();
// persist the log directory
if (!dir.exists()) {
dir.mkpath(dir.path());
}
}
void AppConfig::applyAppSettings() const {
QApplication::setQuitOnLastWindowClosed(!m_CloseToTray);
}
///////////////////////////////////////////////////////////////////////////////
// Begin getters and setters
// Begin getters
///////////////////////////////////////////////////////////////////////////////
#ifdef SYNERGY_ENABLE_LICENSING
bool AppConfig::activationHasRun() const { return m_ActivationHasRun; }
QString AppConfig::serialKey() const { return m_SerialKey; }
Config &AppConfig::config() { return m_Config; }
const QString &AppConfig::screenName() const { return m_ScreenName; }
int AppConfig::port() const { return m_Port; }
const QString &AppConfig::networkInterface() const { return m_Interface; }
int AppConfig::logLevel() const { return m_LogLevel; }
bool AppConfig::logToFile() const { return m_LogToFile; }
const QString &AppConfig::logFilename() const { return m_LogFilename; }
QString AppConfig::logLevelText() const { return logLevelNames[logLevel()]; }
ProcessMode AppConfig::processMode() const {
return m_ServiceEnabled ? ProcessMode::kService : ProcessMode::kDesktop;
}
bool AppConfig::wizardShouldRun() const {
return m_WizardLastRun < kWizardVersion;
}
bool AppConfig::startedBefore() const { return m_StartedBefore; }
QString AppConfig::lastVersion() const { return m_LastVersion; }
QString AppConfig::coreServerName() const { return m_CoreServerName; }
QString AppConfig::coreClientName() const { return m_CoreClientName; }
ElevateMode AppConfig::elevateMode() const { return m_ElevateMode; }
bool AppConfig::tlsEnabled() const { return m_TlsEnabled; }
bool AppConfig::autoHide() const { return m_AutoHide; }
bool AppConfig::invertScrollDirection() const {
return m_InvertScrollDirection;
}
unsigned long long AppConfig::licenseNextCheck() const {
return m_licenseNextCheck;
}
bool AppConfig::languageSync() const { return m_LanguageSync; }
bool AppConfig::preventSleep() const { return m_PreventSleep; }
bool AppConfig::invertConnection() const { return m_InvertConnection; }
bool AppConfig::minimizeToTray() const { return m_MinimizeToTray; }
QString AppConfig::tlsCertPath() const { return m_TlsCertPath; }
QString AppConfig::tlsKeyLength() const { return m_TlsKeyLength; }
bool AppConfig::serviceEnabled() const { return m_ServiceEnabled; }
bool AppConfig::closeToTray() const { return m_CloseToTray; }
bool AppConfig::serverGroupChecked() const { return m_ServerGroupChecked; }
bool AppConfig::useExternalConfig() const { return m_UseExternalConfig; }
const QString &AppConfig::configFile() const { return m_ConfigFile; }
bool AppConfig::useInternalConfig() const { return m_UseInternalConfig; }
bool AppConfig::clientGroupChecked() const { return m_ClientGroupChecked; }
QString AppConfig::serverHostname() const { return m_ServerHostname; }
void AppConfig::setActivationHasRun(bool value) { m_ActivationHasRun = value; }
void AppConfig::setEdition(Edition e) {
setSettingModified(m_Edition, e);
setCommonSetting(Setting::kEditionSetting, m_Edition);
///////////////////////////////////////////////////////////////////////////////
// End getters
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Begin setters
///////////////////////////////////////////////////////////////////////////////
void AppConfig::clearSerialKey() { m_SerialKey.clear(); }
void AppConfig::setTlsEnabled(bool value) {
setSettingModified(m_TlsEnabled, value);
m_TlsChanged = true;
}
Edition AppConfig::edition() const { return m_Edition; }
void AppConfig::setSerialKey(const QString &serial) {
setSettingModified(m_Serialkey, serial);
setCommonSetting(Setting::kSerialKey, m_Serialkey);
void AppConfig::setTlsCertPath(const QString &value) {
setSettingModified(m_TlsCertPath, value);
m_TlsChanged = true;
}
void AppConfig::clearSerialKey() { m_Serialkey.clear(); }
QString AppConfig::serialKey() const { return m_Serialkey; }
int AppConfig::lastExpiringWarningTime() const {
return m_LastExpiringWarningTime;
void AppConfig::setTlsKeyLength(const QString &value) {
setSettingModified(m_TlsKeyLength, value);
m_TlsChanged = true;
}
void AppConfig::setLastExpiringWarningTime(int newValue) {
setSettingModified(m_LastExpiringWarningTime, newValue);
void AppConfig::setSerialKey(const QString &serialKey) {
setSettingModified(m_SerialKey, serialKey);
setCommonSetting(Setting::kSerialKey, m_SerialKey);
}
#endif // SYNERGY_ENABLE_LICENSING
void AppConfig::setServerGroupChecked(bool newValue) {
setSettingModified(m_ServerGroupChecked, newValue);
}
@ -399,57 +460,6 @@ void AppConfig::setClientGroupChecked(bool newValue) {
void AppConfig::setServerHostname(const QString &newValue) {
setSettingModified(m_ServerHostname, newValue);
}
void AppConfig::setClientHostMode(bool newValue) {
setSettingModified(m_ClientHostMode, newValue);
}
void AppConfig::setServerClientMode(bool newValue) {
setSettingModified(m_ServerClientMode, newValue);
}
Config &AppConfig::config() { return m_Config; }
const QString &AppConfig::screenName() const { return m_ScreenName; }
int AppConfig::port() const { return m_Port; }
const QString &AppConfig::networkInterface() const { return m_Interface; }
int AppConfig::logLevel() const { return m_LogLevel; }
bool AppConfig::logToFile() const { return m_LogToFile; }
const QString &AppConfig::logFilename() const { return m_LogFilename; }
QString AppConfig::logDir() const {
// by default log to home dir
return QDir::home().absolutePath() + "/";
}
void AppConfig::persistLogDir() const {
QDir dir = logDir();
// persist the log directory
if (!dir.exists()) {
dir.mkpath(dir.path());
}
}
QString AppConfig::logLevelText() const { return logLevelNames[logLevel()]; }
ProcessMode AppConfig::processMode() const {
return m_ServiceEnabled ? ProcessMode::kService : ProcessMode::kDesktop;
}
bool AppConfig::wizardShouldRun() const {
return m_WizardLastRun < kWizardVersion;
}
bool AppConfig::startedBefore() const { return m_StartedBefore; }
QString AppConfig::lastVersion() const { return m_LastVersion; }
void AppConfig::setLastVersion(const QString &version) {
setSettingModified(m_LastVersion, version);
}
@ -485,61 +495,16 @@ void AppConfig::setElevateMode(ElevateMode em) {
setSettingModified(m_ElevateMode, em);
}
QString AppConfig::coreServerName() const { return m_CoreServerName; }
QString AppConfig::coreClientName() const { return m_CoreClientName; }
ElevateMode AppConfig::elevateMode() { return m_ElevateMode; }
void AppConfig::setCryptoEnabled(bool newValue) {
if (m_CryptoEnabled != newValue && newValue) {
generateCertificate();
} else {
emit sslToggled();
}
setSettingModified(m_CryptoEnabled, newValue);
}
bool AppConfig::cryptoAvailable() const {
bool result{true};
#ifdef SYNERGY_ENABLE_LICENSING
result =
(edition() == kPro || edition() == kProChina || edition() == kBusiness ||
edition() == kUltimate);
#endif // SYNERGY_ENABLE_LICENSING
return result;
}
bool AppConfig::cryptoEnabled() const {
return cryptoAvailable() && m_CryptoEnabled;
}
void AppConfig::setAutoHide(bool b) { setSettingModified(m_AutoHide, b); }
bool AppConfig::autoHide() const { return m_AutoHide; }
void AppConfig::setMinimizeToTray(bool newValue) {
setSettingModified(m_MinimizeToTray, newValue);
}
bool AppConfig::invertScrollDirection() const {
return m_InvertScrollDirection;
}
void AppConfig::setLicenseNextCheck(unsigned long long time) {
setSettingModified(m_licenseNextCheck, time);
}
unsigned long long AppConfig::licenseNextCheck() const {
return m_licenseNextCheck;
}
const QString &AppConfig::guid() const { return m_Guid; }
bool AppConfig::languageSync() const { return m_LanguageSync; }
void AppConfig::setInvertScrollDirection(bool newValue) {
setSettingModified(m_InvertScrollDirection, newValue);
}
@ -548,63 +513,23 @@ void AppConfig::setLanguageSync(bool newValue) {
setSettingModified(m_LanguageSync, newValue);
}
bool AppConfig::preventSleep() const { return m_PreventSleep; }
bool AppConfig::clientHostMode() const {
return (m_ClientHostMode && initiateConnectionFromServer());
}
bool AppConfig::serverClientMode() const {
return (m_ServerClientMode && initiateConnectionFromServer());
}
bool AppConfig::initiateConnectionFromServer() const {
return m_InitiateConnectionFromServer;
}
void AppConfig::setPreventSleep(bool newValue) {
setSettingModified(m_PreventSleep, newValue);
}
bool AppConfig::minimizeToTray() const { return m_MinimizeToTray; }
void AppConfig::setTlsCertPath(const QString &path) { m_TlsCertPath = path; }
QString AppConfig::tlsCertPath() const { return m_TlsCertPath; }
QString AppConfig::tlsKeyLength() const { return m_TlsKeyLength; }
void AppConfig::setTlsKeyLength(const QString &length) {
if (m_TlsKeyLength != length) {
m_TlsKeyLength = length;
generateCertificate(true);
}
}
void AppConfig::setServiceEnabled(bool enabled) {
setSettingModified(m_ServiceEnabled, enabled);
}
bool AppConfig::serviceEnabled() const { return m_ServiceEnabled; }
void AppConfig::setCloseToTray(bool minimize) {
setSettingModified(m_CloseToTray, minimize);
}
bool AppConfig::closeToTray() const { return m_CloseToTray; }
bool AppConfig::serverGroupChecked() const { return m_ServerGroupChecked; }
bool AppConfig::useExternalConfig() const { return m_UseExternalConfig; }
const QString &AppConfig::configFile() const { return m_ConfigFile; }
bool AppConfig::useInternalConfig() const { return m_UseInternalConfig; }
bool AppConfig::clientGroupChecked() const { return m_ClientGroupChecked; }
QString AppConfig::serverHostname() const { return m_ServerHostname; }
void AppConfig::setInvertConnection(bool value) {
setSettingModified(m_InvertConnection, value);
emit invertConnectionChanged();
}
///////////////////////////////////////////////////////////////////////////////
// End getters and setters
// End setters
///////////////////////////////////////////////////////////////////////////////

View file

@ -20,10 +20,9 @@
#include "CommonConfig.h"
#include "Config.h"
#include "CoreInterface.h"
#include "LicenseManager.h"
#include "gui/CoreInterface.h"
#include "gui/ElevateMode.h"
#include "shared/EditionType.h"
#include "gui/IAppConfig.h"
#include <QObject>
#include <QString>
@ -32,11 +31,9 @@
class QSettings;
class SettingsDialog;
class LicenseRegister;
class ServerConfig;
class LicenseManager;
class LicenseHandler;
class ActivationDialog;
class LicenseRegistry;
enum class ProcessMode { kService, kDesktop };
@ -48,17 +45,67 @@ const ProcessMode kDefaultProcessMode = ProcessMode::kService;
const ProcessMode kDefaultProcessMode = ProcessMode::kDesktop;
#endif
/// @brief Reads and writes application specific settings
class AppConfig : public QObject, public synergy::gui::CommonConfig {
/**
* @brief Simply reads and writes app settings.
*
* Important: Maintain a clear separation of concerns and keep it simple.
* It is tempting to add logic (e.g. license checks) to this class since it
* instance is widely accessible, but that has previously led to this class
* becoming a god object.
*/
class AppConfig : public QObject,
public synergy::gui::CommonConfig,
public synergy::gui::IAppConfig {
Q_OBJECT
friend class SettingsDialog;
friend class MainWindow;
friend class SetupWizard;
friend class ServerConfig;
friend class LicenseManager;
friend class ActivationDialog;
friend class LicenseRegistry;
private:
enum class Setting {
kScreenName = 0,
kPort = 1,
kInterface = 2,
kLogLevel = 3,
kLogToFile = 4,
kLogFilename = 5,
kWizardLastRun = 6,
kStartedBefore = 7,
kElevateMode = 8,
kElevateModeEnum = 9,
// 10 = edition, obsolete (using serial key instead)
kTlsEnabled = 11,
kAutoHide = 12,
kSerialKey = 13,
kLastVersion = 14,
// 15 = last expire time, obsolete
kActivationHasRun = 16,
kMinimizeToTray = 17,
// 18 = activate email, obsolete
kLoadSystemSettings = 19,
kServerGroupChecked = 20,
kUseExternalConfig = 21,
kConfigFile = 22,
kUseInternalConfig = 23,
kClientGroupChecked = 24,
kServerHostname = 25,
kTlsCertPath = 26,
kTlsKeyLength = 27,
kPreventSleep = 28,
kLanguageSync = 29,
kInvertScrollDirection = 30,
// 31 = guid, obsolete
// 32 = license registry url, obsolete
kLicenseNextCheck = 33,
kInvertConnection = 34,
// 35 = client-host-mode, obsolete
// 36 = server-client-mode, obsolete
kServiceEnabled = 37,
kCloseToTray = 38,
};
public:
explicit AppConfig();
@ -66,12 +113,8 @@ public:
/// @brief Underlying configuration reader/writer
synergy::gui::Config &config();
/// @brief Saves the setting to the current scope
void saveSettings() override;
void applyAppSettings() const;
/// @brief Generates TLS certificate
/// @param [in] bool forceGeneration Generate certificate even if it's exists.
void generateCertificate(bool forceGeneration = false) const;
/**
* Getters
@ -93,18 +136,13 @@ public:
QString coreClientName() const;
QString logDir() const;
void persistLogDir() const;
ElevateMode elevateMode();
bool cryptoAvailable() const;
bool cryptoEnabled() const;
ElevateMode elevateMode() const;
bool autoHide() const;
bool invertScrollDirection() const;
unsigned long long licenseNextCheck() const;
const QString &guid() const;
bool languageSync() const;
bool preventSleep() const;
bool clientHostMode() const;
bool serverClientMode() const;
bool initiateConnectionFromServer() const;
bool invertConnection() const;
bool serverGroupChecked() const;
bool useExternalConfig() const;
const QString &configFile() const;
@ -115,70 +153,18 @@ public:
bool serviceEnabled() const;
bool minimizeToTray() const;
bool closeToTray() const;
/// @brief Gets the current TLS certificate path
/// @return QString The path to the cert
QString tlsCertPath() const;
/// @brief Get the key length to be used for the private key of a TLS cert
/// @return QString The key length in bits
QString tlsKeyLength() const;
#ifdef SYNERGY_ENABLE_LICENSING
Edition edition() const;
QString serialKey() const;
int lastExpiringWarningTime() const;
bool activationHasRun() const;
#endif
protected:
enum class Setting {
kScreenName,
kPort,
kInterfaceSetting,
kLogLevel,
kLogToFile,
kLogFilename,
kWizardLastRun,
kStartedBefore,
kElevateModeSetting,
kElevateModeEnum,
kEditionSetting,
kCryptoEnabled,
kAutoHide,
kSerialKey,
kLastVersion,
kLastExpireWarningTime,
kActivationHasRun,
kMinimizeToTray,
kActivateEmail,
kLoadSystemSettings,
kGroupServerCheck,
kUseExternalConfig,
kConfigFile,
kUseInternalConfig,
kGroupClientCheck,
kServerHostname,
kTlsCertPath,
kTlsKeyLength,
kPreventSleep,
kLanguageSync,
kInvertScrollDirection,
kGuid,
kLicenseRegistryUrl,
kLicenseNextCheck,
kInitiateConnectionFromServer,
kClientHostMode,
kServerClientMode,
kServiceEnabled,
kCloseToTray
};
static QString settingName(AppConfig::Setting name);
bool tlsEnabled() const override;
QString tlsCertPath() const override;
QString tlsKeyLength() const override;
private:
/// @brief Loads the setting from the current scope
void loadSettings() override;
static QString settingName(AppConfig::Setting name);
/**
* Setters
*/
@ -192,11 +178,9 @@ protected:
void setWizardHasRun();
void setStartedBefore(bool b);
void setElevateMode(ElevateMode em);
void setCryptoEnabled(bool e);
void setEdition(Edition);
void setSerialKey(const QString &serial);
void setTlsEnabled(bool e);
void setSerialKey(const QString &serialKey);
void clearSerialKey();
void setLastExpiringWarningTime(int t);
void setAutoHide(bool b);
void setInvertScrollDirection(bool b);
void setLicenseNextCheck(unsigned long long);
@ -208,13 +192,14 @@ protected:
void setUseInternalConfig(bool);
void setClientGroupChecked(bool);
void setServerHostname(const QString &);
void setClientHostMode(bool newValue);
void setServerClientMode(bool newValue);
void setMinimizeToTray(bool b);
void setLastVersion(const QString &version);
void setServiceEnabled(bool enabled);
void setCloseToTray(bool minimize);
void setActivationHasRun(bool value);
void setTlsCertPath(const QString &path);
void setTlsKeyLength(const QString &length);
void setInvertConnection(bool value);
/// @brief Sets the user preference to load from SystemScope.
/// @param [in] value
@ -223,17 +208,8 @@ protected:
/// scope settings.
void setLoadFromSystemScope(bool value);
/// @brief Set the path to the TLS/SSL certificate file that will be used
/// @param [in] path The path to the Certificate
void setTlsCertPath(const QString &path);
/// @brief Sets the key length of the private key to use in a TLS connection
/// @param [in] QString length The key length eg: 1024, 2048, 4096
void setTlsKeyLength(const QString &length);
private:
/// @brief Loads config from the underlying reader/writer
void load();
void loadAllScopes();
/// @brief Sets the value of a setting
/// @param [in] name The Setting to be saved
@ -273,6 +249,11 @@ private:
/// for settings that shouldn't be copied from between scopes.
void setDefaultValues();
/**
* @brief Gets a TLS certificate path based on the user's profile dir.
*/
QString defaultTlsCertPath() const;
synergy::gui::Config m_Config;
CoreInterface m_CoreInterface;
QString m_ScreenName = "";
@ -284,23 +265,18 @@ private:
int m_WizardLastRun = 0;
bool m_StartedBefore = false;
ElevateMode m_ElevateMode = kDefaultElevateMode;
Edition m_Edition = Edition::kUnregistered;
QString m_ActivateEmail = "";
bool m_CryptoEnabled = false;
bool m_TlsEnabled = true;
bool m_AutoHide = false;
QString m_Serialkey = "";
QString m_SerialKey = "";
QString m_LastVersion = "";
QString m_Guid = "";
unsigned long long m_licenseNextCheck = 0;
int m_LastExpiringWarningTime = 0;
bool m_ActivationHasRun = false;
bool m_MinimizeToTray = true;
bool m_InvertScrollDirection = false;
bool m_LanguageSync = true;
bool m_PreventSleep = false;
bool m_InitiateConnectionFromServer = false;
bool m_ClientHostMode = true;
bool m_ServerClientMode = true;
bool m_InvertConnection = false;
bool m_ServerGroupChecked = false;
bool m_UseExternalConfig = false;
QString m_ConfigFile = "";
@ -308,13 +284,15 @@ private:
bool m_ClientGroupChecked = false;
QString m_ServerHostname = "";
bool m_ServiceEnabled = kDefaultProcessMode == ProcessMode::kService;
bool m_CloseToTray = true;
/// @brief The path to the TLS certificate file
bool m_CloseToTray = false;
QString m_TlsCertPath = "";
QString m_TlsKeyLength = "2048";
/// @brief The key length of the TLS cert to make
QString m_TlsKeyLength = "";
/**
* @brief Flag is set when any TLS is setting is changed, and is reset
* when the TLS changed event is emitted.
*/
bool m_TlsChanged = false;
/// @brief should the setting be loaded from
/// SystemScope
@ -340,6 +318,9 @@ private:
static const char m_ConfigFilename[];
signals:
void sslToggled() const;
void screenNameChanged() const;
void loaded();
void saved();
void tlsChanged();
void screenNameChanged();
void invertConnectionChanged();
};

View file

@ -1,237 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015 Synergy 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 <http://www.gnu.org/licenses/>.
*/
#include "LicenseManager.h"
#include "ActivationNotifier.h"
#include "AppConfig.h"
#include <QDateTime>
#include <QLocale>
#include <QThread>
#include <QTimer>
#include <ctime>
#include <stdexcept>
#include <utility>
namespace {
std::string getMaintenanceMessage(const SerialKey &serialKey) {
auto expiration =
QDateTime::fromSecsSinceEpoch(serialKey.getExpiration()).date();
QString message =
"The license key you used will only work with versions of Synergy "
"released before %1."
"<p>To use this version, you’ll need to renew your Synergy maintenance "
"license. "
"<a href=\"https://symless.com/synergy/account?source=gui\""
"style=\"text-decoration: none; color: #4285F4;\">Renew today</a>.</p>";
auto formatedDate = QLocale("en_US").toString(expiration, "MMM dd yyyy");
return message.arg(formatedDate).toStdString();
}
void checkSerialKey(const SerialKey &serialKey, bool acceptExpired) {
if (serialKey.isMaintenance()) {
auto buildDate =
QDateTime::fromString(__TIMESTAMP__, "ddd MMM dd hh:mm:ss yyyy")
.toSecsSinceEpoch();
if (buildDate > serialKey.getExpiration()) {
throw std::runtime_error(getMaintenanceMessage(serialKey));
}
}
if (!acceptExpired && serialKey.isExpired(::time(nullptr))) {
throw std::runtime_error("Serial key expired");
}
#ifdef SYNERGY_ENABLE_LICENSING
if (!serialKey.isValid()) {
throw std::runtime_error("The serial key is not valid.");
}
#endif // SYNERGY_ENABLE_LICENSING
}
} // namespace
LicenseManager::LicenseManager(AppConfig *appConfig)
: m_pAppConfig(appConfig),
m_serialKey(appConfig->edition()),
m_registry(*appConfig) {}
void LicenseManager::setSerialKey(SerialKey serialKey, bool acceptExpired) {
checkSerialKey(serialKey, acceptExpired);
if (serialKey != m_serialKey) {
using std::swap;
swap(serialKey, m_serialKey);
m_pAppConfig->setSerialKey(QString::fromStdString(m_serialKey.toString()));
emit showLicenseNotice(getLicenseNotice());
validateSerialKey();
m_registry.scheduleRegistration();
if (m_serialKey.edition() != serialKey.edition()) {
m_pAppConfig->setEdition(m_serialKey.edition());
emit editionChanged(m_serialKey.edition());
}
}
}
void LicenseManager::notifyUpdate(
QString fromVersion, QString toVersion) const {
if ((fromVersion == "Unknown") && (m_serialKey == SerialKey(kUnregistered))) {
return;
}
ActivationNotifier *notifier = new ActivationNotifier();
notifier->setUpdateInfo(
fromVersion, toVersion, QString::fromStdString(m_serialKey.toString()));
QThread *thread = new QThread();
connect(notifier, SIGNAL(finished()), thread, SLOT(quit()));
connect(notifier, SIGNAL(finished()), notifier, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
notifier->moveToThread(thread);
thread->start();
QMetaObject::invokeMethod(notifier, "notifyUpdate", Qt::QueuedConnection);
}
Edition LicenseManager::activeEdition() const { return m_serialKey.edition(); }
QString LicenseManager::activeEditionName() const {
return getEditionName(activeEdition(), m_serialKey.isTrial());
}
const SerialKey &LicenseManager::serialKey() const { return m_serialKey; }
void LicenseManager::refresh() {
if (!m_pAppConfig->serialKey().isEmpty()) {
try {
SerialKey serialKey(m_pAppConfig->serialKey().toStdString());
setSerialKey(serialKey, true);
} catch (const std::exception &e) {
qDebug() << e.what();
m_serialKey = SerialKey();
m_pAppConfig->clearSerialKey();
}
}
if (!m_serialKey.isValid()) {
emit InvalidLicense();
}
}
QString LicenseManager::getEditionName(Edition const edition, bool trial) {
SerialKeyEdition KeyEdition(edition);
std::string name = KeyEdition.getProductName();
if (trial) {
name += " (Trial)";
}
return QString::fromUtf8(name.c_str(), static_cast<int>(name.size()));
}
void LicenseManager::notifyActivation(QString identity) const {
ActivationNotifier *notifier = new ActivationNotifier();
notifier->setIdentity(identity);
QThread *thread = new QThread();
connect(notifier, SIGNAL(finished()), thread, SLOT(quit()));
connect(notifier, SIGNAL(finished()), notifier, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
notifier->moveToThread(thread);
thread->start();
QMetaObject::invokeMethod(notifier, "notify", Qt::QueuedConnection);
}
QString LicenseManager::getLicenseNotice() const {
QString Notice;
if (m_serialKey.isTemporary()) {
if (m_serialKey.isTrial()) {
Notice = getTrialNotice();
} else {
Notice = getTemporaryNotice();
}
}
return Notice;
}
void LicenseManager::registerLicense() { m_registry.registerLicense(); }
QString LicenseManager::getTrialNotice() const {
QString Notice;
if (m_serialKey.isExpired(::time(0))) {
Notice = "<html><head/><body><p>"
"Trial expired - "
"<a href=\"https://symless.com/synergy/purchase?source=gui\" "
"style=\"color: #FFFFFF;\">Buy now</a>"
"</p></body></html>";
} else {
Notice = "<html><head/><body><p>"
"Trial expires in %1 day%2 - "
"<a href=\"https://symless.com/synergy/purchase?source=gui\" "
"style=\"color: #FFFFFF;\">Buy now</a>"
"</p></body></html>";
time_t daysLeft = m_serialKey.daysLeft(::time(0));
Notice = Notice.arg(daysLeft).arg((daysLeft == 1) ? "" : "s");
}
return Notice;
}
QString LicenseManager::getTemporaryNotice() const {
QString Notice;
if (m_serialKey.isExpired(::time(0))) {
Notice = "<html><head/><body><p>"
"License expired - "
"<a href=\"https://symless.com/synergy/purchase?source=gui\" "
"style=\"color: #FFFFFF;\">Renew now</a>"
"</p></body></html>";
} else if (m_serialKey.isExpiring(::time(0))) {
Notice = "<html><head/><body><p>"
"License expires in %1 day%2 - "
"<a href=\"https://symless.com/synergy/purchase?source=gui\" "
"style=\"color: #FFFFFF;\">Renew now</a>"
"</p></body></html>";
time_t daysLeft = m_serialKey.daysLeft(::time(0));
Notice = Notice.arg(daysLeft).arg((daysLeft == 1) ? "" : "s");
}
return Notice;
}
void LicenseManager::validateSerialKey() const {
if (m_serialKey.isValid()) {
if (m_serialKey.isTemporary()) {
QTimer::singleShot(
m_serialKey.getSpanLeft(), this, SLOT(validateSerialKey()));
}
} else {
emit InvalidLicense();
}
}

View file

@ -1,60 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015 Synergy 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "LicenseRegistry.h"
#include "shared/EditionType.h"
#include "shared/SerialKey.h"
#include <QObject>
class AppConfig;
class LicenseManager : public QObject {
Q_OBJECT
public:
LicenseManager(AppConfig *appConfig);
void setSerialKey(SerialKey serialKey, bool acceptExpired = false);
void refresh();
Edition activeEdition() const;
QString activeEditionName() const;
const SerialKey &serialKey() const;
void notifyUpdate(QString fromVersion, QString toVersion) const;
static QString getEditionName(Edition edition, bool trial = false);
void notifyActivation(QString identity) const;
QString getLicenseNotice() const;
private:
AppConfig *m_pAppConfig;
SerialKey m_serialKey;
LicenseRegistry m_registry;
public slots:
void validateSerialKey() const;
void registerLicense();
signals:
void editionChanged(Edition) const;
void InvalidLicense() const;
void showLicenseNotice(const QString &notice) const;
protected:
QString getTrialNotice() const;
QString getTemporaryNotice() const;
};

View file

@ -1,101 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2022 Synergy 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 <http://www.gnu.org/licenses/>.
*/
#include <QJsonDocument>
#include <QJsonObject>
#include <QNetworkReply>
#include <QTimer>
#include "AppConfig.h"
#include "LicenseRegistry.h"
#include <QSysInfo>
const char *const kLicenseRegistryUrl =
"https://api2.prod.symless.com/license/register";
LicenseRegistry::LicenseRegistry(AppConfig &config) : m_config(config) {
connect(&m_timer, SIGNAL(timeout()), this, SLOT(registerLicense()));
}
void LicenseRegistry::registerLicense() {
m_timer.stop();
if (m_config.edition() == Edition::kBusiness) {
const auto url = QUrl(kLicenseRegistryUrl);
auto request = QNetworkRequest(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
m_manager.post(request, getRequestData());
connect(
&m_manager, SIGNAL(finished(QNetworkReply *)), this,
SLOT(handleResponse(QNetworkReply *)));
}
}
void LicenseRegistry::handleResponse(QNetworkReply *reply) {
if (reply) {
const auto HOUR = (60 * 60); // seconds per hour
const auto DAY = (24 * HOUR); // seconds per day
const auto WEEK = (7 * DAY); // seconds per week
const auto currentTimestamp = time(nullptr);
if (reply->error() == QNetworkReply::NoError) {
m_config.setLicenseNextCheck(currentTimestamp + WEEK);
} else {
m_config.setLicenseNextCheck(currentTimestamp + HOUR);
}
scheduleRegistration();
reply->deleteLater();
}
}
QByteArray LicenseRegistry::getRequestData() const {
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0)
QString guid(QSysInfo::machineUniqueId());
#else
QString guid;
#endif
QJsonObject data;
if (!guid.isEmpty()) {
data["guid"] = guid;
data["guid_type"] = "system";
} else {
data["guid"] = m_config.guid();
data["guid_type"] = "synergy";
}
data["key"] = m_config.serialKey();
data["is_server"] = m_config.serverGroupChecked();
return QJsonDocument(data).toJson();
}
void LicenseRegistry::scheduleRegistration() {
const auto nextCheck = m_config.licenseNextCheck();
const auto currentTimestamp = static_cast<unsigned long long>(time(nullptr));
if (currentTimestamp >= nextCheck) {
registerLicense();
} else {
const auto interval =
(nextCheck - currentTimestamp) * 1000; // interval in milliseconds
m_timer.setInterval(static_cast<int>(interval));
m_timer.setSingleShot(true);
m_timer.start();
}
}

File diff suppressed because it is too large Load diff

View file

@ -35,9 +35,10 @@
#include "ServerConfig.h"
#include "ServerConnection.h"
#include "TrayIcon.h"
#include "global/Ipc.h"
#include "gui/QIpcClient.h"
#include "gui/TlsUtility.h"
#include "gui/VersionChecker.h"
#include "shared/Ipc.h"
class QAction;
class QMenu;
@ -57,8 +58,7 @@ class QSynergyApplication;
class SetupWizard;
class DataDownloader;
class CommandProcess;
class SslCertificate;
class LicenseManager;
class TlsCertificate;
class MainWindow : public QMainWindow, public Ui::MainWindowBase {
Q_OBJECT
@ -80,60 +80,57 @@ public:
};
enum class CoreMode { Client, Server };
enum class LogLevel { Error, Info };
enum class RuningState { Started, Stopped };
public:
#ifdef SYNERGY_ENABLE_LICENSING
MainWindow(AppConfig &appConfig, LicenseManager &licenseManager);
#else
explicit MainWindow(AppConfig &appConfig);
#endif
~MainWindow() override;
public:
void setVisible(bool visible) override;
CoreMode coreMode() const {
auto isClient = m_pRadioGroupClient->isChecked();
return isClient ? CoreMode::Client : CoreMode::Server;
}
CoreState coreState() const { return m_CoreState; }
QString hostname() const { return m_pLineEditHostname->text(); }
QString configFilename();
CoreMode coreMode() const;
QString address() const;
QString appPath(const QString &name);
QString appPath(const QString &name) const;
void open();
void clearLog();
VersionChecker &versionChecker() { return m_VersionChecker; }
ServerConfig &serverConfig() { return m_ServerConfig; }
void showConfigureServer(const QString &message);
void showConfigureServer() { showConfigureServer(""); }
void autoAddScreen(const QString name);
#ifdef SYNERGY_ENABLE_LICENSING
LicenseManager &licenseManager() const;
int raiseActivationDialog();
#endif
public slots:
void setEdition(Edition edition);
#ifdef SYNERGY_ENABLE_LICENSING
void InvalidLicense();
void showLicenseNotice(const QString &message);
#endif
void appendLogRaw(const QString &text);
LicenseHandler &licenseHandler();
int showActivationDialog();
void appendLogInfo(const QString &text);
void appendLogDebug(const QString &text);
void appendLogError(const QString &text);
void startCore();
void retryStart();
void actionStart();
void handleIdleService(const QString &text);
protected slots:
void updateLocalFingerprint();
void updateScreenName();
signals:
void created();
void shown();
public slots:
void onAppAboutToQuit();
private slots:
void onCreated();
void onShown();
void onAppConfigLoaded();
void onAppConfigTlsChanged();
void onAppConfigScreenNameChanged();
void onAppConfigInvertConnection();
void onLicenseHandlerSerialKeyChanged(const QString &serialKey);
void onLicenseHandlerInvalidLicense();
void onIpcClientReadLogLine(const QString &text);
void onIpcClientErrorMessage(const QString &text);
void onIpcClientInfoMessage(const QString &text);
void onCoreProcessFinished(int exitCode, QProcess::ExitStatus);
void onVersionCheckerUpdateFound(const QString &version);
void onTrayIconCreate(QSystemTrayIcon::ActivationReason reason);
void onActionStartCoreTriggered();
void onActionStopCoreTriggered();
void onCoreProcessReadyReadStandardOutput();
void onCoreProcessReadyReadStandardError();
void on_m_pButtonApply_clicked();
void on_m_pLabelComputerName_linkActivated(const QString &link);
void on_m_pLabelFingerprint_linkActivated(const QString &link);
void on_m_pButtonConnect_clicked();
void on_m_pButtonConnectToClient_clicked();
void on_m_pRadioGroupServer_clicked(bool);
void on_m_pRadioGroupClient_clicked(bool);
void on_m_pButtonConfigureServer_clicked();
@ -142,24 +139,15 @@ protected slots:
void on_m_pActionHelp_triggered();
void on_m_pActionSettings_triggered();
void on_m_pActivate_triggered();
void coreProcessExit(int exitCode, QProcess::ExitStatus);
void trayActivated(QSystemTrayIcon::ActivationReason reason);
void stopCore();
void logOutput();
void logError();
void updateFound(const QString &version);
void saveSettings();
protected:
private:
QSettings &settings() { return *appConfig().config().currentSettings(); }
AppConfig &appConfig() { return m_AppConfig; }
AppConfig const &appConfig() const { return m_AppConfig; }
AppConfig *appConfigPtr() { return &m_AppConfig; }
void initConnections();
void createMenuBar();
void createStatusBar();
void createTrayIcon();
void loadSettings();
void applyConfig();
void setIcon(CoreState state) const;
void setCoreState(CoreState state);
bool checkForApp(int which, QString &app);
@ -168,51 +156,45 @@ protected:
void setStatus(const QString &status);
void sendIpcMessage(IpcMessageType type, const char *buffer, bool showErrors);
void updateFromLogLine(const QString &line);
QString getIPAddresses();
QString getIPAddresses() const;
void stopService();
void stopDesktop();
void enableServer(bool enable);
void enableClient(bool enable);
QString getProfileRootForArg();
QString getProfileRootForArg() const;
void checkConnected(const QString &line);
void checkFingerprint(const QString &line);
bool checkSecureSocket(const QString &line);
void checkLicense(const QString &line);
QString getTimeStamp() const;
void restartCore();
void showEvent(QShowEvent *) override;
void secureSocket(bool secureSocket);
void windowStateChanged();
void connectSlots() const;
void updateWindowTitle();
void processCoreLogLine(const QString &line);
void startCore();
void onCoreProcessRetryStart();
void updateLocalFingerprint();
void updateScreenName();
void saveSettings();
QString configFilename();
void showConfigureServer(const QString &message);
void showConfigureServer() { showConfigureServer(""); }
void showLicenseNotice();
void stopCore();
#ifdef Q_OS_MAC
void checkOSXNotification(const QString &line);
#endif
#ifdef SYNERGY_ENABLE_LICENSING
void checkLicense(const QString &line);
#endif
QString getTimeStamp();
void restartCore();
void showEvent(QShowEvent *) override;
void secureSocket(bool secureSocket);
void windowStateChanged();
private:
void updateWindowTitle();
#ifdef SYNERGY_ENABLE_LICENSING
LicenseManager *m_LicenseManager = nullptr;
#endif
AppConfig &m_AppConfig;
ServerConfig m_ServerConfig;
ServerConnection m_serverConnection;
ClientConnection m_clientConnection;
VersionChecker m_VersionChecker;
QIpcClient m_IpcClient;
TrayIcon m_trayIcon;
TrayIcon m_TrayIcon;
QMutex m_StopDesktopMutex;
#ifdef SYNERGY_ENABLE_LICENSING
bool m_ActivationDialogRunning = false;
QStringList m_PendingClientNames;
#endif
RuningState m_ExpectedRunningState = RuningState::Stopped;
std::unique_ptr<QProcess> m_pCoreProcess;
QMenuBar *m_pMenuBar = nullptr;
@ -226,16 +208,10 @@ private:
bool m_SecureSocket = false;
QString m_SecureSocketVersion = "";
private slots:
void on_m_pButtonApply_clicked();
void on_windowShown();
void on_m_pLabelComputerName_linkActivated(const QString &link);
void on_m_pLabelFingerprint_linkActivated(const QString &link);
void on_m_pButtonConnect_clicked();
void on_m_pButtonConnectToClient_clicked();
signals:
void windowShown();
AppConfig &m_AppConfig;
LicenseHandler m_LicenseHandler;
ServerConfig m_ServerConfig;
ServerConnection m_ServerConnection;
ClientConnection m_ClientConnection;
synergy::gui::TlsUtility m_TlsUtility;
};

View file

@ -7,11 +7,11 @@
<x>0</x>
<y>0</y>
<width>750</width>
<height>650</height>
<height>700</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
@ -34,83 +34,45 @@
<number>20</number>
</property>
<item>
<widget class="QWidget" name="m_pWidgetUpdate" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="m_pIconUpdate">
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="../res/Synergy.qrc">:/res/icons/16x16/warning.png</pixmap>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_pLabelUpdate">
<property name="text">
<string notr="true">m_pLabelUpdate</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="m_pSpacerUpdate">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>469</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="m_pLabelComputerName">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>65535</width>
<height>65535</height>
</size>
</property>
<property name="font">
<font>
<family>Arial</family>
<kerning>true</kerning>
</font>
</property>
<property name="text">
<string notr="true">This computer's name:</string>
</property>
</widget>
<layout class="QHBoxLayout" name="m_layout1">
<item>
<widget class="QLabel" name="m_pLabelComputerName">
<property name="text">
<string notr="true">This computer's name:</string>
</property>
</widget>
</item>
<item>
<spacer name="m_pSpacerUpdate">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="m_pLabelUpdate">
<property name="styleSheet">
<string notr="true">padding: 3px 5px;
border-radius: 3px;
background-color: #3B67D3;
color: #ffffff;
top: 3px;</string>
</property>
<property name="text">
<string notr="true">m_pLabelUpdate</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer_5">
@ -138,23 +100,11 @@
<item>
<widget class="QWidget" name="m_pMainWidgets" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>220</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="spacing">
<number>16</number>
@ -173,17 +123,11 @@
</property>
<item>
<widget class="QFrame" name="m_pGroupServer">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>250</height>
</size>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">.QFrame{
@ -192,193 +136,162 @@ border-radius: 4px;
background-color: rgba(192,192,192, 0.1);
}</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="topMargin">
<number>11</number>
<property name="spacing">
<number>15</number>
</property>
<item>
<item alignment="Qt::AlignTop">
<widget class="QRadioButton" name="m_pRadioGroupServer">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>65535</width>
<height>30</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QRadioButton::indicator{
top: -7px;
top: -7px;
}</string>
</property>
<property name="text">
<string>Use this computer's keyboard and mouse
(make this computer the server)</string>
(make this computer the &amp;server)</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="m_pLabelClientIp">
<property name="text">
<string>Client IP address or hostname:</string>
</property>
<property name="indent">
<number>20</number>
</property>
<item alignment="Qt::AlignTop">
<widget class="QWidget" name="m_pWidgetServer" native="true">
<layout class="QVBoxLayout" name="m_pLayoutServer">
<property name="spacing">
<number>15</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="m_pWidgetServerInverse" native="true">
<layout class="QVBoxLayout" name="m_pLayoutServerInverse">
<property name="spacing">
<number>15</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_pLabelClientIp">
<property name="text">
<string>Client IP address or hostname:</string>
</property>
<property name="indent">
<number>20</number>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>20</number>
</property>
<item>
<widget class="QLineEdit" name="m_pLineEditClientIp"/>
</item>
<item>
<widget class="QPushButton" name="m_pButtonConnectToClient">
<property name="text">
<string>Connect</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="synergy_widgets::ServerStateLabel" name="m_pLabelServerState">
<property name="text">
<string>No clients connected</string>
</property>
<property name="indent">
<number>20</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_pLabelFingerprint">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;TLS enabled (&lt;a href=&quot;#&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#4285f4;&quot;&gt;fingerprint&lt;/span&gt;&lt;/a&gt;)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="indent">
<number>20</number>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<spacer name="spacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="m_pButtonConfigureServer">
<property name="text">
<string>&amp;Configure</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>20</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="m_pLineEditClienIp"/>
</item>
<item>
<widget class="QPushButton" name="m_pButtonConnectToClient">
<property name="text">
<string>Connect</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="synergy_widgets::ServerStateLabel" name="m_pLabelServerState">
<property name="text">
<string>No clients connected</string>
</property>
<property name="indent">
<number>20</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="m_pLabelFingerprint">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;TLS enabled (&lt;a href=&quot;#&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#4285f4;&quot;&gt;fingerprint&lt;/span&gt;&lt;/a&gt;)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="indent">
<number>20</number>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="m_pButtonConfigureServer">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>&amp;Configure</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QFrame" name="m_pGroupClient">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>250</height>
</size>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">.QFrame{
@ -387,36 +300,15 @@ border-radius: 4px;
background-color: rgba(192,192,192, 0.1);
}</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<property name="spacing">
<number>15</number>
</property>
<property name="topMargin">
<number>11</number>
</property>
<item>
<item alignment="Qt::AlignTop">
<widget class="QRadioButton" name="m_pRadioGroupClient">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>300</width>
<height>30</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">QRadioButton::indicator{
top: -7px;
@ -424,18 +316,83 @@ background-color: rgba(192,192,192, 0.1);
</property>
<property name="text">
<string>Use another computer’s mouse and keyboard
(make this computer the client)</string>
(make this computer the &amp;client)</string>
</property>
</widget>
</item>
<item alignment="Qt::AlignTop">
<widget class="QWidget" name="m_pWidgetClient" native="true">
<layout class="QVBoxLayout" name="m_pLayoutClient">
<property name="spacing">
<number>15</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_pLabelServerName">
<property name="text">
<string>Server IP address or hostname:</string>
</property>
<property name="indent">
<number>20</number>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>20</number>
</property>
<item>
<widget class="QLineEdit" name="m_pLineEditHostname">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Hostname or IP address of the server computer.</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_pButtonConnect">
<property name="text">
<string>Connect</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="synergy_widgets::ClientStateLabel" name="m_pLabelClientState">
<property name="text">
<string>Connected to server</string>
</property>
<property name="indent">
<number>20</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_4">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
@ -444,104 +401,6 @@ background-color: rgba(192,192,192, 0.1);
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>19</number>
</property>
<property name="topMargin">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="m_pLabelServerName">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>&amp;Server IP address or hostname:</string>
</property>
<property name="buddy">
<cstring>m_pLineEditHostname</cstring>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="m_pLineEditHostname">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Hostname or IP address of the server computer.</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="synergy_widgets::ClientStateLabel" name="m_pLabelClientState">
<property name="text">
<string>Connected to server</string>
</property>
<property name="indent">
<number>20</number>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<property name="topMargin">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="m_pButtonConnect">
<property name="text">
<string>Connect</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
@ -687,28 +546,19 @@ background-color: rgba(192,192,192, 0.1);
</spacer>
</item>
<item>
<widget class="QLabel" name="m_trialLabel">
<property name="font">
<font>
<family>Arial</family>
<pointsize>-1</pointsize>
<bold>true</bold>
</font>
</property>
<widget class="QLabel" name="m_labelNotice">
<property name="autoFillBackground">
<bool>false</bool>
</property>
<property name="styleSheet">
<string notr="true">font-size: 13px;
font-weight: 700;
padding: 3px 5px;
<string notr="true">padding: 3px 5px;
border-radius: 3px;
background-color: #EC4C47;
background-color: #3B67D3;
color: #ffffff;
top: 3px;</string>
</property>
<property name="text">
<string notr="true"/>
<string notr="true">m_labelNotice</string>
</property>
<property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>

View file

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2013-2016 Symless Ltd.
* Copyright (C) 2013 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -17,7 +17,6 @@
#include "QUtility.h"
#include "CommandProcess.h"
#include "ProcessorArch.h"
#if defined(Q_OS_LINUX)

View file

@ -22,14 +22,13 @@
#include "Config.h"
#include "Hotkey.h"
#include "MainWindow.h"
#include "gui/constants.h"
#include <QAbstractButton>
#include <QMessageBox>
#include <QPushButton>
#include <QtCore>
using synergy::gui::Config;
static const struct {
int x;
int y;
@ -162,9 +161,6 @@ void ServerConfig::saveSettings() {
settings().endArray();
settings().endGroup();
m_pAppConfig->saveSettings();
m_pAppConfig->config().markUnsaved();
}
void ServerConfig::loadSettings() {
@ -541,7 +537,7 @@ size_t ServerConfig::setClipboardSharingSize(size_t size) {
}
void ServerConfig::setClientAddress(const QString &address) {
if (m_pAppConfig->serverClientMode()) {
if (m_pAppConfig->invertConnection()) {
m_ClientAddress = address;
}
}
@ -549,7 +545,7 @@ void ServerConfig::setClientAddress(const QString &address) {
QString ServerConfig::getClientAddress() const {
QString clientAddress;
if (m_pAppConfig->serverClientMode()) {
if (m_pAppConfig->invertConnection()) {
clientAddress = m_ClientAddress.trimmed();
}
@ -559,11 +555,3 @@ QString ServerConfig::getClientAddress() const {
QSettings &ServerConfig::settings() {
return *m_pAppConfig->config().currentSettings();
}
bool ServerConfig::isHotkeysAvailable() const {
#ifdef SYNERGY_ENABLE_LICENSING
return (m_pAppConfig->edition() != Edition::kLite);
#else
return true;
#endif
}

View file

@ -81,7 +81,6 @@ public:
bool isFull() const;
bool isScreenExists(const QString &screenName) const;
void addClient(const QString &clientName);
bool isHotkeysAvailable() const;
QString getClientAddress() const;
void setClientAddress(const QString &address);

View file

@ -22,7 +22,8 @@
#include "ScreenSettingsDialog.h"
#include "ServerConfig.h"
#include "UpgradeDialog.h"
#include "shared/EditionType.h"
#include "gui/constants.h"
#include "license/ProductEdition.h"
#include <QFileDialog>
#include <QMessageBox>
@ -273,27 +274,12 @@ void ServerConfigDialog::reject() {
}
void ServerConfigDialog::on_m_pButtonNewHotkey_clicked() {
if (serverConfig().isHotkeysAvailable()) {
Hotkey hotkey;
HotkeyDialog dlg(this, hotkey);
if (dlg.exec() == QDialog::Accepted) {
serverConfig().hotkeys().append(hotkey);
m_pListHotkeys->addItem(hotkey.text());
onChange();
}
} else {
#ifdef SYNERGY_ENABLE_LICENSING
auto edition = appConfig().edition();
if (edition == Edition::kLite || edition == Edition::kBasic) {
UpgradeDialog upgradeDialog(this);
if (appConfig().edition() == Edition::kLite) {
upgradeDialog.showDialog(
"Upgrade to Synergy 1 Ultimate to enable hotkeys");
} else if (appConfig().edition() == Edition::kBasic) {
upgradeDialog.showDialog("Upgrade to Synergy 1 Pro to enable hotkeys");
}
}
#endif // SYNERGY_ENABLE_LICENSING
Hotkey hotkey;
HotkeyDialog dlg(this, hotkey);
if (dlg.exec() == QDialog::Accepted) {
serverConfig().hotkeys().append(hotkey);
m_pListHotkeys->addItem(hotkey.text());
onChange();
}
}

View file

@ -20,11 +20,9 @@
#include "AppConfig.h"
#include "MainWindow.h"
#include "SslCertificate.h"
#ifdef SYNERGY_ENABLE_LICENSING
#include "UpgradeDialog.h"
#endif // SYNERGY_ENABLE_LICENSING
#include "gui/TlsCertificate.h"
#include "gui/constants.h"
#include <QDir>
#include <QFileDialog>
@ -33,13 +31,20 @@
#include <QtGui>
#include <memory>
SettingsDialog::SettingsDialog(QWidget *parent, AppConfig &config)
using namespace synergy::license;
const char *const kProProductName = "Synergy 1 Pro";
SettingsDialog::SettingsDialog(
QWidget *parent, AppConfig &config, const License &license)
: QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
Ui::SettingsDialogBase(),
m_appConfig(config) {
m_appConfig(config),
m_license(license),
m_tlsUtility(config, license) {
setupUi(this);
// TODO: maybe just accept MainWindow type in ctor?
m_pMainWindow = dynamic_cast<MainWindow *>(parent);
loadFromConfig();
@ -79,9 +84,6 @@ SettingsDialog::SettingsDialog(QWidget *parent, AppConfig &config)
connect(m_pCheckBoxLanguageSync, SIGNAL(clicked()), this, SLOT(onChange()));
connect(
m_pCheckBoxScrollDirection, SIGNAL(clicked()), this, SLOT(onChange()));
connect(m_pCheckBoxClientHostMode, SIGNAL(clicked()), this, SLOT(onChange()));
connect(
m_pCheckBoxServerClientMode, SIGNAL(clicked()), this, SLOT(onChange()));
adjustSize();
}
@ -106,13 +108,12 @@ void SettingsDialog::accept() {
appConfig().setMinimizeToTray(m_pCheckBoxMinimizeToTray->isChecked());
appConfig().setTlsCertPath(m_pLineEditCertificatePath->text());
appConfig().setTlsKeyLength(m_pComboBoxKeyLength->currentText());
appConfig().setCryptoEnabled(m_pCheckBoxEnableCrypto->isChecked());
appConfig().setTlsEnabled(m_pCheckBoxEnableCrypto->isChecked());
appConfig().setLanguageSync(m_pCheckBoxLanguageSync->isChecked());
appConfig().setInvertScrollDirection(m_pCheckBoxScrollDirection->isChecked());
appConfig().setClientHostMode(m_pCheckBoxClientHostMode->isChecked());
appConfig().setServerClientMode(m_pCheckBoxServerClientMode->isChecked());
appConfig().setServiceEnabled(m_pCheckBoxServiceEnabled->isChecked());
appConfig().setCloseToTray(m_pCheckBoxCloseToTray->isChecked());
appConfig().setInvertConnection(m_pInvertConnection->isChecked());
appConfig().saveSettings();
QDialog::accept();
@ -139,11 +140,9 @@ void SettingsDialog::loadFromConfig() {
m_pCheckBoxPreventSleep->setChecked(appConfig().preventSleep());
m_pCheckBoxMinimizeToTray->setChecked(appConfig().minimizeToTray());
m_pLineEditCertificatePath->setText(appConfig().tlsCertPath());
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.cryptoEnabled());
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.tlsEnabled());
m_pCheckBoxLanguageSync->setChecked(m_appConfig.languageSync());
m_pCheckBoxScrollDirection->setChecked(m_appConfig.invertScrollDirection());
m_pCheckBoxClientHostMode->setChecked(m_appConfig.clientHostMode());
m_pCheckBoxServerClientMode->setChecked(m_appConfig.serverClientMode());
m_pCheckBoxServiceEnabled->setChecked(m_appConfig.serviceEnabled());
m_pCheckBoxCloseToTray->setChecked(m_appConfig.closeToTray());
@ -153,6 +152,10 @@ void SettingsDialog::loadFromConfig() {
m_pRadioUserScope->setChecked(true);
}
m_pInvertConnection->setChecked(m_appConfig.invertConnection());
m_pInvertConnection->setEnabled(
m_license.productEdition() == Edition::kBusiness);
updateTlsControls();
}
@ -164,20 +167,20 @@ void SettingsDialog::updateTlsControls() {
m_pComboBoxKeyLength->findText(appConfig().tlsKeyLength()));
}
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.cryptoEnabled());
m_pCheckBoxEnableCrypto->setChecked(m_appConfig.tlsEnabled());
updateTlsControlsEnabled();
}
void SettingsDialog::updateTlsControlsEnabled() {
auto clientMode = appConfig().clientGroupChecked();
auto cryptoAvailable = appConfig().cryptoAvailable();
auto tlsAvailable = m_tlsUtility.isAvailableAndEnabled();
auto tlsChecked = m_pCheckBoxEnableCrypto->isChecked();
auto enabled = !clientMode && cryptoAvailable && tlsChecked;
auto enabled = !clientMode && tlsAvailable && tlsChecked;
qDebug(
"TLS controls enabled=%d, client=%d, crypto=%d, checked=%d", enabled,
clientMode, cryptoAvailable, tlsChecked);
"TLS controls enabled=%d, client=%d, available=%d, checked=%d", enabled,
clientMode, tlsAvailable, tlsChecked);
m_pLabelKeyLength->setEnabled(enabled);
m_pComboBoxKeyLength->setEnabled(enabled);
@ -209,24 +212,17 @@ void SettingsDialog::on_m_pButtonBrowseLog_clicked() {
}
}
void SettingsDialog::on_m_pCheckBoxEnableCrypto_clicked(bool checked) {
void SettingsDialog::on_m_pCheckBoxEnableCrypto_clicked(bool) {
updateTlsControlsEnabled();
if (!appConfig().cryptoAvailable()) {
#ifdef SYNERGY_ENABLE_LICENSING
auto edition = appConfig().edition();
if (edition == Edition::kLite || edition == Edition::kBasic) {
if (kLicensingEnabled && !m_tlsUtility.isAvailable()) {
auto edition = m_license.productEdition();
if (edition == Edition::kBasic) {
UpgradeDialog upgradeDialog(this);
if (appConfig().edition() == Edition::kLite) {
upgradeDialog.showDialog(
"Upgrade to Synergy Ultimate to enable TLS encryption.");
} else if (appConfig().edition() == Edition::kBasic) {
upgradeDialog.showDialog(
"Upgrade to Synergy Pro to enable TLS encryption.");
}
upgradeDialog.showDialog(
QString("Upgrade to %1 to enable TLS encryption.")
.arg(kProProductName));
}
#endif // SYNERGY_ENABLE_LICENSING
}
}
@ -271,11 +267,11 @@ void SettingsDialog::updateTlsRegenerateButton() {
}
void SettingsDialog::on_m_pPushButtonRegenCert_clicked() {
appConfig().generateCertificate(true);
m_tlsUtility.generateCertificate(true);
}
void SettingsDialog::updateKeyLengthOnFile(const QString &path) {
SslCertificate ssl;
TlsCertificate ssl;
auto length = ssl.getCertKeyLength(path);
auto index = m_pComboBoxKeyLength->findText(length);
m_pComboBoxKeyLength->setCurrentIndex(index);
@ -299,8 +295,6 @@ void SettingsDialog::updateControlsEnabled() {
m_pComboBoxKeyLength->setEnabled(writable);
m_pPushButtonBrowseCert->setEnabled(writable);
m_pCheckBoxEnableCrypto->setEnabled(writable);
m_pCheckBoxClientHostMode->setEnabled(writable);
m_pCheckBoxServerClientMode->setEnabled(writable);
m_pCheckBoxServiceEnabled->setEnabled(writable);
m_pCheckBoxCloseToTray->setEnabled(writable);
@ -311,12 +305,6 @@ void SettingsDialog::updateControlsEnabled() {
m_pCheckBoxServiceEnabled->setEnabled(false);
#endif
m_pCheckBoxClientHostMode->setEnabled(
writable && isClientMode() && appConfig().initiateConnectionFromServer());
m_pCheckBoxServerClientMode->setEnabled(
writable && !isClientMode() &&
appConfig().initiateConnectionFromServer());
m_pLabelLogPath->setEnabled(writable && m_pCheckBoxLogToFile->isChecked());
m_pLineEditLogFilename->setEnabled(
writable && m_pCheckBoxLogToFile->isChecked());

View file

@ -18,9 +18,11 @@
#pragma once
#include "gui/TlsUtility.h"
#include "ui_SettingsDialogBase.h"
#include "CoreInterface.h"
#include "gui/CoreInterface.h"
#include "license/License.h"
#include "validators/ScreenNameValidator.h"
#include <QDialog>
@ -33,7 +35,9 @@ class SettingsDialog : public QDialog, public Ui::SettingsDialogBase {
Q_OBJECT
public:
SettingsDialog(QWidget *parent, AppConfig &config);
SettingsDialog(
QWidget *parent, AppConfig &config,
const synergy::license::License &license);
static QString browseForSynergyc(
QWidget *parent, const QString &programDir,
const QString &coreClientName);
@ -63,9 +67,12 @@ protected:
void updateTlsControlsEnabled();
private:
QString m_nameError = "";
MainWindow *m_pMainWindow;
AppConfig &m_appConfig;
CoreInterface m_CoreInterface;
CoreInterface m_coreInterface;
const synergy::license::License &m_license;
synergy::gui::TlsUtility m_tlsUtility;
std::unique_ptr<validators::ScreenNameValidator> m_screenNameValidator;
/// @brief Stores settings scope at start of settings dialog
@ -73,8 +80,6 @@ private:
/// the scope and doesn't save changes
bool m_isSystemAtStart = false;
QString m_nameError = "";
private slots:
void on_m_pCheckBoxEnableCrypto_clicked(bool checked);
void on_m_pCheckBoxLogToFile_stateChanged(int);

View file

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>417</width>
<height>786</height>
<width>500</width>
<height>830</height>
</rect>
</property>
<property name="sizePolicy">
@ -38,195 +38,6 @@
<property name="verticalSpacing">
<number>5</number>
</property>
<item row="6" column="0">
<widget class="QFrame" name="m_pGroupLog1">
<property name="styleSheet">
<string notr="true">.QFrame{
border: 1px solid rgba(192,192,192, 0.2);
border-radius: 4px;
background-color: rgba(192,192,192, 0.1);
}
</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="topMargin">
<number>15</number>
</property>
<property name="bottomMargin">
<number>15</number>
</property>
<property name="verticalSpacing">
<number>7</number>
</property>
<item row="0" column="1">
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="m_pCheckBoxLogToFile">
<property name="text">
<string>Log to file</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QComboBox" name="m_pComboLogLevel">
<item>
<property name="text">
<string>Info</string>
</property>
</item>
<item>
<property name="text">
<string>Debug</string>
</property>
</item>
<item>
<property name="text">
<string>Debug1</string>
</property>
</item>
<item>
<property name="text">
<string>Debug2</string>
</property>
</item>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="m_pLabel_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Level</string>
</property>
<property name="buddy">
<cstring>m_pComboLogLevel</cstring>
</property>
</widget>
</item>
<item row="1" column="0" colspan="4">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
<number>3</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_pLabelLogPath">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Log path</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>30</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLineEdit" name="m_pLineEditLogFilename">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_pButtonBrowseLog">
<property name="enabled">
<bool>false</bool>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="styleSheet">
<string notr="true">margin: 0px; padding: 0px;</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../res/Synergy.qrc">
<normaloff>:/res/icons/64x64/folder.png</normaloff>:/res/icons/64x64/folder.png</iconset>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>13</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="m_pLabelGroupScope">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Use settings profile from</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QFrame" name="m_pGroupBoxCommon">
<property name="styleSheet">
@ -238,10 +49,10 @@ background-color: rgba(192,192,192, 0.1);
</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
<enum>QFrame::Shape::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
<enum>QFrame::Shadow::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="topMargin">
@ -277,10 +88,10 @@ background-color: rgba(192,192,192, 0.1);
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Maximum</enum>
<enum>QSizePolicy::Policy::Maximum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -382,7 +193,7 @@ background-color: rgba(192,192,192, 0.1);
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -413,7 +224,7 @@ background-color: rgba(192,192,192, 0.1);
</size>
</property>
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
<enum>Qt::LayoutDirection::LeftToRight</enum>
</property>
<property name="text">
<string>Minimize to system &amp;tray</string>
@ -432,26 +243,13 @@ background-color: rgba(192,192,192, 0.1);
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="m_pLabelGroupNetwork">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Security</string>
</property>
</widget>
</item>
<item row="8" column="0">
<spacer name="verticalSpacer_5">
<item row="1" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -461,6 +259,61 @@ background-color: rgba(192,192,192, 0.1);
</property>
</spacer>
</item>
<item row="12" column="0">
<widget class="QLabel" name="m_pLabelGroupAdvanced">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Advanced</string>
</property>
</widget>
</item>
<item row="11" column="0">
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>3</height>
</size>
</property>
</spacer>
</item>
<item row="15" column="0">
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0">
<widget class="QLabel" name="m_pLabelGroupLog">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Logs</string>
</property>
</widget>
</item>
<item row="13" column="0">
<widget class="QFrame" name="m_pGroupAdvanced">
<property name="sizePolicy">
@ -478,34 +331,44 @@ background-color: rgba(192,192,192, 0.1);
</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
<enum>QFrame::Shape::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
<enum>QFrame::Shadow::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="7" column="0" colspan="3">
<item row="1" column="0">
<widget class="QCheckBox" name="m_pCheckBoxPreventSleep">
<property name="text">
<string>Stop this computer from sleeping</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="m_pCheckBoxScrollDirection">
<property name="text">
<string>Invert scroll direction on this computer (client mode)</string>
</property>
</widget>
</item>
<item row="8" column="0" colspan="3">
<item row="9" column="0">
<widget class="QCheckBox" name="m_pInvertConnection">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Invert server/client TCP connection (business edition)</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="m_pCheckBoxLanguageSync">
<property name="text">
<string>Use server's keyboard language on this computer (client mode)</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="m_pCheckBoxServiceEnabled">
<property name="text">
<string>Use background service (daemon)</string>
</property>
</widget>
</item>
<item row="3" column="0" rowspan="3" colspan="2">
<item row="4" column="0" rowspan="3" colspan="2">
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QLabel" name="m_pLabelElevate">
@ -559,46 +422,87 @@ background-color: rgba(192,192,192, 0.1);
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="m_pCheckBoxPreventSleep">
<item row="2" column="0">
<widget class="QCheckBox" name="m_pCheckBoxServiceEnabled">
<property name="text">
<string>Stop this computer from sleeping</string>
<string>Use background service (daemon)</string>
</property>
</widget>
</item>
<item row="9" column="0" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout_8">
<property name="sizeConstraint">
<enum>QLayout::SetNoConstraint</enum>
</layout>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="m_pLabelGroupScope">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Use settings profile from</string>
</property>
</widget>
</item>
<item row="4" column="0">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>3</height>
</size>
</property>
</spacer>
</item>
<item row="10" column="0">
<widget class="QFrame" name="m_pGroupScope">
<property name="styleSheet">
<string notr="true">.QFrame{
border: 1px solid rgba(192,192,192, 0.2);
border-radius: 4px;
background-color: rgba(192,192,192, 0.1);
}
</string>
</property>
<property name="frameShape">
<enum>QFrame::Shape::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Shadow::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="topMargin">
<number>15</number>
</property>
<property name="bottomMargin">
<number>15</number>
</property>
<property name="verticalSpacing">
<number>6</number>
</property>
<item row="0" column="1">
<widget class="QRadioButton" name="m_pRadioSystemScope">
<property name="text">
<string>All users</string>
</property>
<item>
<widget class="QCheckBox" name="m_pCheckBoxServerClientMode">
<property name="text">
<string>Use server as a client</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="m_pCheckBoxClientHostMode">
<property name="text">
<string>Use client in host mode</string>
</property>
</widget>
</item>
</layout>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="m_pRadioUserScope">
<property name="text">
<string>Current user</string>
</property>
</widget>
</item>
</layout>
</widget>
@ -614,10 +518,10 @@ background-color: rgba(192,192,192, 0.1);
</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
<enum>QFrame::Shape::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
<enum>QFrame::Shadow::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
@ -647,7 +551,7 @@ background-color: rgba(192,192,192, 0.1);
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -715,10 +619,10 @@ background-color: rgba(192,192,192, 0.1);
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Minimum</enum>
<enum>QSizePolicy::Policy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -774,7 +678,7 @@ background-color: rgba(192,192,192, 0.1);
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -796,63 +700,18 @@ background-color: rgba(192,192,192, 0.1);
</layout>
</widget>
</item>
<item row="12" column="0">
<widget class="QLabel" name="m_pLabelGroupAdvanced">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
<item row="19" column="0">
<widget class="QDialogButtonBox" name="m_pButtonBox">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="text">
<string>Advanced</string>
<property name="standardButtons">
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Save</set>
</property>
</widget>
</item>
<item row="14" column="0">
<spacer name="verticalSpacer_6">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0">
<widget class="QLabel" name="m_pLabelGroupLog">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Logs</string>
</property>
</widget>
</item>
<item row="4" column="0">
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>3</height>
</size>
</property>
</spacer>
</item>
<item row="10" column="0">
<widget class="QFrame" name="m_pGroupScope">
<item row="6" column="0">
<widget class="QFrame" name="m_pGroupLog1">
<property name="styleSheet">
<string notr="true">.QFrame{
border: 1px solid rgba(192,192,192, 0.2);
@ -862,12 +721,12 @@ background-color: rgba(192,192,192, 0.1);
</string>
</property>
<property name="frameShape">
<enum>QFrame::StyledPanel</enum>
<enum>QFrame::Shape::StyledPanel</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
<enum>QFrame::Shadow::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<layout class="QGridLayout" name="gridLayout">
<property name="topMargin">
<number>15</number>
</property>
@ -875,61 +734,178 @@ background-color: rgba(192,192,192, 0.1);
<number>15</number>
</property>
<property name="verticalSpacing">
<number>6</number>
<number>7</number>
</property>
<item row="0" column="1">
<widget class="QRadioButton" name="m_pRadioSystemScope">
<property name="text">
<string>All users</string>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="checked">
<bool>true</bool>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="m_pCheckBoxLogToFile">
<property name="text">
<string>Log to file</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="m_pRadioUserScope">
<item row="0" column="3">
<widget class="QComboBox" name="m_pComboLogLevel">
<item>
<property name="text">
<string>Info</string>
</property>
</item>
<item>
<property name="text">
<string>Debug</string>
</property>
</item>
<item>
<property name="text">
<string>Debug1</string>
</property>
</item>
<item>
<property name="text">
<string>Debug2</string>
</property>
</item>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="m_pLabel_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Current user</string>
<string>Level</string>
</property>
<property name="buddy">
<cstring>m_pComboLogLevel</cstring>
</property>
</widget>
</item>
<item row="1" column="0" colspan="4">
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
<number>3</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="m_pLabelLogPath">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Log path</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::Minimum</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>30</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLineEdit" name="m_pLineEditLogFilename">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="m_pButtonBrowseLog">
<property name="enabled">
<bool>false</bool>
</property>
<property name="cursor">
<cursorShape>PointingHandCursor</cursorShape>
</property>
<property name="styleSheet">
<string notr="true">margin: 0px; padding: 0px;</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../res/Synergy.qrc">
<normaloff>:/res/icons/64x64/folder.png</normaloff>:/res/icons/64x64/folder.png</iconset>
</property>
<property name="iconSize">
<size>
<width>20</width>
<height>13</height>
</size>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item row="18" column="0">
<widget class="QDialogButtonBox" name="m_pButtonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
<item row="2" column="0">
<widget class="QLabel" name="m_pLabelGroupNetwork">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
<property name="text">
<string>Security</string>
</property>
</widget>
</item>
<item row="11" column="0">
<spacer name="verticalSpacer_3">
<item row="8" column="0">
<spacer name="verticalSpacer_5">
<property name="orientation">
<enum>Qt::Vertical</enum>
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>3</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
<enum>QSizePolicy::Policy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
@ -962,10 +938,6 @@ background-color: rgba(192,192,192, 0.1);
<tabstop>m_pCheckBoxPreventSleep</tabstop>
<tabstop>m_pCheckBoxServiceEnabled</tabstop>
<tabstop>m_pComboElevate</tabstop>
<tabstop>m_pCheckBoxScrollDirection</tabstop>
<tabstop>m_pCheckBoxLanguageSync</tabstop>
<tabstop>m_pCheckBoxServerClientMode</tabstop>
<tabstop>m_pCheckBoxClientHostMode</tabstop>
</tabstops>
<resources>
<include location="../res/Synergy.qrc"/>

View file

@ -1,3 +1,20 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "TrayIcon.h"
void TrayIcon::tryCreate() const {

View file

@ -1,4 +1,22 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QMenu>
#include <QObject>
#include <QSystemTrayIcon>

View file

@ -17,11 +17,11 @@
*/
#include "AppConfig.h"
#include "LicenseManager.h"
#include "MainWindow.h"
#include "QSynergyApplication.h"
#include "SetupWizard.h"
#include "SetupWizardBlocker.h"
#include "gui/dotenv.h"
#include <QMessageBox>
#include <QtCore>
@ -29,9 +29,6 @@
#if defined(Q_OS_MAC)
#include <Carbon/Carbon.h>
#endif
#ifdef Q_OS_DARWIN
#include <cstdlib>
#endif
@ -55,6 +52,8 @@ int main(int argc, char *argv[]) {
::setenv("QT_BEARER_POLL_TIMEOUT", "-1", 1);
#endif
dotenv(".env");
QCoreApplication::setOrganizationName("Synergy");
QCoreApplication::setOrganizationDomain("http://symless.com/");
QCoreApplication::setApplicationName("Synergy");
@ -79,16 +78,11 @@ int main(int argc, char *argv[]) {
AppConfig appConfig;
qRegisterMetaType<Edition>("Edition");
#ifdef SYNERGY_ENABLE_LICENSING
LicenseManager licenseManager(&appConfig);
MainWindow mainWindow(appConfig, licenseManager);
#else
MainWindow mainWindow(appConfig);
#endif
QObject::connect(
dynamic_cast<QObject *>(&app), SIGNAL(aboutToQuit()), &mainWindow,
SLOT(saveSettings()));
&app, &QSynergyApplication::aboutToQuit, &mainWindow,
&MainWindow::onAppAboutToQuit);
std::unique_ptr<SetupWizardBlocker> setupBlocker;
if (qgetenv("XDG_SESSION_TYPE") == "wayland") {

View file

@ -35,14 +35,10 @@ void ServerStateLabel::updateServerState(const QString &line) {
m_clients.removeAll(message.getClientName());
}
updateState();
}
void ServerStateLabel::updateState() {
if (m_clients.isEmpty()) {
show();
setText(tr("No clients connected"));
} else {
hide();
setText(tr("Connected clients: %1").arg(m_clients.join(", ")));
}
}

View file

@ -25,5 +25,6 @@ add_subdirectory(net)
add_subdirectory(platform)
add_subdirectory(server)
add_subdirectory(synergy)
add_subdirectory(shared)
add_subdirectory(global)
add_subdirectory(license)
add_subdirectory(gui)

View file

@ -56,7 +56,7 @@
Client::Client(
IEventQueue *events, const String &name, const NetworkAddress &address,
ISocketFactory *socketFactory, synergy::Screen *screen,
lib::synergy::ClientArgs const &args)
synergy::ClientArgs const &args)
: m_mock(false),
m_name(name),
m_serverAddress(address),

View file

@ -65,7 +65,7 @@ public:
Client(
IEventQueue *events, const String &name, const NetworkAddress &address,
ISocketFactory *socketFactory, synergy::Screen *screen,
lib::synergy::ClientArgs const &args);
synergy::ClientArgs const &args);
Client(Client const &) = delete;
Client(Client &&) = delete;
~Client();
@ -248,6 +248,6 @@ private:
bool m_useSecureNetwork;
bool m_enableClipboard;
size_t m_maximumClipboardSize;
lib::synergy::ClientArgs m_args;
synergy::ClientArgs m_args;
size_t m_resolvedAddressesCount = 0;
};

View file

@ -21,6 +21,6 @@ if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()
add_library(shared STATIC ${sources})
add_library(global STATIC ${sources})
target_link_libraries(shared arch base)
target_link_libraries(global)

View file

@ -30,7 +30,8 @@ endif()
add_library(${target} STATIC ${sources})
target_link_libraries(
${target}
shared
global
license
Qt6::Core
Qt6::Widgets
Qt6::Network)

View file

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
* Copyright (C) 2014 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -20,8 +20,8 @@
#include <QProcess>
CommandProcess::CommandProcess(
QString cmd, QStringList arguments, QString input)
: m_Command(cmd),
QString command, QStringList arguments, QString input)
: m_Command(command),
m_Arguments(arguments),
m_Input(input) {}

View file

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2014-2016 Symless Ltd.
* Copyright (C) 2014 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View file

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
* Copyright (C) 2015 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "CoreInterface.h"
#include "gui/CoreInterface.h"
#include "CommandProcess.h"
@ -32,22 +32,22 @@ static const char kSerialKeyFilename[] = "Synergy.subkey";
static const char kSerialKeyFilename[] = ".synergy.subkey";
#endif
QString CoreInterface::getProfileDir() {
QString CoreInterface::getProfileDir() const {
QStringList args("--get-profile-dir");
return QDir::cleanPath(run(args));
}
QString CoreInterface::getInstalledDir() {
QString CoreInterface::getInstalledDir() const {
QStringList args("--get-installed-dir");
return QDir::cleanPath(run(args));
}
QString CoreInterface::getArch() {
QString CoreInterface::getArch() const {
QStringList args("--get-arch");
return run(args);
}
QString CoreInterface::getSerialKeyFilePath() {
QString CoreInterface::getSerialKeyFilePath() const {
auto filename = getProfileDir() + QDir::separator() + kSerialKeyFilename;
return QDir::cleanPath(filename);
}

View file

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
* Copyright (C) 2015 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -21,9 +21,9 @@
class CoreInterface {
public:
QString getProfileDir();
QString getInstalledDir();
QString getArch();
QString getSerialKeyFilePath();
QString getProfileDir() const;
QString getInstalledDir() const;
QString getArch() const;
QString getSerialKeyFilePath() const;
QString run(const QStringList &args, const QString &input = "") const;
};

View file

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2022 Synergy Ltd.
* 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
@ -14,30 +14,19 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QNetworkAccessManager>
#include <QObject>
#include <QTimer>
#include <QString>
class QNetworkReply;
class AppConfig;
class LicenseRegistry : public QObject {
Q_OBJECT
namespace synergy::gui {
class IAppConfig {
public:
explicit LicenseRegistry(AppConfig &config);
void scheduleRegistration();
public slots:
void registerLicense();
void handleResponse(QNetworkReply *reply);
private:
AppConfig &m_config;
QNetworkAccessManager m_manager;
QTimer m_timer;
QByteArray getRequestData() const;
virtual ~IAppConfig() = default;
virtual QString tlsCertPath() const = 0;
virtual QString tlsKeyLength() const = 0;
virtual bool tlsEnabled() const = 0;
};
} // namespace synergy::gui

View file

@ -1,7 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* Copyright (C) 2012 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -17,7 +16,8 @@
*/
#include "IpcReader.h"
#include "shared/Ipc.h"
#include "global/Ipc.h"
#include <QByteArray>
#include <QMutex>
#include <QTcpSocket>

View file

@ -1,7 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* Copyright (C) 2012 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License

View file

@ -0,0 +1,94 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015 Synergy 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 <http://www.gnu.org/licenses/>.
*/
#include "LicenseHandler.h"
#include "license/ProductEdition.h"
#include "license/parse_serial_key.h"
#include <QDebug>
#include <QProcessEnvironment>
#include <QTimer>
using namespace std::chrono;
using namespace synergy::license;
const License &LicenseHandler::license() const { return m_license; }
Edition LicenseHandler::productEdition() const {
return m_license.productEdition();
}
QString LicenseHandler::productName() const {
return QString::fromStdString(m_license.productName());
}
LicenseHandler::ChangeSerialKeyResult
LicenseHandler::changeSerialKey(const QString &hexString) {
using enum LicenseHandler::ChangeSerialKeyResult;
if (hexString.isEmpty()) {
qFatal("serial key is empty");
return kFatal;
}
qDebug() << "changing serial key to:" << hexString;
auto serialKey = parseSerialKey(hexString.toStdString());
if (serialKey == m_license.serialKey()) {
qDebug("serial key did not change, ignoring");
return kUnchanged;
}
if (!serialKey.isValid) {
qDebug() << "invalid serial key, ignoring";
return kInvalid;
}
const auto license = License(serialKey);
if (license.isExpired()) {
qDebug("license is expired, ignoring");
return kExpired;
}
m_license = license;
emit serialKeyChanged(hexString);
if (m_license.isSubscription()) {
auto daysLeft = m_license.daysLeft();
auto msLeft = duration_cast<milliseconds>(daysLeft);
if (msLeft.count() < INT_MAX) {
QTimer::singleShot(msLeft, this, SLOT(validateLicense()));
} else {
qDebug("license expiry too distant to schedule timer");
}
}
return kSuccess;
}
void LicenseHandler::validate() const {
if (!m_license.isValid()) {
qDebug("license validation failed, license invalid");
emit invalidLicense();
}
if (m_license.isExpired()) {
qDebug("license validation failed, license expired");
emit invalidLicense();
}
}

View file

@ -0,0 +1,54 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015 Synergy 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "license/License.h"
#include "license/ProductEdition.h"
#include <QObject>
/**
* @brief A convenience wrapper for `License` that provides Qt signals, etc.
*/
class LicenseHandler : public QObject {
Q_OBJECT
using License = synergy::license::License;
using SerialKey = synergy::license::SerialKey;
public:
enum class ChangeSerialKeyResult {
kSuccess,
kFatal,
kUnchanged,
kInvalid,
kExpired,
};
Edition productEdition() const;
const License &license() const;
void validate() const;
QString productName() const;
ChangeSerialKeyResult changeSerialKey(const QString &hexString);
signals:
void serialKeyChanged(const QString &serialKey) const;
void invalidLicense() const;
private:
License m_license = License::invalid();
};

View file

@ -1,3 +1,20 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2024 Synergy 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 <http://www.gnu.org/licenses/>.
*/
#include <QTcpSocket>
/**

View file

@ -18,7 +18,7 @@
#include "QIpcClient.h"
#include "IpcReader.h"
#include "shared/Ipc.h"
#include "global/Ipc.h"
#include <QDataStream>
#include <QHostAddress>

View file

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
* Copyright (C) 2015 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -15,9 +15,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "SslCertificate.h"
#include "TlsCertificate.h"
#include "Fingerprint.h"
#include "TlsFingerprint.h"
#include <QCoreApplication>
#include <QDir>
@ -89,14 +89,14 @@ QString openSslWindowsBinary() {
using namespace synergy::gui;
SslCertificate::SslCertificate(QObject *parent) : QObject(parent) {
TlsCertificate::TlsCertificate(QObject *parent) : QObject(parent) {
m_ProfileDir = m_CoreInterface.getProfileDir();
if (m_ProfileDir.isEmpty()) {
emit error(tr("Failed to get profile directory."));
}
}
bool SslCertificate::runTool(const QStringList &args) {
bool TlsCertificate::runTool(const QStringList &args) {
QString program;
#if defined(Q_OS_WIN)
program = openSslWindowsBinary();
@ -134,7 +134,7 @@ bool SslCertificate::runTool(const QStringList &args) {
return true;
}
void SslCertificate::generateCertificate(
void TlsCertificate::generateCertificate(
const QString &path, const QString &keyLength, bool forceGen) {
QString sslDirPath =
QString("%1%2%3").arg(m_ProfileDir).arg(QDir::separator()).arg(kSslDir);
@ -193,7 +193,7 @@ void SslCertificate::generateCertificate(
emit generateFinished();
}
void SslCertificate::generateFingerprint(const QString &certificateFilename) {
void TlsCertificate::generateFingerprint(const QString &certificateFilename) {
QStringList arguments;
arguments.append("x509");
arguments.append("-fingerprint");
@ -212,14 +212,14 @@ void SslCertificate::generateFingerprint(const QString &certificateFilename) {
i++;
QString fingerprint = m_ToolOutput.mid(i, m_ToolOutput.size() - i);
Fingerprint::local().trust(fingerprint, false);
TlsFingerprint::local().trust(fingerprint, false);
emit info(tr("SSL fingerprint generated."));
} else {
emit error(tr("Failed to find SSL fingerprint."));
}
}
QString SslCertificate::getCertKeyLength(const QString &path) {
QString TlsCertificate::getCertKeyLength(const QString &path) {
QStringList arguments;
arguments.append("rsa");

View file

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
* Copyright (C) 2015 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -17,16 +17,15 @@
#pragma once
#include "CoreInterface.h"
#include "gui/CoreInterface.h"
#include <QObject>
#include <base/String.h>
class SslCertificate : public QObject {
class TlsCertificate : public QObject {
Q_OBJECT
public:
explicit SslCertificate(QObject *parent = 0);
explicit TlsCertificate(QObject *parent = nullptr);
public slots:
/// @brief Generates a TLS cert and private key

View file

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
* Copyright (C) 2015 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -15,9 +15,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "Fingerprint.h"
#include "TlsFingerprint.h"
#include "CoreInterface.h"
#include "gui/CoreInterface.h"
#include <QDir>
#include <QTextStream>
@ -27,10 +27,12 @@ static const char kLocalFilename[] = "Local.txt";
static const char kTrustedServersFilename[] = "TrustedServers.txt";
static const char kTrustedClientsFilename[] = "TrustedClients.txt";
Fingerprint::Fingerprint(const QString &filename) { m_Filename = filename; }
TlsFingerprint::TlsFingerprint(const QString &filename) {
m_Filename = filename;
}
void Fingerprint::trust(const QString &fingerprintText, bool append) {
Fingerprint::persistDirectory();
void TlsFingerprint::trust(const QString &fingerprintText, bool append) {
TlsFingerprint::persistDirectory();
QIODevice::OpenMode openMode;
if (append) {
@ -47,8 +49,8 @@ void Fingerprint::trust(const QString &fingerprintText, bool append) {
}
}
bool Fingerprint::fileExists() const {
QString dirName = Fingerprint::directoryPath();
bool TlsFingerprint::fileExists() const {
QString dirName = TlsFingerprint::directoryPath();
if (!QDir(dirName).exists()) {
return false;
}
@ -57,7 +59,7 @@ bool Fingerprint::fileExists() const {
return file.exists();
}
bool Fingerprint::isTrusted(const QString &fingerprintText) {
bool TlsFingerprint::isTrusted(const QString &fingerprintText) {
QStringList list = readList();
foreach (QString trusted, list) {
if (trusted == fingerprintText) {
@ -67,10 +69,10 @@ bool Fingerprint::isTrusted(const QString &fingerprintText) {
return false;
}
QStringList Fingerprint::readList(const int readTo) {
QStringList TlsFingerprint::readList(const int readTo) {
QStringList list;
QString dirName = Fingerprint::directoryPath();
QString dirName = TlsFingerprint::directoryPath();
if (!QDir(dirName).exists()) {
return list;
}
@ -91,36 +93,38 @@ QStringList Fingerprint::readList(const int readTo) {
return list;
}
QString Fingerprint::readFirst() {
QString TlsFingerprint::readFirst() {
QStringList list = readList(1);
return list.at(0);
}
QString Fingerprint::filePath() const {
QString dir = Fingerprint::directoryPath();
QString TlsFingerprint::filePath() const {
QString dir = TlsFingerprint::directoryPath();
return QString("%1/%2").arg(dir).arg(m_Filename);
}
void Fingerprint::persistDirectory() {
QDir dir(Fingerprint::directoryPath());
void TlsFingerprint::persistDirectory() {
QDir dir(TlsFingerprint::directoryPath());
if (!dir.exists()) {
dir.mkpath(".");
}
}
QString Fingerprint::directoryPath() {
QString TlsFingerprint::directoryPath() {
CoreInterface coreInterface;
QString profileDir = coreInterface.getProfileDir();
return QString("%1/%2").arg(profileDir).arg(kDirName);
}
Fingerprint Fingerprint::local() { return Fingerprint(kLocalFilename); }
Fingerprint Fingerprint::trustedServers() {
return Fingerprint(kTrustedServersFilename);
TlsFingerprint TlsFingerprint::local() {
return TlsFingerprint(kLocalFilename);
}
Fingerprint Fingerprint::trustedClients() {
return Fingerprint(kTrustedClientsFilename);
TlsFingerprint TlsFingerprint::trustedServers() {
return TlsFingerprint(kTrustedServersFilename);
}
TlsFingerprint TlsFingerprint::trustedClients() {
return TlsFingerprint(kTrustedClientsFilename);
}

View file

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015-2016 Symless Ltd.
* Copyright (C) 2015 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -19,9 +19,9 @@
#include <QString>
class Fingerprint {
class TlsFingerprint {
private:
Fingerprint(const QString &filename);
TlsFingerprint(const QString &filename);
public:
void trust(const QString &fingerprintText, bool append = true);
@ -32,9 +32,9 @@ public:
bool fileExists() const;
public:
static Fingerprint local();
static Fingerprint trustedServers();
static Fingerprint trustedClients();
static TlsFingerprint local();
static TlsFingerprint trustedServers();
static TlsFingerprint trustedClients();
static QString directoryPath();
static QString localFingerprint();
static bool localFingerprintExists();

View file

@ -0,0 +1,47 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "TlsUtility.h"
#include "TlsCertificate.h"
#include "constants.h"
namespace synergy::gui {
bool TlsUtility::isAvailable() const {
return !kLicensingEnabled || m_license.isTlsAvailable();
}
bool TlsUtility::isAvailableAndEnabled() const {
const auto &config = m_appConfig;
return isAvailable() && config.tlsEnabled();
}
void TlsUtility::generateCertificate(bool replace) const {
if (!isAvailableAndEnabled()) {
qFatal("unable to generate tls certificate, "
"tls is either not available or not enabled");
}
auto path = m_appConfig.tlsCertPath();
auto length = m_appConfig.tlsKeyLength();
TlsCertificate cert;
cert.generateCertificate(path, length, replace);
}
} // namespace synergy::gui

58
src/lib/gui/TlsUtility.h Normal file
View file

@ -0,0 +1,58 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "IAppConfig.h"
#include "license/License.h"
#include <stdexcept>
namespace synergy::gui {
class TlsUtility {
public:
explicit TlsUtility(
const IAppConfig &appConfig, const license::License &license)
: m_appConfig(appConfig),
m_license(license) {}
/**
* @brief Combines the availability and the enabled status of TLS.
*
* @return Given that the app setting for TLS is enabled:
* If licensing is enabled, it checks whether the product has TLS
* available, and if licensing is not enabled, true is returned.
*/
bool isAvailableAndEnabled() const;
/**
* @return true if TLS is available, regardless of whether it is enabled.
*/
bool isAvailable() const;
/**
* @param replace Replace certificate on disk (default: false).
*/
void generateCertificate(bool replace = false) const;
private:
const IAppConfig &m_appConfig;
const license::License &m_license;
};
} // namespace synergy::gui

View file

@ -1,7 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2016 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* Copyright (C) 2012 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -26,23 +25,28 @@
#include <QRegularExpression>
#include <memory>
VersionChecker::VersionChecker(std::shared_ptr<QNetworkAccessManager> nam)
: m_manager(nam ? nam : std::make_shared<QNetworkAccessManager>(this)) {
const char *const kVersion = SYNERGY_VERSION;
VersionChecker::VersionChecker(std::shared_ptr<QNetworkAccessManager> network)
: m_network(
network ? network : std::make_shared<QNetworkAccessManager>(this)) {
connect(
m_manager.get(), SIGNAL(finished(QNetworkReply *)), this,
m_network.get(), SIGNAL(finished(QNetworkReply *)), this,
SLOT(replyFinished(QNetworkReply *)));
}
void VersionChecker::checkLatest() {
auto request = QNetworkRequest(QUrl(SYNERGY_VERSION_URL));
request.setHeader(
QNetworkRequest::UserAgentHeader, QString("Synergy (") + SYNERGY_VERSION +
") " +
QSysInfo::prettyProductName());
request.setRawHeader("X-Synergy-Version", SYNERGY_VERSION);
void VersionChecker::checkLatest() const {
const QString url =
qEnvironmentVariable("SYNERGY_VERSION_URL", SYNERGY_VERSION_URL);
auto request = QNetworkRequest(url);
auto userAgent = QString("Synergy %1 on %2")
.arg(kVersion)
.arg(QSysInfo::prettyProductName());
request.setHeader(QNetworkRequest::UserAgentHeader, userAgent);
request.setRawHeader("X-Synergy-Version", kVersion);
request.setRawHeader(
"X-Synergy-Language", QLocale::system().name().toStdString().c_str());
m_manager->get(request);
m_network->get(request);
}
void VersionChecker::replyFinished(QNetworkReply *reply) {
@ -53,7 +57,7 @@ void VersionChecker::replyFinished(QNetworkReply *reply) {
}
}
int VersionChecker::getStageVersion(QString stage) const {
int VersionChecker::getStageVersion(QString stage) {
const char *stableName = "stable";
const char *rcName = "rc";
const char *betaName = "beta";

View file

@ -1,7 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2012-2019 Symless Ltd.
* Copyright (C) 2012 Nick Bolton
* Copyright (C) 2012 Symless Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -24,23 +23,24 @@
class QNetworkAccessManager;
class QNetworkReply;
class VersionCheckerTests;
class VersionChecker : public QObject {
Q_OBJECT
friend class VersionCheckerTests;
public:
VersionChecker(std::shared_ptr<QNetworkAccessManager> manager = nullptr);
virtual ~VersionChecker() {}
void checkLatest();
void setApp(const QString &app) { m_app = app; }
int compareVersions(const QString &left, const QString &right);
explicit VersionChecker(
std::shared_ptr<QNetworkAccessManager> network = nullptr);
void checkLatest() const;
public slots:
void replyFinished(QNetworkReply *reply);
signals:
void updateFound(const QString &version);
private:
std::shared_ptr<QNetworkAccessManager> m_manager;
QString m_app;
static int compareVersions(const QString &left, const QString &right);
/**
* \brief Converts a string stage to a integer value
@ -48,5 +48,7 @@ private:
* \return An integer representation of the stage, the higher the number the
* more recent the version
*/
int getStageVersion(QString stage) const;
static int getStageVersion(QString stage);
std::shared_ptr<QNetworkAccessManager> m_network;
};

50
src/lib/gui/constants.h Normal file
View file

@ -0,0 +1,50 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2014 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QString>
#ifdef SYNERGY_ENABLE_LICENSING
const bool kLicensingEnabled = true;
#else
const bool kLicensingEnabled = false;
#endif // SYNERGY_ENABLE_LICENSING
const auto kColorWhite = "#ffffff";
const auto kColorPrimary = "#ff7c00";
const auto kColorSecondary = "#4285f4";
const auto kLinkStyleWhite = QString("color: %1").arg(kColorWhite);
const auto kLinkStylePrimary = QString("color: %1").arg(kColorPrimary);
const auto kLinkStyleSecondary = QString("color: %1").arg(kColorSecondary);
const auto kLinkBuy = R"(<a href="%1" style="%2">Buy now</a>)";
const auto kLinkRenew = R"(<a href="%1" style="%2">Renew now</a>)";
const auto kLinkDownload = R"(<a href="%1" style="%2">Download now</a>)";
const auto kUrlSourceQuery = "source=gui";
const auto kUrlWebsite = "https://symless.com";
const auto kUrlProduct = QString("%1/synergy").arg(kUrlWebsite);
const auto kUrlPurchase =
QString("%1/purchase?%2").arg(kUrlProduct).arg(kUrlSourceQuery);
const auto kUrlContact =
QString("%1/contact?%2").arg(kUrlProduct).arg(kUrlSourceQuery);
const auto kUrlHelp =
QString("%1/help?%2").arg(kUrlProduct).arg(kUrlSourceQuery);
const auto kUrlDownload =
QString("%1/download?%2").arg(kUrlProduct).arg(kUrlSourceQuery);

91
src/lib/gui/dotenv.cpp Normal file
View file

@ -0,0 +1,91 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "dotenv.h"
#include <QDebug>
#include <QFile>
#include <QProcess>
#include <QProcessEnvironment>
#include <QString>
#include <QTextStream>
namespace synergy::gui {
QPair<QString, QString> getPair(const QString &line);
/**
* @brief A _very_ basic Qt .env file parser.
*
* This function re-invents the wheel to save adding a library dependency.
* It does not support many things that a proper .env parser would, such as
* trailing comments, escaping characters, multiline values, etc.
*
* If this function is not sufficient, replace it with a library such as:
* https://github.com/adeharo9/cpp-dotenv
*/
void dotenv(const QString &filePath) {
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug("no .env file in current dir");
return;
}
qDebug("loading env vars from: %s", filePath.toUtf8().constData());
QTextStream in(&file);
while (!in.atEnd()) {
QString line = in.readLine().trimmed();
if (line.startsWith('#'))
continue;
auto [key, value] = getPair(line);
if (key.isEmpty() || value.isEmpty())
continue;
const auto keyBytes = key.toUtf8();
const auto valueBytes = value.toUtf8();
const auto &key_c = keyBytes.constData();
const auto &value_c = valueBytes.constData();
qDebug("%s=%s", key_c, value_c);
qputenv(keyBytes, valueBytes);
}
}
QString stripQuotes(const QString &value) {
QString result = value;
if (result.startsWith('"') && result.endsWith('"')) {
result = result.mid(1, result.length() - 2);
}
return result;
}
QPair<QString, QString> getPair(const QString &line) {
auto pos = line.indexOf('=');
if (pos == -1) {
return QPair<QString, QString>("", "");
}
QString key = line.left(pos);
QString value = line.mid(pos + 1);
return QPair<QString, QString>(key.trimmed(), stripQuotes(value.trimmed()));
}
} // namespace synergy::gui

30
src/lib/gui/dotenv.h Normal file
View file

@ -0,0 +1,30 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QString>
namespace synergy::gui {
/**
* @param filePath Path to the .env file.
* @param envVars Somewhere to save strings for the lifetime of the app.
*/
void dotenv(const QString &filePath);
} // namespace synergy::gui

View file

@ -0,0 +1,76 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2024 Synergy 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 <http://www.gnu.org/licenses/>.
*/
#include "license_notices.h"
#include "constants.h"
#include "license/License.h"
using License = synergy::license::License;
namespace synergy::gui {
QString trialLicenseNotice(const License &license);
QString subscriptionLicenseNotice(const License &license);
QString licenseNotice(const License &license) {
if (license.isTrial()) {
return trialLicenseNotice(license);
} else if (license.isSubscription()) {
return subscriptionLicenseNotice(license);
} else {
qFatal("license notice only for time limited licenses");
}
}
QString trialLicenseNotice(const License &license) {
const QString buyLink =
QString(kLinkBuy).arg(kUrlPurchase).arg(kLinkStyleWhite);
if (license.isExpired()) {
return QString("<p>Your trial has expired. %1</p>").arg(buyLink);
} else {
auto daysLeft = license.daysLeft().count();
if (daysLeft <= 0) {
return QString("<p>Your trial expires today. %1</p>").arg(buyLink);
} else {
return QString("<p>Your trial expires in %1 %2. %3</p>")
.arg(daysLeft)
.arg((daysLeft == 1) ? "day" : "days")
.arg(buyLink);
}
}
}
QString subscriptionLicenseNotice(const License &license) {
const QString renewLink =
QString(kLinkRenew).arg(kUrlPurchase).arg(kLinkStyleWhite);
if (license.isExpired()) {
return QString("<p>Your license has expired. %1</p>").arg(renewLink);
} else {
auto daysLeft = license.daysLeft().count();
if (daysLeft <= 0) {
return QString("<p>Your license expires today. %1</p>").arg(renewLink);
} else {
return QString("<p>Your license expires in %1 %2. %3</p>")
.arg(daysLeft)
.arg((daysLeft == 1) ? "day" : "days")
.arg(renewLink);
}
}
}
} // namespace synergy::gui

View file

@ -1,6 +1,6 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2015 Synergy Ltd.
* Copyright (C) 2024 Synergy Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -15,33 +15,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ACTIVATIONNOTIFIER_H
#define ACTIVATIONNOTIFIER_H
#pragma once
#include <QObject>
#include "license/License.h"
class ActivationNotifier : public QObject {
Q_OBJECT
public:
explicit ActivationNotifier(QObject *parent = 0);
#include <QString>
void setIdentity(QString identity);
void setUpdateInfo(
QString const &fromVersion, QString const &toVersion,
QString const &serialKey);
namespace synergy::gui {
public slots:
void notify();
void notifyUpdate();
QString licenseNotice(const synergy::license::License &license);
signals:
void finished();
private:
QString m_Identity;
QString m_fromVersion;
QString m_toVersion;
QString m_serialKey;
};
#endif // ACTIVATIONNOTIFIER_H
} // namespace synergy::gui

View file

@ -17,9 +17,9 @@
#include "ipc/IpcClient.h"
#include "base/TMethodEventJob.h"
#include "global/Ipc.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServerProxy.h"
#include "shared/Ipc.h"
//
// IpcClient

View file

@ -19,10 +19,10 @@
#include "base/Log.h"
#include "base/TMethodEventJob.h"
#include "global/Ipc.h"
#include "io/IStream.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcSettingMessage.h"
#include "shared/Ipc.h"
#include "synergy/ProtocolUtil.h"
//

View file

@ -21,7 +21,7 @@
#include "arch/IArchMultithread.h"
#include "base/Event.h"
#include "base/EventTypes.h"
#include "shared/Ipc.h"
#include "global/Ipc.h"
namespace synergy {
class IStream;

View file

@ -24,11 +24,11 @@
#include "base/EventQueue.h"
#include "base/TMethodEventJob.h"
#include "base/TMethodJob.h"
#include "global/Ipc.h"
#include "ipc/IpcClientProxy.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServer.h"
#include "mt/Thread.h"
#include "shared/Ipc.h"
enum EIpcLogOutputter {
kBufferMaxSize = 1000,

View file

@ -21,7 +21,7 @@
#include "arch/Arch.h"
#include "arch/IArchMultithread.h"
#include "base/ILogOutputter.h"
#include "shared/Ipc.h"
#include "global/Ipc.h"
#include <deque>

View file

@ -17,7 +17,7 @@
*/
#include "ipc/IpcMessage.h"
#include "shared/Ipc.h"
#include "global/Ipc.h"
IpcMessage::IpcMessage(IpcMessageType type) : m_type(type) {}

View file

@ -19,7 +19,7 @@
#include "base/Event.h"
#include "base/String.h"
#include "shared/Ipc.h"
#include "global/Ipc.h"
class IpcMessage : public EventData {
public:

View file

@ -22,11 +22,11 @@
#include "base/IEventQueue.h"
#include "base/Log.h"
#include "base/TMethodEventJob.h"
#include "global/Ipc.h"
#include "io/IStream.h"
#include "ipc/IpcClientProxy.h"
#include "ipc/IpcMessage.h"
#include "net/IDataSocket.h"
#include "shared/Ipc.h"
//
// IpcServer

View file

@ -20,9 +20,9 @@
#include "arch/Arch.h"
#include "base/EventTypes.h"
#include "global/Ipc.h"
#include "net/NetworkAddress.h"
#include "net/TCPListenSocket.h"
#include "shared/Ipc.h"
#include <list>

View file

@ -20,9 +20,9 @@
#include "base/Log.h"
#include "base/TMethodEventJob.h"
#include "global/Ipc.h"
#include "io/IStream.h"
#include "ipc/IpcMessage.h"
#include "shared/Ipc.h"
#include "synergy/ProtocolUtil.h"
//

View file

@ -0,0 +1,26 @@
# Synergy -- mouse and keyboard sharing utility
# Copyright (C) 2012-2024 Symless Ltd.
# Copyright (C) 2009-2012 Nick Bolton
#
# 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 <http://www.gnu.org/licenses/>.
file(GLOB headers "*.h")
file(GLOB sources "*.cpp")
if(ADD_HEADERS_TO_SOURCES)
list(APPEND sources ${headers})
endif()
add_library(license STATIC ${sources})
target_link_libraries(license arch base)

View file

@ -0,0 +1,99 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "License.h"
#include "Product.h"
#include "license/SerialKey.h"
#include "license/parse_serial_key.h"
#include <chrono>
#include <climits>
using namespace std::chrono;
namespace synergy::license {
License::License(const std::string &hexString)
: m_serialKey(parseSerialKey(hexString)) {}
License::License(const SerialKey &serialKey) : m_serialKey(serialKey) {
if (!m_serialKey.isValid) {
throw InvalidSerialKey();
}
}
bool License::isTrial() const { return m_serialKey.type.isTrial(); }
bool License::isSubscription() const {
return m_serialKey.type.isSubscription();
}
bool License::isTimeLimited() const { return m_serialKey.type.isTimeLimited(); }
bool License::isTlsAvailable() const {
return m_serialKey.product.isTlsAvailable();
}
Edition License::productEdition() const {
return m_serialKey.product.edition();
}
bool License::isExpiring() const {
if (!isTimeLimited()) {
return false;
}
if (!m_serialKey.warnTime.has_value()) {
throw NoTimeLimitError();
}
return m_nowFunc() >= m_serialKey.warnTime.value();
}
bool License::isExpired() const {
if (!isTimeLimited()) {
return false;
}
if (!m_serialKey.expireTime.has_value()) {
throw NoTimeLimitError();
}
return m_nowFunc() >= m_serialKey.expireTime.value();
}
days License::daysLeft() const {
if (!m_serialKey.expireTime.has_value()) {
throw NoTimeLimitError();
}
auto expireTime = m_serialKey.expireTime.value();
auto timeLeft = expireTime - m_nowFunc();
return duration_cast<days>(timeLeft);
}
std::string License::productName() const {
auto name = m_serialKey.product.name();
if (m_serialKey.type.isTrial()) {
name += " (Trial)";
}
return name;
}
} // namespace synergy::license

93
src/lib/license/License.h Normal file
View file

@ -0,0 +1,93 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "SerialKey.h"
#include <chrono>
#include <ctime>
#include <functional>
#include <string>
class Server;
class LicenseHandler;
class LicenseTests;
namespace synergy::license {
class License {
friend class ::Server;
friend class ::LicenseHandler;
friend class ::LicenseTests;
using days = std::chrono::days;
using system_clock = std::chrono::system_clock;
using time_point = system_clock::time_point;
using NowFunc = std::function<time_point()>;
using LicenseError = std::runtime_error;
public:
explicit License(const SerialKey &serialKey);
explicit License(const std::string &hexString);
friend bool operator==(License const &lhs, License const &rhs) {
return lhs.m_serialKey == rhs.m_serialKey;
}
bool isValid() const { return m_serialKey.isValid; }
bool isExpiring() 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;
const SerialKey &serialKey() const { return m_serialKey; }
void invalidate() { m_serialKey = SerialKey::invalid(); }
class InvalidSerialKey : public LicenseError {
public:
explicit InvalidSerialKey() : LicenseError("invalid serial key") {}
};
class NoTimeLimitError : public LicenseError {
public:
explicit NoTimeLimitError()
: LicenseError("serial key has no time limit") {}
};
protected:
void setNowFunc(const NowFunc &nowFunc) { m_nowFunc = nowFunc; }
private:
// for intentionality, force use of `invalid()` static function.
License() = default;
// prevent copy, so that changes can be reflected in one instance.
License(const License &) = default;
License &operator=(const License &) = default;
static License invalid() { return License(); }
SerialKey m_serialKey = SerialKey::invalid();
NowFunc m_nowFunc = []() { return system_clock::now(); };
};
} // namespace synergy::license

121
src/lib/license/Product.cpp Normal file
View file

@ -0,0 +1,121 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <map>
#include "Product.h"
using SKE = Product::SerialKeyEditionID;
const char *const kLicensedProductName = "Synergy 1";
const std::string SKE::Pro = "pro";
const std::string SKE::Basic = "basic";
const std::string SKE::Buisiness = "business";
using Edition = Product::Edition;
const std::map<std::string, Edition, std::less<>> kSerialKeyEditions{
{SKE::Basic, Edition::kBasic},
{SKE::Pro, Edition::kPro},
{SKE::Buisiness, Edition::kBusiness},
};
Product::Product(Edition edition) : m_edition(edition) {}
Product::Product(const std::string &serialKeyEditionID) {
setEdition(serialKeyEditionID);
}
Edition Product::edition() const { return m_edition; }
std::string Product::serialKeyId() const {
switch (edition()) {
using enum Edition;
case kPro:
return SKE::Pro;
case kBasic:
return SKE::Basic;
case kBusiness:
return SKE::Buisiness;
default:
throw InvalidType();
}
}
std::string Product::name() const {
const std::string nameBase = kLicensedProductName;
switch (edition()) {
using enum Edition;
case kUnregistered:
return nameBase + " (unregistered)";
case kBasic:
return nameBase + " Basic";
case kPro:
return nameBase + " Pro";
case kBusiness:
return nameBase + " Business";
default:
throw InvalidType();
}
}
void Product::setEdition(Edition edition) { m_edition = edition; }
void Product::setEdition(const std::string &name) {
const auto &pType = kSerialKeyEditions.find(name);
if (pType != kSerialKeyEditions.end()) {
m_edition = pType->second;
} else {
throw InvalidType();
}
}
bool Product::isValid() const {
if (m_edition == Edition::kUnregistered) {
return false;
}
return kSerialKeyEditions.contains(serialKeyId());
}
bool Product::isTlsAvailable() const {
switch (edition()) {
using enum Edition;
case kPro:
case kBusiness:
return true;
case kBasic:
case kUnregistered:
return false;
default:
throw InvalidType();
}
}

64
src/lib/license/Product.h Normal file
View file

@ -0,0 +1,64 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdexcept>
#include <string>
class Product {
friend bool operator==(Product const &, Product const &) = default;
public:
class InvalidType : public std::runtime_error {
public:
explicit InvalidType() : std::runtime_error("invalid product type") {}
};
enum class Edition {
kUnregistered = -1,
kBasic = 0,
kPro = 1,
kBusiness = 4,
};
/**
* @brief Product edition IDs found in a decoded serial key.
*/
class SerialKeyEditionID {
public:
static const std::string Basic;
static const std::string Pro;
static const std::string Buisiness;
};
Product() = default;
explicit Product(Edition edition);
explicit Product(const std::string &serialKeyEditionID);
bool isValid() const;
Edition edition() const;
std::string serialKeyId() const;
std::string name() const;
bool isTlsAvailable() const;
void setEdition(Edition type);
void setEdition(const std::string &serialKeyId);
private:
Edition m_edition = Edition::kUnregistered;
};

View file

@ -15,21 +15,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EDITIONTYPE_H
#define EDITIONTYPE_H
#pragma once
/* Do not reorder these! */
#include "Product.h"
enum Edition {
kBasic,
kPro,
kValueNotUsed,
kUnregistered,
kBusiness,
kBasicChina,
kProChina,
kLite,
kUltimate
};
#endif // EDITIONTYPE_H
/// @deprecated Use `Product::Edition` instead
using Edition = Product::Edition;

View file

@ -0,0 +1,60 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "ProductEdition.h"
#include "SerialKeyType.h"
#include "license/Product.h"
#include "license/ProductEdition.h"
#include <chrono>
#include <ctime>
#include <optional>
#include <string>
namespace synergy::license {
struct SerialKey {
using time_point = std::chrono::system_clock::time_point;
friend bool operator==(const SerialKey &lhs, const SerialKey &rhs) {
return (lhs.hexString == rhs.hexString) && (lhs.warnTime == rhs.warnTime) &&
(lhs.expireTime == rhs.expireTime) && (lhs.product == rhs.product) &&
(lhs.type == rhs.type);
}
explicit SerialKey(const std::string &key) : hexString(key) {}
static SerialKey invalid() {
return SerialKey(Product::Edition::kUnregistered);
}
const std::string &toString() const { return hexString; }
bool isValid = false;
std::string hexString = "";
Product product;
SerialKeyType type;
std::optional<time_point> warnTime = std::nullopt;
std::optional<time_point> expireTime = std::nullopt;
private:
explicit SerialKey(Edition edition) : product(edition) {}
};
} // namespace synergy::license

View file

@ -19,18 +19,16 @@
const std::string SerialKeyType::Trial = "trial";
const std::string SerialKeyType::Subscription = "subscription";
const std::string SerialKeyType::Maintenance = "maintenance";
SerialKeyType::SerialKeyType() {}
void SerialKeyType::setKeyType(const std::string &Type) {
m_isTrial = (Type == SerialKeyType::Trial);
m_isTemporary = (m_isTrial || (Type == SerialKeyType::Subscription));
m_isMaintenance = (Type == SerialKeyType::Maintenance);
void SerialKeyType::setType(const std::string_view &type) {
m_isTrial = (type == SerialKeyType::Trial);
m_isSubscription = (type == SerialKeyType::Subscription);
}
bool SerialKeyType::isTrial() const { return m_isTrial; }
bool SerialKeyType::isTemporary() const { return m_isTemporary; }
bool SerialKeyType::isSubscription() const { return m_isSubscription; }
bool SerialKeyType::isMaintenance() const { return m_isMaintenance; }
bool SerialKeyType::isTimeLimited() const {
return m_isTrial || m_isSubscription;
}

View file

@ -21,31 +21,22 @@
class SerialKeyType {
private:
friend bool operator==(SerialKeyType const &, SerialKeyType const &);
friend bool
operator==(SerialKeyType const &lhs, SerialKeyType const &rhs) = default;
public:
static const std::string Trial;
static const std::string Subscription;
static const std::string Maintenance;
SerialKeyType();
explicit SerialKeyType() = default;
explicit SerialKeyType(const std::string_view &type) { setType(type); }
void setKeyType(const std::string &type);
void setType(const std::string_view &type);
bool isTrial() const;
bool isTemporary() const;
bool isMaintenance() const;
bool isSubscription() const;
bool isTimeLimited() const;
private:
bool m_isTrial = false;
bool m_isTemporary = false;
bool m_isMaintenance = false;
bool m_isSubscription = false;
};
inline bool operator==(SerialKeyType const &lhs, SerialKeyType const &rhs) {
return (lhs.m_isTrial == rhs.m_isTrial) &&
(lhs.m_isTemporary == rhs.m_isTemporary);
}
inline bool operator!=(SerialKeyType const &lhs, SerialKeyType const &rhs) {
return !(lhs == rhs);
}

View file

@ -0,0 +1,143 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "parse_serial_key.h"
#include "SerialKey.h"
#include "SerialKeyType.h"
#include "utils/trim.h"
#include <cctype>
#include <optional>
#include <sstream>
#include <string>
#include <vector>
using Parts = std::vector<std::string>;
using system_clock = std::chrono::system_clock;
using time_point = system_clock::time_point;
namespace synergy::license {
std::string decode(const std::string &hexString);
Parts tokenize(const std::string &plainText);
SerialKey parseV1(const std::string &hexString, const Parts &parts);
SerialKey parseV2(const std::string &hexString, const Parts &parts);
std::optional<time_point> parseDate(const std::string &unixTimeString);
SerialKey parseSerialKey(const std::string &hexString) {
const auto &plainText = decode(hexString);
const auto &parts = tokenize(plainText);
const auto &version = parts.at(0);
if (version == "v1") {
return parseV1(hexString, parts);
} else if (version == "v2") {
return parseV2(hexString, parts);
} else {
throw InvalidSerialKeyVersion(version);
}
}
std::string decode(const std::string &hexString) {
std::string trimmed = utils::trim(hexString);
if (trimmed.length() % 2 != 0) {
throw InvalidHexString();
}
std::string plainText;
plainText.reserve(trimmed.length() / 2);
for (size_t i = 0; i < trimmed.length(); i += 2) {
std::string byteString = trimmed.substr(i, 2);
auto byte = static_cast<char>(std::stoi(byteString, nullptr, 16));
plainText.push_back(byte);
}
return plainText;
}
SerialKey parseV1(const std::string &hexString, const Parts &parts) {
if (parts.size() < 8) {
throw InvalidSerialKeyFormat();
}
// e.g.: {v1;basic;name;1;email;company name;1398297600;1398384000}
SerialKey serialKey(hexString);
serialKey.product = Product(parts.at(1));
serialKey.warnTime = parseDate(parts.at(6));
serialKey.expireTime = parseDate(parts.at(7));
serialKey.isValid = true;
return serialKey;
}
SerialKey parseV2(const std::string &hexString, const Parts &parts) {
if (parts.size() < 9) {
throw InvalidSerialKeyFormat();
}
// e.g.: {v2;trial;basic;name;1;email;company name;1398297600;1398384000}
SerialKey serialKey(hexString);
serialKey.type = SerialKeyType(parts.at(1));
serialKey.product = Product(parts.at(2));
serialKey.warnTime = parseDate(parts.at(7));
serialKey.expireTime = parseDate(parts.at(8));
serialKey.isValid = true;
return serialKey;
}
Parts tokenize(const std::string &plainText) {
if (plainText.front() != '{' || plainText.back() != '}') {
throw InvalidSerialKeyFormat();
}
const auto serialData = plainText.substr(1, plainText.length() - 2);
Parts parts;
std::stringstream ss(serialData);
std::string item;
while (std::getline(ss, item, ';')) {
parts.push_back(item);
}
// it's possible that the last character is a delimiter, so add an empty part
if (!serialData.empty() && serialData.back() == ';') {
parts.emplace_back("");
}
return parts;
}
std::optional<time_point> parseDate(const std::string &unixTimeString) {
auto clean = utils::trim(unixTimeString);
if (clean.empty()) {
return std::nullopt;
}
try {
auto seconds = std::stoi(clean);
if (seconds < 0) {
throw InvalidSerialKeyDate(unixTimeString);
}
return time_point{std::chrono::seconds{seconds}};
} catch (const std::invalid_argument &) {
throw InvalidSerialKeyDate(unixTimeString);
}
}
} // namespace synergy::license

View file

@ -0,0 +1,57 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "SerialKey.h"
#include <stdexcept>
#include <string>
namespace synergy::license {
class SerialKeyParseError : public std::runtime_error {
public:
explicit SerialKeyParseError(const std::string &message)
: std::runtime_error(message) {}
};
class InvalidHexString : public SerialKeyParseError {
public:
explicit InvalidHexString()
: SerialKeyParseError("invalid hex string length") {}
};
class InvalidSerialKeyFormat : public SerialKeyParseError {
public:
explicit InvalidSerialKeyFormat()
: SerialKeyParseError("invalid serial key format") {}
};
class InvalidSerialKeyDate : public SerialKeyParseError {
public:
explicit InvalidSerialKeyDate(const std::string &date)
: SerialKeyParseError("invalid serial key date: " + date) {}
};
class InvalidSerialKeyVersion : public SerialKeyParseError {
public:
explicit InvalidSerialKeyVersion(const std::string &version)
: SerialKeyParseError("invalid serial key version: " + version) {}
};
SerialKey parseSerialKey(const std::string &hexString);
} // namespace synergy::license

View file

@ -93,7 +93,7 @@ MSWindowsScreen *MSWindowsScreen::s_screen = NULL;
MSWindowsScreen::MSWindowsScreen(
bool isPrimary, bool noHooks, bool stopOnDeskSwitch, IEventQueue *events,
bool enableLangSync, lib::synergy::ClientScrollDirection scrollDirection)
bool enableLangSync, synergy::ClientScrollDirection scrollDirection)
: PlatformScreen(events, scrollDirection),
m_isPrimary(isPrimary),
m_noHooks(noHooks),

View file

@ -44,8 +44,8 @@ public:
MSWindowsScreen(
bool isPrimary, bool noHooks, bool stopOnDeskSwitch, IEventQueue *events,
bool enableLangSync = false,
lib::synergy::ClientScrollDirection scrollDirection =
lib::synergy::ClientScrollDirection::SERVER);
synergy::ClientScrollDirection scrollDirection =
synergy::ClientScrollDirection::SERVER);
virtual ~MSWindowsScreen();
//! @name manipulators

View file

@ -23,11 +23,11 @@
#include "base/Log.h"
#include "base/TMethodJob.h"
#include "base/log_outputters.h"
#include "global/Ipc.h"
#include "ipc/IpcLogOutputter.h"
#include "ipc/IpcMessage.h"
#include "ipc/IpcServer.h"
#include "mt/Thread.h"
#include "shared/Ipc.h"
#include "synergy/App.h"
#include "synergy/ArgsBase.h"

View file

@ -56,8 +56,8 @@ class OSXScreen : public PlatformScreen {
public:
OSXScreen(
IEventQueue *events, bool isPrimary, bool enableLangSync = false,
lib::synergy::ClientScrollDirection scrollDirection =
lib::synergy::ClientScrollDirection::SERVER);
synergy::ClientScrollDirection scrollDirection =
synergy::ClientScrollDirection::SERVER);
virtual ~OSXScreen();

View file

@ -86,7 +86,7 @@ bool OSXScreen::s_hasGHOM = false;
OSXScreen::OSXScreen(IEventQueue* events,
bool isPrimary,
bool enableLangSync,
lib::synergy::ClientScrollDirection scrollDirection) :
synergy::ClientScrollDirection scrollDirection) :
PlatformScreen(events, scrollDirection),
m_isPrimary(isPrimary),
m_isOnScreen(m_isPrimary),

View file

@ -98,7 +98,7 @@ XWindowsScreen *XWindowsScreen::s_screen = NULL;
XWindowsScreen::XWindowsScreen(
const char *displayName, bool isPrimary, bool disableXInitThreads,
int mouseScrollDelta, IEventQueue *events,
lib::synergy::ClientScrollDirection scrollDirection)
synergy::ClientScrollDirection scrollDirection)
: PlatformScreen(events, scrollDirection),
m_isPrimary(isPrimary),
m_mouseScrollDelta(mouseScrollDelta),

View file

@ -42,8 +42,8 @@ public:
XWindowsScreen(
const char *displayName, bool isPrimary, bool disableXInitThreads,
int mouseScrollDelta, IEventQueue *events,
lib::synergy::ClientScrollDirection m_clientScrollDirection =
lib::synergy::ClientScrollDirection::SERVER);
synergy::ClientScrollDirection m_clientScrollDirection =
synergy::ClientScrollDirection::SERVER);
virtual ~XWindowsScreen();
//! @name manipulators

View file

@ -23,7 +23,7 @@ endif()
add_library(server STATIC ${sources})
target_link_libraries(server shared)
target_link_libraries(server global license)
if(UNIX)
target_link_libraries(server synlib)

View file

@ -24,6 +24,7 @@
#include "base/TMethodEventJob.h"
#include "base/TMethodJob.h"
#include "common/stdexcept.h"
#include "license/License.h"
#include "mt/Thread.h"
#include "net/IDataSocket.h"
#include "net/IListenSocket.h"
@ -33,7 +34,6 @@
#include "server/ClientProxy.h"
#include "server/ClientProxyUnknown.h"
#include "server/PrimaryClient.h"
#include "shared/SerialKey.h"
#include "synergy/AppUtil.h"
#include "synergy/DropHelper.h"
#include "synergy/FileChunk.h"
@ -54,13 +54,15 @@
#include <fstream>
#include <sstream>
using namespace synergy::license;
//
// Server
//
Server::Server(
Config &config, PrimaryClient *primaryClient, synergy::Screen *screen,
IEventQueue *events, lib::synergy::ServerArgs const &args)
IEventQueue *events, synergy::ServerArgs const &args)
: m_mock(false),
m_primaryClient(primaryClient),
m_active(primaryClient),
@ -429,7 +431,8 @@ void Server::switchScreen(
assert(dst != NULL);
// if trial is expired, exit the process
if (m_args.m_serial.isExpired(std::time(0))) {
License license(m_args.m_serialKey);
if (license.isExpired()) {
LOG((CLOG_ERR "trial has expired, aborting server"));
exit(kExitSuccess);
}

View file

@ -111,7 +111,7 @@ public:
*/
Server(
Config &config, PrimaryClient *primaryClient, synergy::Screen *screen,
IEventQueue *events, lib::synergy::ServerArgs const &args);
IEventQueue *events, synergy::ServerArgs const &args);
Server(Server const &) = delete;
Server(Server &&) = delete;
~Server();
@ -490,5 +490,5 @@ private:
bool m_waitDragInfoThread;
ClientListener *m_clientListener;
lib::synergy::ServerArgs m_args;
synergy::ServerArgs m_args;
};

View file

@ -1,123 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "SerialKey.h"
#include "SerialKeyEdition.h"
#include "SerialKeyParser.h"
#include <climits>
#include <stdexcept>
#include <vector>
SerialKey::SerialKey(Edition edition) : m_data(edition) {}
SerialKey::SerialKey(const std::string &serial) : m_data(serial) {
SerialKeyParser parser;
if (parser.parse(serial)) {
m_data = parser.getData();
} else {
throw std::runtime_error("Invalid serial key");
}
}
bool SerialKey::isExpiring(time_t currentTime) const {
bool result = false;
if (isTemporary()) {
unsigned long long currentTimeAsLL =
static_cast<unsigned long long>(currentTime);
if ((m_data.warnTime <= currentTimeAsLL) &&
(currentTimeAsLL < m_data.expireTime)) {
result = true;
}
}
return result;
}
bool SerialKey::isExpired(time_t currentTime) const {
bool result = false;
if (isTemporary()) {
unsigned long long currentTimeAsLL =
static_cast<unsigned long long>(currentTime);
if (m_data.expireTime <= currentTimeAsLL) {
result = true;
}
}
return result;
}
bool SerialKey::isTrial() const { return m_data.keyType.isTrial(); }
bool SerialKey::isTemporary() const {
return (m_data.keyType.isTemporary() && !m_data.edition.isChina());
}
bool SerialKey::isMaintenance() const {
return (m_data.keyType.isMaintenance() || m_data.edition.isChina());
}
bool SerialKey::isValid() const {
bool Valid = true;
if (!m_data.edition.isValid() || isExpired(::time(nullptr))) {
Valid = false;
}
return Valid;
}
Edition SerialKey::edition() const { return m_data.edition.getType(); }
const std::string &SerialKey::toString() const { return m_data.key; }
time_t SerialKey::daysLeft(time_t currentTime) const {
unsigned long long timeLeft = 0;
unsigned long long const day = 60 * 60 * 24;
unsigned long long currentTimeAsLL =
static_cast<unsigned long long>(currentTime);
if (currentTimeAsLL < m_data.expireTime) {
timeLeft = m_data.expireTime - currentTimeAsLL;
}
unsigned long long daysLeft = 0;
daysLeft = timeLeft % day != 0 ? 1 : 0;
return timeLeft / day + daysLeft;
}
time_t SerialKey::getExpiration() const { return m_data.expireTime; }
int SerialKey::getSpanLeft(time_t time) const {
int result{-1};
if (isTemporary() && !isExpired(time)) {
auto timeLeft = (m_data.expireTime - time) * 1000;
if (timeLeft < INT_MAX) {
result = static_cast<int>(timeLeft);
} else {
result = INT_MAX;
}
}
return result;
}

View file

@ -1,54 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "SerialKeyData.h"
#include "SerialKeyEdition.h"
#include <ctime>
#include <string>
class SerialKey {
friend bool operator==(SerialKey const &, SerialKey const &);
public:
explicit SerialKey(Edition edition = kUnregistered);
explicit SerialKey(const std::string &serial);
bool isExpiring(time_t currentTime) const;
bool isExpired(time_t currentTime) const;
bool isTrial() const;
bool isTemporary() const;
bool isMaintenance() const;
bool isValid() const;
time_t daysLeft(time_t currentTime) const;
time_t getExpiration() const;
int getSpanLeft(time_t time = ::time(0)) const;
Edition edition() const;
const std::string &toString() const;
private:
SerialKeyData m_data;
};
inline bool operator==(SerialKey const &lhs, SerialKey const &rhs) {
return (lhs.m_data == rhs.m_data);
}
inline bool operator!=(SerialKey const &lhs, SerialKey const &rhs) {
return !(lhs == rhs);
}

View file

@ -1,52 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "SerialKeyEdition.h"
#include "SerialKeyType.h"
#include <string>
/**
* @brief The SerialKeyData struct
* This is DTO which stores key data
*/
struct SerialKeyData {
std::string key; // Encoded serial key as a string
SerialKeyEdition edition; // Serial key edition
SerialKeyType keyType; // Serial key type
unsigned long long warnTime = 0; // Warning time
unsigned long long expireTime = 0; // Expiration time
/**
* @brief SerialKeyData constructor
* @param key encoded key
*/
explicit SerialKeyData(const std::string &key) : key(key) {}
/**
* @brief SerialKeyData default constructor
* @param key edition. Unregistered by default
*/
explicit SerialKeyData(Edition edition = kUnregistered) : edition(edition) {}
};
inline bool operator==(SerialKeyData const &lhs, SerialKeyData const &rhs) {
return (lhs.key == rhs.key) && (lhs.warnTime == rhs.warnTime) &&
(lhs.expireTime == rhs.expireTime) && (lhs.edition == rhs.edition) &&
(lhs.keyType == rhs.keyType);
}

View file

@ -1,126 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#include <map>
#include "SerialKeyEdition.h"
const std::string SerialKeyEdition::Pro = "pro";
const std::string SerialKeyEdition::ProChina = "pro_china";
const std::string SerialKeyEdition::Basic = "basic";
const std::string SerialKeyEdition::BasicChina = "basic_china";
const std::string SerialKeyEdition::Buisiness = "business";
const std::string SerialKeyEdition::Unregistered = "community";
const std::string SerialKeyEdition::Ultimate = "ultimate";
const std::string SerialKeyEdition::Lite = "lite";
const std::map<std::string, Edition, std::less<>> serialTypes{
{SerialKeyEdition::Basic, kBasic},
{SerialKeyEdition::Pro, kPro},
{SerialKeyEdition::BasicChina, kBasicChina},
{SerialKeyEdition::ProChina, kProChina},
{SerialKeyEdition::Buisiness, kBusiness},
{SerialKeyEdition::Lite, kLite},
{SerialKeyEdition::Ultimate, kUltimate}};
SerialKeyEdition::SerialKeyEdition(Edition type) : m_type(type) {}
SerialKeyEdition::SerialKeyEdition(const std::string &type) { setType(type); }
Edition SerialKeyEdition::getType() const { return m_type; }
std::string SerialKeyEdition::getName() const {
switch (getType()) {
case kLite:
return Lite;
case kUltimate:
return Ultimate;
case kPro:
return Pro;
case kBasic:
return Basic;
case kBusiness:
return Buisiness;
case kBasicChina:
return BasicChina;
case kProChina:
return ProChina;
default:
return Unregistered;
}
}
std::string SerialKeyEdition::getProductName() const {
const std::string nameBase = "Synergy 1";
switch (getType()) {
case kLite:
return nameBase;
case kUltimate:
return nameBase + " Ultimate";
case kPro:
return nameBase + " Pro";
case kBasic:
return nameBase + " Basic";
case kBusiness:
return nameBase + " Business";
case kBasicChina:
return nameBase + " 中文版";
case kProChina:
return nameBase + " Pro 中文版";
default:
return nameBase + " (Unregistered)";
}
}
void SerialKeyEdition::setType(Edition type) {
m_type = type;
setType(getName());
}
void SerialKeyEdition::setType(const std::string &name) {
const auto &pType = serialTypes.find(name);
if (pType != serialTypes.end()) {
m_type = pType->second;
} else {
m_type = kUnregistered;
}
}
bool SerialKeyEdition::isValid() const {
return serialTypes.contains(getName());
}
bool SerialKeyEdition::isChina() const {
return ((m_type == kBasicChina) || (m_type == kProChina));
}

View file

@ -1,53 +0,0 @@
/*
* 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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "EditionType.h"
#include <string>
class SerialKeyEdition {
friend bool
operator==(SerialKeyEdition const &, SerialKeyEdition const &) = default;
public:
SerialKeyEdition() = default;
explicit SerialKeyEdition(Edition type);
explicit SerialKeyEdition(const std::string &name);
Edition getType() const;
std::string getName() const;
std::string getProductName() const;
void setType(Edition type);
void setType(const std::string &type);
bool isValid() const;
bool isChina() const;
static const std::string Pro;
static const std::string ProChina;
static const std::string Basic;
static const std::string BasicChina;
static const std::string Buisiness;
static const std::string Unregistered;
static const std::string Ultimate;
static const std::string Lite;
private:
Edition m_type = kUnregistered;
};

View file

@ -1,138 +0,0 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
*/
#include "SerialKeyParser.h"
void SerialKeyParser::setKey(const std::string &key) { m_data.key = key; }
void SerialKeyParser::setType(const std::string &type) {
m_data.keyType.setKeyType(type);
}
void SerialKeyParser::setEdition(const std::string &edition) {
m_data.edition.setType(edition);
if (m_data.keyType.isMaintenance() &&
m_data.edition.getType() == Edition::kBasic) {
m_data.edition.setType(kLite);
} else if (
m_data.keyType.isMaintenance() &&
m_data.edition.getType() == Edition::kPro) {
m_data.edition.setType(kUltimate);
}
}
void SerialKeyParser::setWarningTime(const std::string &warnTime) {
sscanf(warnTime.c_str(), "%lld", &m_data.warnTime);
}
void SerialKeyParser::setExpirationTime(const std::string &expTime) {
sscanf(expTime.c_str(), "%lld", &m_data.expireTime);
}
std::string SerialKeyParser::decode(const std::string &serial) const {
static const char *const lut = "0123456789ABCDEF";
std::string output;
size_t len = serial.length();
if (len & 1) {
return output;
}
output.reserve(len / 2);
for (size_t i = 0; i < len; i += 2) {
char a = serial[i];
char b = serial[i + 1];
const auto p = std::lower_bound(lut, lut + 16, a);
const auto q = std::lower_bound(lut, lut + 16, b);
if (*q != b || *p != a) {
return output;
}
output.push_back(static_cast<char>(((p - lut) << 4) | (q - lut)));
}
return output;
}
bool SerialKeyParser::parse(const std::string &plainSerial) {
bool valid = false;
auto key = decode(plainSerial);
const auto parts = splitToParts(key);
if ((parts.size() == 8) && (parts.at(0).find("v1") != std::string::npos)) {
setKey(plainSerial);
parseV1(parts);
valid = true;
} else if (
(parts.size() == 9) && (parts.at(0).find("v2") != std::string::npos)) {
setKey(plainSerial);
parseV2(parts);
valid = true;
}
return valid;
}
const SerialKeyData &SerialKeyParser::getData() const { return m_data; }
void SerialKeyParser::parseV1(const std::vector<std::string> &parts) {
// e.g.: {v1;basic;Bob;1;email;company name;1398297600;1398384000}
setEdition(parts.at(1));
setWarningTime(parts.at(6));
setExpirationTime(parts.at(7));
}
void SerialKeyParser::parseV2(const std::vector<std::string> &parts) {
// e.g.: {v2;trial;basic;Bob;1;email;company name;1398297600;1398384000}
setType(parts.at(1));
setEdition(parts.at(2));
setWarningTime(parts.at(7));
setExpirationTime(parts.at(8));
}
std::vector<std::string>
SerialKeyParser::splitToParts(const std::string &plainSerial) const {
// tokenize serialised subscription.
std::vector<std::string> parts;
if (!plainSerial.empty()) {
std::string parityStart = plainSerial.substr(0, 1);
std::string parityEnd = plainSerial.substr(plainSerial.length() - 1, 1);
// check for parity chars { and }, record parity result, then remove them.
if (parityStart == "{" && parityEnd == "}") {
const auto serialData = plainSerial.substr(1, plainSerial.length() - 2);
std::string::size_type pos = 0;
bool look = true;
while (look) {
std::string::size_type start = pos;
pos = serialData.find(";", pos);
if (pos == std::string::npos) {
pos = serialData.length();
look = false;
}
parts.push_back(serialData.substr(start, pos - start));
pos += 1;
}
}
}
return parts;
}

Some files were not shown because too many files have changed in this diff Show more