Fingerprint file check and trust logic #4522

Also refactored the 'get profile dir' code to use the core interface
(reduce code duplication)
This commit is contained in:
Nick Bolton 2015-04-15 13:09:22 +01:00
parent 07b1ea203f
commit 689737ee7a
5 changed files with 202 additions and 44 deletions

View File

@ -55,7 +55,8 @@ SOURCES += src/main.cpp \
src/WebClient.cpp \ src/WebClient.cpp \
src/PluginWizardPage.cpp \ src/PluginWizardPage.cpp \
src/PluginManager.cpp \ src/PluginManager.cpp \
src/CoreInterface.cpp src/CoreInterface.cpp \
src/Fingerprint.cpp
HEADERS += src/MainWindow.h \ HEADERS += src/MainWindow.h \
src/AboutDialog.h \ src/AboutDialog.h \
src/ServerConfig.h \ src/ServerConfig.h \
@ -97,7 +98,8 @@ HEADERS += src/MainWindow.h \
src/PluginWizardPage.h \ src/PluginWizardPage.h \
src/ProcessorArch.h \ src/ProcessorArch.h \
src/PluginManager.h \ src/PluginManager.h \
src/CoreInterface.h src/CoreInterface.h \
src/Fingerprint.h
RESOURCES += res/Synergy.qrc RESOURCES += res/Synergy.qrc
RC_FILE = res/win/Synergy.rc RC_FILE = res/win/Synergy.rc
macx { macx {

104
src/gui/src/Fingerprint.cpp Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "Fingerprint.h"
#include "CoreInterface.h"
#include <QDir>
#include <QTextStream>
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);
}

38
src/gui/src/Fingerprint.h Normal file
View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QString>
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;
};

View File

@ -21,6 +21,8 @@
#include <iostream> #include <iostream>
#include "MainWindow.h" #include "MainWindow.h"
#include "Fingerprint.h"
#include "AboutDialog.h" #include "AboutDialog.h"
#include "ServerConfigDialog.h" #include "ServerConfigDialog.h"
#include "SettingsDialog.h" #include "SettingsDialog.h"
@ -396,32 +398,48 @@ void MainWindow::updateStateFromLogLine(const QString &line)
setSynergyState(synergyConnected); setSynergyState(synergyConnected);
} }
checkFingerprint(line);
}
void MainWindow::checkFingerprint(const QString& line)
{
QRegExp fingerprintRegex(".*server fingerprint: ([A-F0-9:]+)"); QRegExp fingerprintRegex(".*server fingerprint: ([A-F0-9:]+)");
if (fingerprintRegex.exactMatch(line)) { if (!fingerprintRegex.exactMatch(line)) {
return;
}
QString fingerprint = fingerprintRegex.cap(1); QString fingerprint = fingerprintRegex.cap(1);
QMessageBox::StandardButton fingerprintReply = if (Fingerprint::trustedServers().check(fingerprint)) {
QMessageBox::information( return;
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) { QMessageBox::StandardButton fingerprintReply =
// TODO: save to file QMessageBox::information(
qDebug() << "fingerprint: " << fingerprint; this, tr("Security question"),
} tr("Do you trust this fingerprint?\n\n"
else { "%1\n\n"
stopSynergy(); "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) #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 #endif
if ((synergyType() == synergyClient && !clientArgs(args, app)) if ((synergyType() == synergyClient && !clientArgs(args, app))
@ -1251,25 +1273,17 @@ void MainWindow::bonjourInstallFinished()
m_pCheckBoxAutoConfig->setChecked(true); 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) #if defined(Q_OS_WIN)
dir.replace("\\Synergy", "");
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", "");
#else #else
dir.replace("/.synergy", "");
return "";
#endif #endif
}
QString MainWindow::getProfileDirectoryForArg() return QString("\"%1\"").arg(dir);
{
return QString("\"%1\"").arg(getProfileDirectory());
} }

View File

@ -165,8 +165,8 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
void downloadBonjour(); void downloadBonjour();
void promptAutoConfig(); void promptAutoConfig();
void updateEdition(); void updateEdition();
QString getProfileDirectory(); QString getProfileRootForArg();
QString getProfileDirectoryForArg(); void checkFingerprint(const QString& line);
private: private:
QSettings& m_Settings; QSettings& m_Settings;