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/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 {

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 "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);
}

View File

@ -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;