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:
parent
07b1ea203f
commit
689737ee7a
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
|
@ -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;
|
||||||
|
};
|
|
@ -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());
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue