1 /*
2 * synergy -- mouse and keyboard sharing utility
3 * Copyright (C) 2012-2016 Symless Ltd.
4 * Copyright (C) 2008 Volker Lanz (vl@fidra.de)
5 *
6 * This package is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * found in the file LICENSE that should have accompanied this file.
9 *
10 * This package is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "QSynergyApplication.h"
20 #include "AppConfig.h"
21 #include "QUtility.h"
22
23 #include <QtCore>
24 #include <QtNetwork>
25 #include <QtWidgets/QMessageBox>
26 #include <QPushButton>
27
28 #include "ConfigWriter.h"
29 #include "SslCertificate.h"
30
31 using GUI::Config::ConfigWriter;
32 #if defined(Q_OS_WIN)
33 const char AppConfig::m_SynergysName[] = "synergys.exe";
34 const char AppConfig::m_SynergycName[] = "synergyc.exe";
35 const char AppConfig::m_SynergyLogDir[] = "log/";
36 const char AppConfig::synergyConfigName[] = "synergy.sgc";
37 #define DEFAULT_PROCESS_MODE Service
38 #else
39 const char AppConfig::m_SynergysName[] = "synergys";
40 const char AppConfig::m_SynergycName[] = "synergyc";
41 const char AppConfig::m_SynergyLogDir[] = "/var/log/";
42 const char AppConfig::synergyConfigName[] = "synergy.conf";
43 #define DEFAULT_PROCESS_MODE Desktop
44 #endif
45
46 const ElevateMode defaultElevateMode = ElevateAsNeeded;
47
48 const char* AppConfig::m_SynergySettingsName[] = {
49 "screenName",
50 "port",
51 "interface",
52 "logLevel2",
53 "logToFile",
54 "logFilename",
55 "wizardLastRun",
56 "language",
57 "startedBefore",
58 "autoConfig",
59 "autoConfigServer",
60 "elevateMode",
61 "elevateModeEnum",
62 "edition",
63 "cryptoEnabled",
64 "autoHide",
65 "serialKey",
66 "lastVersion",
67 "lastExpiringWarningTime",
68 "activationHasRun",
69 "minimizeToTray",
70 "ActivateEmail",
71 "loadFromSystemScope",
72 "groupServerChecked",
73 "useExternalConfig",
74 "configFile",
75 "useInternalConfig",
76 "groupClientChecked",
77 "serverHostname",
78 "tlsCertPath",
79 "tlsKeyLength",
80 };
81
82 static const char* logLevelNames[] =
83 {
84 "INFO",
85 "DEBUG",
86 "DEBUG1",
87 "DEBUG2"
88 };
89
AppConfig()90 AppConfig::AppConfig() :
91 m_ScreenName(),
92 m_Port(24800),
93 m_Interface(),
94 m_LogLevel(0),
95 m_WizardLastRun(0),
96 m_ProcessMode(DEFAULT_PROCESS_MODE),
97 m_AutoConfig(true),
98 m_ElevateMode(defaultElevateMode),
99 m_CryptoEnabled(false),
100 m_AutoHide(false),
101 m_LastExpiringWarningTime(0),
102 m_AutoConfigServer(),
103 m_MinimizeToTray(false),
104 m_Edition(kUnregistered),
105 m_LogToFile(),
106 m_StartedBefore(),
107 m_ActivationHasRun(),
108 m_ServerGroupChecked(),
109 m_UseExternalConfig(),
110 m_UseInternalConfig(),
111 m_ClientGroupChecked(),
112 m_LoadFromSystemScope()
113 {
114
115 auto writer = ConfigWriter::make();
116
117 //Register this class to receive global load and saves
118 writer->registerClass(this);
119 writer->globalLoad();
120
121 //User settings exist and the load from system scope variable is true
122 if (writer->hasSetting(settingName(kLoadSystemSettings), ConfigWriter::kUser)) {
123 setLoadFromSystemScope(m_LoadFromSystemScope);
124 }
125 //If user setting don't exist but system ones do, load the system settings
126 else if (writer->hasSetting(settingName(kScreenName), ConfigWriter::kSystem)) {
127 setLoadFromSystemScope(true);
128 }
129 }
130
screenName() const131 const QString &AppConfig::screenName() const { return m_ScreenName; }
132
port() const133 int AppConfig::port() const { return m_Port; }
134
networkInterface() const135 const QString &AppConfig::networkInterface() const { return m_Interface; }
136
logLevel() const137 int AppConfig::logLevel() const { return m_LogLevel; }
138
logToFile() const139 bool AppConfig::logToFile() const { return m_LogToFile; }
140
logFilename() const141 const QString &AppConfig::logFilename() const { return m_LogFilename; }
142
synergyLogDir() const143 QString AppConfig::synergyLogDir() const
144 {
145 // by default log to home dir
146 return QDir::home().absolutePath() + "/";
147 }
148
synergyProgramDir() const149 QString AppConfig::synergyProgramDir() const
150 {
151 // synergy binaries should be in the same dir.
152 return QCoreApplication::applicationDirPath() + "/";
153 }
154
persistLogDir()155 void AppConfig::persistLogDir()
156 {
157 QDir dir = synergyLogDir();
158
159 // persist the log directory
160 if (!dir.exists())
161 {
162 dir.mkpath(dir.path());
163 }
164 }
165
logFilenameCmd() const166 const QString AppConfig::logFilenameCmd() const
167 {
168 QString filename = m_LogFilename;
169 #if defined(Q_OS_WIN)
170 // wrap in quotes in case username contains spaces.
171 filename = QString("\"%1\"").arg(filename);
172 #endif
173 return filename;
174 }
175
logLevelText() const176 QString AppConfig::logLevelText() const
177 {
178 return logLevelNames[logLevel()];
179 }
180
processMode() const181 ProcessMode AppConfig::processMode() const { return m_ProcessMode; }
182
wizardShouldRun() const183 bool AppConfig::wizardShouldRun() const { return m_WizardLastRun < kWizardVersion; }
184
language() const185 const QString &AppConfig::language() const { return m_Language; }
186
startedBefore() const187 bool AppConfig::startedBefore() const { return m_StartedBefore; }
188
autoConfig() const189 bool AppConfig::autoConfig() const {
190 #if !defined(SYNERGY_ENTERPRISE) && defined(SYNERGY_AUTOCONFIG)
191 return m_AutoConfig;
192 #else
193 // always disable auto config for enterprise edition.
194 return false;
195 #endif
196 }
197
autoConfigServer() const198 QString AppConfig::autoConfigServer() const { return m_AutoConfigServer; }
199
loadSettings()200 void AppConfig::loadSettings()
201 {
202 m_ScreenName = loadSetting(kScreenName, QHostInfo::localHostName()).toString();
203 if (m_ScreenName.isEmpty()) {
204 m_ScreenName = QHostInfo::localHostName();
205 }
206
207 m_Port = loadSetting(kPort, 24800).toInt();
208 m_Interface = loadSetting(kInterfaceSetting).toString();
209 m_LogLevel = loadSetting(kLogLevel, 0).toInt();
210 m_LogToFile = loadSetting(kLogToFile, false).toBool();
211 m_LogFilename = loadSetting(kLogFilename, synergyLogDir() + "synergy.log").toString();
212 m_WizardLastRun = loadCommonSetting(kWizardLastRun, 0).toInt();
213 m_Language = loadSetting(kLanguage, QLocale::system().name()).toString();
214 m_StartedBefore = loadSetting(kStartedBefore, false).toBool();
215 m_AutoConfig = loadSetting(kAutoConfig, false).toBool();
216 m_AutoConfigServer = loadSetting(kAutoConfigServer, "").toString();
217
218 { //Scope related code together
219 // TODO Investigate why kElevateModeEnum isn't loaded fully
220 QVariant elevateMode = loadSetting(kElevateModeEnum);
221 if (!elevateMode.isValid()) {
222 elevateMode = loadSetting(kElevateModeSetting,
223 QVariant(static_cast<int>(defaultElevateMode)));
224 }
225 m_ElevateMode = static_cast<ElevateMode>(elevateMode.toInt());
226 }
227
228 m_ActivateEmail = loadSetting(kActivateEmail, "").toString();
229 m_CryptoEnabled = loadSetting(kCryptoEnabled, true).toBool();
230 m_AutoHide = loadSetting(kAutoHide, false).toBool();
231 m_lastVersion = loadSetting(kLastVersion, "Unknown").toString();
232 m_LastExpiringWarningTime = loadSetting(kLastExpireWarningTime, 0).toInt();
233 m_ActivationHasRun = loadSetting(kActivationHasRun, false).toBool();
234 m_MinimizeToTray = loadSetting(kMinimizeToTray, false).toBool();
235 m_LoadFromSystemScope = loadCommonSetting(kLoadSystemSettings, false).toBool();
236 m_ServerGroupChecked = loadSetting(kGroupServerCheck, false).toBool();
237 m_UseExternalConfig = loadSetting(kUseExternalConfig, false).toBool();
238 m_ConfigFile = loadSetting(kConfigFile, QDir::homePath() + "/" + synergyConfigName).toString();
239 m_UseInternalConfig = loadSetting(kUseInternalConfig, false).toBool();
240 m_ClientGroupChecked = loadSetting(kGroupClientCheck, false).toBool();
241 m_ServerHostname = loadSetting(kServerHostname).toString();
242
243 //only change the serial key if the settings being loaded contains a key
244 bool updateSerial = ConfigWriter::make()
245 ->hasSetting(settingName(kLoadSystemSettings),ConfigWriter::kCurrent);
246 //if the setting exists and is not empty
247 updateSerial = updateSerial && !loadSetting(kSerialKey, "").toString().trimmed().isEmpty();
248
249 if (updateSerial) {
250 m_Serialkey = loadSetting(kSerialKey, "").toString().trimmed();
251 m_Edition = static_cast<Edition>(loadSetting(kEditionSetting, kUnregistered).toInt());
252 }
253
254 //Set the default path of the TLS certificate file in the users DIR
255 QString certificateFilename = QString("%1/%2/%3").arg(m_CoreInterface.getProfileDir(),
256 "SSL",
257 "Synergy.pem");
258
259 m_TLSCertificatePath = loadSetting(kTLSCertPath, certificateFilename).toString();
260 m_TLSKeyLength = loadSetting(kTLSKeyLength, "2048").toString();
261
262 if (getCryptoEnabled()) {
263 generateCertificate();
264 }
265
266 }
267
saveSettings()268 void AppConfig::saveSettings()
269 {
270 setCommonSetting(kWizardLastRun, m_WizardLastRun);
271 setCommonSetting(kLoadSystemSettings, m_LoadFromSystemScope);
272
273 if (isWritable()) {
274 setSetting(kScreenName, m_ScreenName);
275 setSetting(kPort, m_Port);
276 setSetting(kInterfaceSetting, m_Interface);
277 setSetting(kLogLevel, m_LogLevel);
278 setSetting(kLogToFile, m_LogToFile);
279 setSetting(kLogFilename, m_LogFilename);
280 setSetting(kLanguage, m_Language);
281 setSetting(kStartedBefore, m_StartedBefore);
282 setSetting(kAutoConfig, m_AutoConfig);
283 setSetting(kAutoConfigServer, m_AutoConfigServer);
284 // Refer to enum ElevateMode declaration for insight in to why this
285 // flag is mapped this way
286 setSetting(kElevateModeSetting, m_ElevateMode == ElevateAlways);
287 setSetting(kElevateModeEnum, static_cast<int>(m_ElevateMode));
288 setSetting(kEditionSetting, m_Edition);
289 setSetting(kCryptoEnabled, m_CryptoEnabled);
290 setSetting(kAutoHide, m_AutoHide);
291 setSetting(kSerialKey, m_Serialkey);
292 setSetting(kLastVersion, m_lastVersion);
293 setSetting(kLastExpireWarningTime, m_LastExpiringWarningTime);
294 setSetting(kActivationHasRun, m_ActivationHasRun);
295 setSetting(kMinimizeToTray, m_MinimizeToTray);
296 setSetting(kGroupServerCheck, m_ServerGroupChecked);
297 setSetting(kUseExternalConfig, m_UseExternalConfig);
298 setSetting(kConfigFile, m_ConfigFile);
299 setSetting(kUseInternalConfig, m_UseInternalConfig);
300 setSetting(kGroupClientCheck, m_ClientGroupChecked);
301 setSetting(kServerHostname, m_ServerHostname);
302 }
303
304 m_unsavedChanges = false;
305 }
306
307 #ifndef SYNERGY_ENTERPRISE
activationHasRun() const308 bool AppConfig::activationHasRun() const
309 {
310 return m_ActivationHasRun;
311 }
312
activationHasRun(bool value)313 AppConfig& AppConfig::activationHasRun(bool value)
314 {
315 m_ActivationHasRun = value;
316 return *this;
317 }
318 #endif
319
lastVersion() const320 QString AppConfig::lastVersion() const
321 {
322 return m_lastVersion;
323 }
324
setLastVersion(const QString & version)325 void AppConfig::setLastVersion(const QString& version) {
326 setSettingModified(m_lastVersion, version);
327 }
328
setScreenName(const QString & s)329 void AppConfig::setScreenName(const QString &s) {
330 setSettingModified(m_ScreenName, s);
331 emit screenNameChanged();
332 }
333
setPort(int i)334 void AppConfig::setPort(int i) {
335 setSettingModified(m_Port, i);
336 }
337
setNetworkInterface(const QString & s)338 void AppConfig::setNetworkInterface(const QString &s) {
339 setSettingModified(m_Interface, s);
340 }
341
setLogLevel(int i)342 void AppConfig::setLogLevel(int i) {
343 setSettingModified(m_LogLevel, i);
344 }
345
setLogToFile(bool b)346 void AppConfig::setLogToFile(bool b) {
347 setSettingModified(m_LogToFile, b);
348 }
349
setLogFilename(const QString & s)350 void AppConfig::setLogFilename(const QString &s) {
351 setSettingModified(m_LogFilename, s);
352 }
353
setWizardHasRun()354 void AppConfig::setWizardHasRun() {
355 setSettingModified(m_WizardLastRun, kWizardVersion);
356 }
357
setLanguage(const QString & language)358 void AppConfig::setLanguage(const QString& language) {
359 setSettingModified(m_Language, language);
360 }
361
setStartedBefore(bool b)362 void AppConfig::setStartedBefore(bool b) {
363 setSettingModified(m_StartedBefore, b);
364 }
365
setElevateMode(ElevateMode em)366 void AppConfig::setElevateMode(ElevateMode em) {
367 setSettingModified(m_ElevateMode, em);
368 }
369
setAutoConfig(bool autoConfig)370 void AppConfig::setAutoConfig(bool autoConfig)
371 {
372 setSettingModified(m_AutoConfig, autoConfig);
373 emit zeroConfToggled();
374 }
375
setAutoConfigServer(const QString & autoConfigServer)376 void AppConfig::setAutoConfigServer(const QString& autoConfigServer)
377 {
378 setSettingModified(m_AutoConfigServer, autoConfigServer);
379 }
380
381 #ifndef SYNERGY_ENTERPRISE
setEdition(Edition e)382 void AppConfig::setEdition(Edition e) {
383 setSettingModified(m_Edition, e);
384 setCommonSetting(kEditionSetting, m_Edition);
385 }
386
edition() const387 Edition AppConfig::edition() const { return m_Edition; }
388
setSerialKey(const QString & serial)389 void AppConfig::setSerialKey(const QString& serial) {
390 setSettingModified(m_Serialkey, serial);
391 setCommonSetting(kSerialKey, m_Serialkey);
392 }
393
clearSerialKey()394 void AppConfig::clearSerialKey()
395 {
396 m_Serialkey.clear();
397 }
398
serialKey()399 QString AppConfig::serialKey() { return m_Serialkey; }
400
lastExpiringWarningTime() const401 int AppConfig::lastExpiringWarningTime() const { return m_LastExpiringWarningTime; }
402
setLastExpiringWarningTime(int newValue)403 void AppConfig::setLastExpiringWarningTime(int newValue) {
404 setSettingModified(m_LastExpiringWarningTime, newValue);
405 }
406 #endif
407
synergysName() const408 QString AppConfig::synergysName() const { return m_SynergysName; }
409
synergycName() const410 QString AppConfig::synergycName() const { return m_SynergycName; }
411
elevateMode()412 ElevateMode AppConfig::elevateMode()
413 {
414 return m_ElevateMode;
415 }
416
setCryptoEnabled(bool newValue)417 void AppConfig::setCryptoEnabled(bool newValue) {
418 if (m_CryptoEnabled != newValue && newValue){
419 generateCertificate();
420 }
421 else {
422 emit sslToggled();
423 }
424 setSettingModified(m_CryptoEnabled, newValue);
425 }
426
isCryptoAvailable() const427 bool AppConfig::isCryptoAvailable() const {
428 bool result {true};
429
430 #ifndef SYNERGY_ENTERPRISE
431 result = (edition() == kPro || edition() == kPro_China || edition() == kBusiness);
432 #endif
433
434 return result;
435 }
436
getCryptoEnabled() const437 bool AppConfig::getCryptoEnabled() const {
438 return isCryptoAvailable() && m_CryptoEnabled;
439 }
440
setAutoHide(bool b)441 void AppConfig::setAutoHide(bool b) {
442 setSettingModified(m_AutoHide, b);
443 }
444
getAutoHide()445 bool AppConfig::getAutoHide() { return m_AutoHide; }
446
setMinimizeToTray(bool newValue)447 void AppConfig::setMinimizeToTray(bool newValue) {
448 setSettingModified(m_MinimizeToTray, newValue);
449 }
450
getLanguageSync() const451 bool AppConfig::getLanguageSync() const { return m_LanguageSync; }
452
setLanguageSync(bool newValue)453 void AppConfig::setLanguageSync(bool newValue) {
454 setSettingModified(m_LanguageSync, newValue);
455 }
456
getMinimizeToTray()457 bool AppConfig::getMinimizeToTray() { return m_MinimizeToTray; }
458
settingName(AppConfig::Setting name)459 QString AppConfig::settingName(AppConfig::Setting name) {
460 return m_SynergySettingsName[name];
461 }
462
463 template<typename T>
setSetting(AppConfig::Setting name,T value)464 void AppConfig::setSetting(AppConfig::Setting name, T value) {
465 ConfigWriter::make()->setSetting(settingName(name), value);
466 }
467
468 template<typename T>
setCommonSetting(AppConfig::Setting name,T value)469 void AppConfig::setCommonSetting(AppConfig::Setting name, T value) {
470 ConfigWriter::make()->setSetting(settingName(name), value, ConfigWriter::kUser);
471 ConfigWriter::make()->setSetting(settingName(name), value, ConfigWriter::kSystem);
472 }
473
loadSetting(AppConfig::Setting name,const QVariant & defaultValue)474 QVariant AppConfig::loadSetting(AppConfig::Setting name, const QVariant& defaultValue) {
475 return ConfigWriter::make()->loadSetting(settingName(name), defaultValue);
476 }
477
loadCommonSetting(AppConfig::Setting name,const QVariant & defaultValue) const478 QVariant AppConfig::loadCommonSetting(AppConfig::Setting name, const QVariant& defaultValue) const {
479 QVariant result(defaultValue);
480 QString setting(settingName(name));
481 auto& writer = *ConfigWriter::make();
482
483 if (writer.hasSetting(setting)) {
484 result = writer.loadSetting(setting, defaultValue);
485 }
486 else if (writer.getScope() == ConfigWriter::kSystem ) {
487 if (writer.hasSetting(setting, ConfigWriter::kUser)) {
488 result = writer.loadSetting(setting, defaultValue, ConfigWriter::kUser);
489 }
490 }
491 else if (writer.hasSetting(setting, ConfigWriter::kSystem)){
492 result = writer.loadSetting(setting, defaultValue, ConfigWriter::kSystem);
493 }
494
495 return result;
496 }
497
loadScope(ConfigWriter::Scope scope) const498 void AppConfig::loadScope(ConfigWriter::Scope scope) const {
499 auto writer = ConfigWriter::make();
500
501 if (writer->getScope() != scope) {
502 writer->setScope(scope);
503 if (writer->hasSetting(settingName(kScreenName), writer->getScope())) {
504 //If the user already has settings, then load them up now.
505 writer->globalLoad();
506 }
507 }
508 }
509
setLoadFromSystemScope(bool value)510 void AppConfig::setLoadFromSystemScope(bool value) {
511
512 if (value) {
513 loadScope(ConfigWriter::kSystem);
514 }
515 else {
516 loadScope(ConfigWriter::kUser);
517 }
518
519 /*
520 * It's very imprortant to set this variable after loadScope
521 * because during scope loading this variable can be rewritten with old value
522 */
523 m_LoadFromSystemScope = value;
524 }
525
isWritable() const526 bool AppConfig::isWritable() const {
527 return ConfigWriter::make()->isWritable();
528 }
529
isSystemScoped() const530 bool AppConfig::isSystemScoped() const {
531 return ConfigWriter::make()->getScope() == ConfigWriter::kSystem;
532 }
533
getServerGroupChecked() const534 bool AppConfig::getServerGroupChecked() const {
535 return m_ServerGroupChecked;
536 }
537
getUseExternalConfig() const538 bool AppConfig::getUseExternalConfig() const {
539 return m_UseExternalConfig;
540 }
541
getConfigFile() const542 const QString& AppConfig::getConfigFile() const {
543 return m_ConfigFile;
544 }
545
getUseInternalConfig() const546 bool AppConfig::getUseInternalConfig() const {
547 return m_UseInternalConfig;
548 }
549
getClientGroupChecked() const550 bool AppConfig::getClientGroupChecked() const {
551 return m_ClientGroupChecked;
552 }
553
getServerHostname() const554 QString AppConfig::getServerHostname() const {
555 return m_ServerHostname;
556 }
557
setServerGroupChecked(bool newValue)558 void AppConfig::setServerGroupChecked(bool newValue) {
559 setSettingModified(m_ServerGroupChecked, newValue);
560 }
561
setUseExternalConfig(bool newValue)562 void AppConfig::setUseExternalConfig(bool newValue) {
563 setSettingModified(m_UseExternalConfig, newValue);
564 }
565
setConfigFile(const QString & newValue)566 void AppConfig::setConfigFile(const QString& newValue) {
567 setSettingModified(m_ConfigFile, newValue);
568 }
569
setUseInternalConfig(bool newValue)570 void AppConfig::setUseInternalConfig(bool newValue) {
571 setSettingModified(m_UseInternalConfig, newValue);
572 }
573
setClientGroupChecked(bool newValue)574 void AppConfig::setClientGroupChecked(bool newValue) {
575 setSettingModified(m_ClientGroupChecked, newValue);
576 }
577
setServerHostname(const QString & newValue)578 void AppConfig::setServerHostname(const QString& newValue) {
579 setSettingModified(m_ServerHostname, newValue);
580 }
581
582 template<typename T>
setSettingModified(T & variable,const T & newValue)583 void AppConfig::setSettingModified(T &variable, const T& newValue) {
584 if (variable != newValue)
585 {
586 variable = newValue;
587 m_unsavedChanges = true;
588 }
589 }
590
setTLSCertPath(const QString & path)591 void AppConfig::setTLSCertPath(const QString& path) {
592 m_TLSCertificatePath = path;
593 }
594
getTLSCertPath() const595 QString AppConfig::getTLSCertPath() const {
596 return m_TLSCertificatePath;
597 }
598
getTLSKeyLength() const599 QString AppConfig::getTLSKeyLength() const {
600 return m_TLSKeyLength;
601 }
602
setTLSKeyLength(const QString & length)603 void AppConfig::setTLSKeyLength(const QString& length) {
604 if (m_TLSKeyLength != length) {
605 m_TLSKeyLength = length;
606 generateCertificate(true);
607 }
608 }
609
generateCertificate(bool forceGeneration) const610 void AppConfig::generateCertificate(bool forceGeneration) const {
611 SslCertificate sslCertificate;
612 sslCertificate.generateCertificate(getTLSCertPath(), getTLSKeyLength(), forceGeneration);
613 emit sslToggled();
614 }
615
616
617