diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 4f8fcabb..7f2670be 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -55,7 +55,8 @@ SOURCES += src/main.cpp \ src/WebClient.cpp \ src/PluginWizardPage.cpp \ src/PluginManager.cpp \ - src/CoreInterface.cpp + src/CoreInterface.cpp \ + src/Fingerprint.cpp HEADERS += src/MainWindow.h \ src/AboutDialog.h \ src/ServerConfig.h \ @@ -97,7 +98,8 @@ HEADERS += src/MainWindow.h \ src/PluginWizardPage.h \ src/ProcessorArch.h \ src/PluginManager.h \ - src/CoreInterface.h + src/CoreInterface.h \ + src/Fingerprint.h RESOURCES += res/Synergy.qrc RC_FILE = res/win/Synergy.rc macx { diff --git a/src/gui/src/Fingerprint.cpp b/src/gui/src/Fingerprint.cpp new file mode 100644 index 00000000..0ff15a44 --- /dev/null +++ b/src/gui/src/Fingerprint.cpp @@ -0,0 +1,104 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2015 Synergy Si 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 COPYING that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "Fingerprint.h" + +#include "CoreInterface.h" + +#include +#include + +static const char kDirName[] = "ssl/fingerprints"; +static const char kLocalFilename[] = "local.txt"; +static const char kTrustedServersFilename[] = "trusted-servers.txt"; +static const char kTrustedClientsFilename[] = "trusted-clients.txt"; + +Fingerprint::Fingerprint(const QString& filename) +{ + m_Filename = filename; +} + +void Fingerprint::trust(const QString& fingerprintText) +{ + CoreInterface coreInterface; + QString profileDir = coreInterface.getProfileDir(); + + QString dirName = QString("%1/%2") + .arg(profileDir) + .arg(kDirName); + + QDir dir(dirName); + if (!dir.exists()) { + dir.mkpath("."); + } + + QString path = QString("%1/%2").arg(dirName).arg(m_Filename); + QFile file(path); + if (file.open(QIODevice::Append)) + { + QTextStream out(&file); + out << fingerprintText << "\n"; + file.close(); + } +} + +bool Fingerprint::check(const QString& fingerprintText) +{ + CoreInterface coreInterface; + QString profileDir = coreInterface.getProfileDir(); + + QString dirName = QString("%1/%2") + .arg(profileDir) + .arg(kDirName); + + if (!QDir(dirName).exists()) { + return false; + } + + QString path = QString("%1/%2").arg(dirName).arg(m_Filename); + QFile file(path); + + if (file.open(QIODevice::ReadOnly)) + { + QTextStream in(&file); + while (!in.atEnd()) + { + QString trusted = in.readLine(); + if (fingerprintText == trusted) { + return true; + } + } + file.close(); + } + + return false; +} + +Fingerprint Fingerprint::local() +{ + return Fingerprint(kLocalFilename); +} + +Fingerprint Fingerprint::trustedServers() +{ + return Fingerprint(kTrustedServersFilename); +} + +Fingerprint Fingerprint::trustedClients() +{ + return Fingerprint(kTrustedClientsFilename); +} diff --git a/src/gui/src/Fingerprint.h b/src/gui/src/Fingerprint.h new file mode 100644 index 00000000..d494af0b --- /dev/null +++ b/src/gui/src/Fingerprint.h @@ -0,0 +1,38 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2015 Synergy Si 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 COPYING that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +class Fingerprint +{ +private: + Fingerprint(const QString& filename); + +public: + void trust(const QString& fingerprintText); + bool check(const QString& fingerprintText); + +public: + static Fingerprint local(); + static Fingerprint trustedServers(); + static Fingerprint trustedClients(); + +private: + QString m_Filename; +}; diff --git a/src/gui/src/MainWindow.cpp b/src/gui/src/MainWindow.cpp index 234370ed..c4e8b0fc 100644 --- a/src/gui/src/MainWindow.cpp +++ b/src/gui/src/MainWindow.cpp @@ -21,6 +21,8 @@ #include #include "MainWindow.h" + +#include "Fingerprint.h" #include "AboutDialog.h" #include "ServerConfigDialog.h" #include "SettingsDialog.h" @@ -396,32 +398,48 @@ void MainWindow::updateStateFromLogLine(const QString &line) setSynergyState(synergyConnected); } + checkFingerprint(line); +} + +void MainWindow::checkFingerprint(const QString& line) +{ QRegExp fingerprintRegex(".*server fingerprint: ([A-F0-9:]+)"); - if (fingerprintRegex.exactMatch(line)) { + if (!fingerprintRegex.exactMatch(line)) { + return; + } - QString fingerprint = fingerprintRegex.cap(1); - QMessageBox::StandardButton fingerprintReply = - QMessageBox::information( - this, tr("Security question"), - tr("Do you trust this fingerprint?\n\n" - "%1\n\n" - "This is a server fingerprint. You should compare this " - "fingerprint to the one on your server's screen. If the " - "two don't match exactly, then it's probably not the server " - "you're expecting (it could be a malicious user).\n\n" - "To automatically trust this fingerprint for future " - "connections, click Yes. To reject this fingerprint and " - "disconnect from the server, click No.") - .arg(fingerprint), - QMessageBox::Yes | QMessageBox::No); + QString fingerprint = fingerprintRegex.cap(1); + if (Fingerprint::trustedServers().check(fingerprint)) { + return; + } - if (fingerprintReply == QMessageBox::Yes) { - // TODO: save to file - qDebug() << "fingerprint: " << fingerprint; - } - else { - stopSynergy(); - } + QMessageBox::StandardButton fingerprintReply = + QMessageBox::information( + this, tr("Security question"), + tr("Do you trust this fingerprint?\n\n" + "%1\n\n" + "This is a server fingerprint. You should compare this " + "fingerprint to the one on your server's screen. If the " + "two don't match exactly, then it's probably not the server " + "you're expecting (it could be a malicious user).\n\n" + "To automatically trust this fingerprint for future " + "connections, click Yes. To reject this fingerprint and " + "disconnect from the server, click No.") + .arg(fingerprint), + QMessageBox::Yes | QMessageBox::No); + + if (fingerprintReply == QMessageBox::Yes) { + // restart core process after trusting fingerprint. + Fingerprint::trustedServers().trust(fingerprint); + startSynergy(); + } + else { + // on all platforms, the core process will stop if the + // fingerprint is not trusted, so technically the stop + // isn't really needed. however on windows, the core + // process will keep trying (and failing) unless we + // tell it to stop. + stopSynergy(); } } @@ -479,7 +497,11 @@ void MainWindow::startSynergy() } #if defined(Q_OS_WIN) - args << "--profile-dir" << getProfileDirectoryForArg(); + // on windows, the profile directory changes depending on the user that + // launched the process (e.g. when launched with elevation). setting the + // profile dir on launch ensures it uses the same profile dir is used + // no matter how its relaunched. + args << "--profile-dir" << getProfileRootForArg(); #endif if ((synergyType() == synergyClient && !clientArgs(args, app)) @@ -1251,25 +1273,17 @@ void MainWindow::bonjourInstallFinished() m_pCheckBoxAutoConfig->setChecked(true); } -QString MainWindow::getProfileDirectory() +QString MainWindow::getProfileRootForArg() { + CoreInterface coreInterface; + QString dir = coreInterface.getProfileDir(); + + // HACK: strip our app name since we're returning the root dir. #if defined(Q_OS_WIN) - - QString qtDataDir = QDesktopServices::storageLocation( - QDesktopServices::DataLocation); - - // HACK: core wants the base app data dir, this seems like a very hacky - // way to get it (maybe consider using %LOCALAPPDATA% instead?) - return qtDataDir.replace("\\Synergy\\Synergy", ""); - + dir.replace("\\Synergy", ""); #else - - return ""; - + dir.replace("/.synergy", ""); #endif -} -QString MainWindow::getProfileDirectoryForArg() -{ - return QString("\"%1\"").arg(getProfileDirectory()); + return QString("\"%1\"").arg(dir); } diff --git a/src/gui/src/MainWindow.h b/src/gui/src/MainWindow.h index b82984cf..9ab1b17b 100644 --- a/src/gui/src/MainWindow.h +++ b/src/gui/src/MainWindow.h @@ -165,8 +165,8 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase void downloadBonjour(); void promptAutoConfig(); void updateEdition(); - QString getProfileDirectory(); - QString getProfileDirectoryForArg(); + QString getProfileRootForArg(); + void checkFingerprint(const QString& line); private: QSettings& m_Settings;