Merge branch 'master' into MacOSX-Sticky-Key-Fix
This commit is contained in:
commit
1a05bed6da
|
@ -15,3 +15,4 @@ src/gui/gui.pro.user
|
||||||
src/gui/.qmake.stash
|
src/gui/.qmake.stash
|
||||||
src/gui/.rnd
|
src/gui/.rnd
|
||||||
src/setup/win32/synergy.suo
|
src/setup/win32/synergy.suo
|
||||||
|
*.smbdelete*
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
# Version number for Synergy
|
# Version number for Synergy
|
||||||
set(VERSION_MAJOR 1)
|
set(VERSION_MAJOR 1)
|
||||||
set(VERSION_MINOR 7)
|
set(VERSION_MINOR 7)
|
||||||
set(VERSION_REV 1)
|
set(VERSION_REV 2)
|
||||||
set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REV}")
|
set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REV}")
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 2.6)
|
cmake_minimum_required(VERSION 2.6)
|
||||||
|
|
27
ChangeLog
27
ChangeLog
|
@ -1,3 +1,30 @@
|
||||||
|
v1.7.1
|
||||||
|
======
|
||||||
|
Bug #3784 - Double click & drag doesn't select words on client
|
||||||
|
Bug #3052 - Triple-click (select line) does not work
|
||||||
|
Bug #4367 - Duplicate Alt-S Keyboard Shortcuts on Gui
|
||||||
|
Bug #4554 - Server unable to accept new SSL connection
|
||||||
|
Bug #4553 - SSL handshake failure error causes GUI to crash
|
||||||
|
Bug #4551 - Plugin wizard doesn't create SSL directory
|
||||||
|
Bug #4548 - Severe code duplication in fingerprint logic
|
||||||
|
Bug #4547 - Windows server crashes when client fingerprint dialog open
|
||||||
|
Bug #4539 - Mac client dies when server has SSL_ERROR_SSL
|
||||||
|
Bug #4537 - Plugin wizard doesn't complete but finish button enabled
|
||||||
|
Bug #4535 - Server crashes on shut down after multiple connections failed
|
||||||
|
Bug #4528 - Error SSL_ERROR_SSL is logged on unknown error
|
||||||
|
Bug #4527 - Server fingerprint dialog on client GUI keeps showing
|
||||||
|
Bug #4469 - GUI crashes on Windows when generating certificate
|
||||||
|
Bug #4410 - SSL_ERROR_SSL (unknown protocol) on Mac client
|
||||||
|
Bug #4409 - SSL_ERROR_SSL (unknown alert type) on Windows 8.1 client
|
||||||
|
Bug #4557 - GUI doesn't show local fingerprint on fresh install
|
||||||
|
Enhancement #4522 - SSL server fingerprint verification from client
|
||||||
|
Enhancement #4526 - Display local fingerprint on server GUI
|
||||||
|
Enhancement #4549 - Extract SSL certificate and fingerprint generate function
|
||||||
|
Enhancement #4546 - Redistribute OpenSSL on Windows with installer
|
||||||
|
Enhancement #4540 - Enable Network Security checkbox only when ns plugin exists
|
||||||
|
Enhancement #4525 - Reorganize app data directory
|
||||||
|
Enhancement #4390 - Disable GUI auto-hide by default
|
||||||
|
|
||||||
1.7.0
|
1.7.0
|
||||||
=====
|
=====
|
||||||
Enhancement #4313 - SSL encrypted secure connection
|
Enhancement #4313 - SSL encrypted secure connection
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
#
|
||||||
|
# Synergy OpenSSL configuration file.
|
||||||
|
# Used for generation of certificate requests.
|
||||||
|
#
|
||||||
|
|
||||||
|
dir = .
|
||||||
|
|
||||||
|
[ca]
|
||||||
|
default_ca = CA_default
|
||||||
|
|
||||||
|
[CA_default]
|
||||||
|
serial = $dir/serial
|
||||||
|
database = $dir/certindex.txt
|
||||||
|
new_certs_dir = $dir/certs
|
||||||
|
certificate = $dir/cacert.pem
|
||||||
|
private_key = $dir/private/cakey.pem
|
||||||
|
default_days = 365
|
||||||
|
default_md = md5
|
||||||
|
preserve = no
|
||||||
|
email_in_dn = no
|
||||||
|
nameopt = default_ca
|
||||||
|
certopt = default_ca
|
||||||
|
policy = policy_match
|
||||||
|
|
||||||
|
[policy_match]
|
||||||
|
countryName = match
|
||||||
|
stateOrProvinceName = match
|
||||||
|
organizationName = match
|
||||||
|
organizationalUnitName = optional
|
||||||
|
commonName = supplied
|
||||||
|
emailAddress = optional
|
||||||
|
|
||||||
|
[req]
|
||||||
|
default_bits = 1024 # Size of keys
|
||||||
|
default_keyfile = key.pem # name of generated keys
|
||||||
|
default_md = md5 # message digest algorithm
|
||||||
|
string_mask = nombstr # permitted characters
|
||||||
|
distinguished_name = req_distinguished_name
|
||||||
|
req_extensions = v3_req
|
||||||
|
|
||||||
|
[req_distinguished_name]
|
||||||
|
0.organizationName = Organization Name (company)
|
||||||
|
organizationalUnitName = Organizational Unit Name (department, division)
|
||||||
|
emailAddress = Email Address
|
||||||
|
emailAddress_max = 40
|
||||||
|
localityName = Locality Name (city, district)
|
||||||
|
stateOrProvinceName = State or Province Name (full name)
|
||||||
|
countryName = Country Name (2 letter code)
|
||||||
|
countryName_min = 2
|
||||||
|
countryName_max = 2
|
||||||
|
commonName = Common Name (hostname, IP, or your name)
|
||||||
|
commonName_max = 64
|
||||||
|
0.organizationName_default = My Company
|
||||||
|
localityName_default = My Town
|
||||||
|
stateOrProvinceName_default = State or Providence
|
||||||
|
countryName_default = US
|
||||||
|
|
||||||
|
[v3_ca]
|
||||||
|
basicConstraints = CA:TRUE
|
||||||
|
subjectKeyIdentifier = hash
|
||||||
|
authorityKeyIdentifier = keyid:always,issuer:always
|
||||||
|
|
||||||
|
[v3_req]
|
||||||
|
basicConstraints = CA:FALSE
|
||||||
|
subjectKeyIdentifier = hash
|
|
@ -55,7 +55,9 @@ 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 \
|
||||||
|
src/SslCertificate.cpp
|
||||||
HEADERS += src/MainWindow.h \
|
HEADERS += src/MainWindow.h \
|
||||||
src/AboutDialog.h \
|
src/AboutDialog.h \
|
||||||
src/ServerConfig.h \
|
src/ServerConfig.h \
|
||||||
|
@ -97,7 +99,9 @@ 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 \
|
||||||
|
src/SslCertificate.h
|
||||||
RESOURCES += res/Synergy.qrc
|
RESOURCES += res/Synergy.qrc
|
||||||
RC_FILE = res/win/Synergy.rc
|
RC_FILE = res/win/Synergy.rc
|
||||||
macx {
|
macx {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>MainWindowBase</class>
|
<class>MainWindowBase</class>
|
||||||
<widget class="QMainWindow" name="MainWindowBase">
|
<widget class="QMainWindow" name="MainWindowBase">
|
||||||
|
@ -87,7 +87,7 @@
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>&Server (share this computer's mouse and keyboard):</string>
|
<string>Ser&ver (share this computer's mouse and keyboard):</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
|
@ -117,6 +117,30 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="m_pLabelFingerprint">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Fingerprint:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="m_pLabelLocalFingerprint">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="m_pRadioInternalConfig">
|
<widget class="QRadioButton" name="m_pRadioInternalConfig">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -128,7 +152,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="m_pButtonConfigureServer">
|
<widget class="QPushButton" name="m_pButtonConfigureServer">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
* 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[] = "TrustedServers.txt";
|
||||||
|
static const char kTrustedClientsFilename[] = "TrustedClients.txt";
|
||||||
|
|
||||||
|
Fingerprint::Fingerprint(const QString& filename)
|
||||||
|
{
|
||||||
|
m_Filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fingerprint::trust(const QString& fingerprintText, bool append)
|
||||||
|
{
|
||||||
|
Fingerprint::persistDirectory();
|
||||||
|
|
||||||
|
QIODevice::OpenMode openMode;
|
||||||
|
if (append) {
|
||||||
|
openMode = QIODevice::Append;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
openMode = QIODevice::WriteOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(filePath());
|
||||||
|
if (file.open(openMode))
|
||||||
|
{
|
||||||
|
QTextStream out(&file);
|
||||||
|
out << fingerprintText << "\n";
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Fingerprint::fileExists() const
|
||||||
|
{
|
||||||
|
QString dirName = Fingerprint::directoryPath();
|
||||||
|
if (!QDir(dirName).exists()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(filePath());
|
||||||
|
return file.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Fingerprint::isTrusted(const QString& fingerprintText)
|
||||||
|
{
|
||||||
|
QStringList list = readList();
|
||||||
|
foreach (QString trusted, list)
|
||||||
|
{
|
||||||
|
if (trusted == fingerprintText) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QStringList Fingerprint::readList(const int readTo)
|
||||||
|
{
|
||||||
|
QStringList list;
|
||||||
|
|
||||||
|
QString dirName = Fingerprint::directoryPath();
|
||||||
|
if (!QDir(dirName).exists()) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile file(filePath());
|
||||||
|
|
||||||
|
if (file.open(QIODevice::ReadOnly))
|
||||||
|
{
|
||||||
|
QTextStream in(&file);
|
||||||
|
while (!in.atEnd())
|
||||||
|
{
|
||||||
|
list.append(in.readLine());
|
||||||
|
if (list.size() == readTo) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Fingerprint::readFirst()
|
||||||
|
{
|
||||||
|
QStringList list = readList(1);
|
||||||
|
return list.at(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Fingerprint::filePath() const
|
||||||
|
{
|
||||||
|
QString dir = Fingerprint::directoryPath();
|
||||||
|
return QString("%1/%2").arg(dir).arg(m_Filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Fingerprint::persistDirectory()
|
||||||
|
{
|
||||||
|
QDir dir(Fingerprint::directoryPath());
|
||||||
|
if (!dir.exists()) {
|
||||||
|
dir.mkpath(".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString Fingerprint::directoryPath()
|
||||||
|
{
|
||||||
|
CoreInterface coreInterface;
|
||||||
|
QString profileDir = coreInterface.getProfileDir();
|
||||||
|
|
||||||
|
return QString("%1/%2")
|
||||||
|
.arg(profileDir)
|
||||||
|
.arg(kDirName);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fingerprint Fingerprint::local()
|
||||||
|
{
|
||||||
|
return Fingerprint(kLocalFilename);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fingerprint Fingerprint::trustedServers()
|
||||||
|
{
|
||||||
|
return Fingerprint(kTrustedServersFilename);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fingerprint Fingerprint::trustedClients()
|
||||||
|
{
|
||||||
|
return Fingerprint(kTrustedClientsFilename);
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* 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 append = true);
|
||||||
|
bool isTrusted(const QString& fingerprintText);
|
||||||
|
QStringList readList(const int readTo = -1);
|
||||||
|
QString readFirst();
|
||||||
|
QString filePath() const;
|
||||||
|
bool fileExists() const;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static Fingerprint local();
|
||||||
|
static Fingerprint trustedServers();
|
||||||
|
static Fingerprint trustedClients();
|
||||||
|
static QString directoryPath();
|
||||||
|
static QString localFingerprint();
|
||||||
|
static bool localFingerprintExists();
|
||||||
|
static void persistDirectory();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_Filename;
|
||||||
|
};
|
|
@ -21,6 +21,9 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
|
||||||
|
#include "Fingerprint.h"
|
||||||
|
#include "PluginManager.h"
|
||||||
#include "AboutDialog.h"
|
#include "AboutDialog.h"
|
||||||
#include "ServerConfigDialog.h"
|
#include "ServerConfigDialog.h"
|
||||||
#include "SettingsDialog.h"
|
#include "SettingsDialog.h"
|
||||||
|
@ -131,6 +134,8 @@ MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig) :
|
||||||
updateEdition();
|
updateEdition();
|
||||||
|
|
||||||
m_pLabelPadlock->hide();
|
m_pLabelPadlock->hide();
|
||||||
|
|
||||||
|
updateLocalFingerprint();
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow::~MainWindow()
|
MainWindow::~MainWindow()
|
||||||
|
@ -395,6 +400,50 @@ 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:]+)");
|
||||||
|
if (!fingerprintRegex.exactMatch(line)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString fingerprint = fingerprintRegex.cap(1);
|
||||||
|
if (Fingerprint::trustedServers().isTrusted(fingerprint)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::clearLog()
|
void MainWindow::clearLog()
|
||||||
|
@ -451,7 +500,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))
|
||||||
|
@ -492,14 +545,6 @@ void MainWindow::startSynergy()
|
||||||
|
|
||||||
if (desktopMode)
|
if (desktopMode)
|
||||||
{
|
{
|
||||||
if (!appConfig().startedBefore()) {
|
|
||||||
QMessageBox::information(
|
|
||||||
this, "Synergy",
|
|
||||||
tr("Synergy will be minimized to the notification "
|
|
||||||
"area. This will happen automatically when Synergy "
|
|
||||||
"starts."));
|
|
||||||
}
|
|
||||||
|
|
||||||
synergyProcess()->start(app, args);
|
synergyProcess()->start(app, args);
|
||||||
if (!synergyProcess()->waitForStarted())
|
if (!synergyProcess()->waitForStarted())
|
||||||
{
|
{
|
||||||
|
@ -757,12 +802,6 @@ void MainWindow::setSynergyState(qSynergyState state)
|
||||||
setIcon(state);
|
setIcon(state);
|
||||||
|
|
||||||
m_SynergyState = state;
|
m_SynergyState = state;
|
||||||
|
|
||||||
// if in desktop mode, hide synergy. in service mode the gui can
|
|
||||||
// just be closed.
|
|
||||||
if ((appConfig().processMode() == Desktop) && (state == synergyConnected)) {
|
|
||||||
hide();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setVisible(bool visible)
|
void MainWindow::setVisible(bool visible)
|
||||||
|
@ -893,6 +932,19 @@ void MainWindow::setEdition(int type)
|
||||||
setWindowTitle(title);
|
setWindowTitle(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::updateLocalFingerprint()
|
||||||
|
{
|
||||||
|
if (Fingerprint::local().fileExists()) {
|
||||||
|
m_pLabelFingerprint->setVisible(true);
|
||||||
|
m_pLabelLocalFingerprint->setVisible(true);
|
||||||
|
m_pLabelLocalFingerprint->setText(Fingerprint::local().readFirst());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_pLabelFingerprint->setVisible(false);
|
||||||
|
m_pLabelLocalFingerprint->setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::on_m_pGroupClient_toggled(bool on)
|
void MainWindow::on_m_pGroupClient_toggled(bool on)
|
||||||
{
|
{
|
||||||
m_pGroupServer->setChecked(!on);
|
m_pGroupServer->setChecked(!on);
|
||||||
|
@ -1172,6 +1224,7 @@ void MainWindow::updateEdition()
|
||||||
QString mac = getFirstMacAddress();
|
QString mac = getFirstMacAddress();
|
||||||
QString hashSrc = m_AppConfig.activateEmail() + mac;
|
QString hashSrc = m_AppConfig.activateEmail() + mac;
|
||||||
QString hashResult = hash(hashSrc);
|
QString hashResult = hash(hashSrc);
|
||||||
|
|
||||||
if (hashResult == m_AppConfig.userToken()) {
|
if (hashResult == m_AppConfig.userToken()) {
|
||||||
setEdition(m_AppConfig.edition());
|
setEdition(m_AppConfig.edition());
|
||||||
}
|
}
|
||||||
|
@ -1223,25 +1276,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());
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,6 +106,7 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
|
||||||
void updateZeroconfService();
|
void updateZeroconfService();
|
||||||
void serverDetected(const QString name);
|
void serverDetected(const QString name);
|
||||||
void setEdition(int type);
|
void setEdition(int type);
|
||||||
|
void updateLocalFingerprint();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void appendLogRaw(const QString& text);
|
void appendLogRaw(const QString& text);
|
||||||
|
@ -165,8 +166,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;
|
||||||
|
|
|
@ -22,10 +22,12 @@
|
||||||
#include "DataDownloader.h"
|
#include "DataDownloader.h"
|
||||||
#include "QUtility.h"
|
#include "QUtility.h"
|
||||||
#include "ProcessorArch.h"
|
#include "ProcessorArch.h"
|
||||||
|
#include "Fingerprint.h"
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
static QString kBaseUrl = "http://synergy-project.org/files";
|
static QString kBaseUrl = "http://synergy-project.org/files";
|
||||||
static const char kWinProcessorArch32[] = "Windows-x86";
|
static const char kWinProcessorArch32[] = "Windows-x86";
|
||||||
|
@ -35,15 +37,9 @@ static const char kLinuxProcessorArchDeb32[] = "Linux-i686-deb";
|
||||||
static const char kLinuxProcessorArchDeb64[] = "Linux-x86_64-deb";
|
static const char kLinuxProcessorArchDeb64[] = "Linux-x86_64-deb";
|
||||||
static const char kLinuxProcessorArchRpm32[] = "Linux-i686-rpm";
|
static const char kLinuxProcessorArchRpm32[] = "Linux-i686-rpm";
|
||||||
static const char kLinuxProcessorArchRpm64[] = "Linux-x86_64-rpm";
|
static const char kLinuxProcessorArchRpm64[] = "Linux-x86_64-rpm";
|
||||||
static QString kCertificateLifetime = "365";
|
|
||||||
static QString kCertificateSubjectInfo = "/CN=Synergy";
|
|
||||||
static QString kCertificateFilename = "Synergy.pem";
|
|
||||||
static QString kUnixOpenSslCommand = "openssl";
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
static const char kWinPluginExt[] = ".dll";
|
static const char kWinPluginExt[] = ".dll";
|
||||||
static const char kWinOpenSslSetup[] = "openssl-1.0.2-Windows-x86.exe";
|
|
||||||
static const char kWinOpenSslBinary[] = "OpenSSL\\openssl.exe";
|
|
||||||
|
|
||||||
#elif defined(Q_OS_MAC)
|
#elif defined(Q_OS_MAC)
|
||||||
static const char kMacPluginPrefix[] = "lib";
|
static const char kMacPluginPrefix[] = "lib";
|
||||||
|
@ -72,10 +68,30 @@ PluginManager::~PluginManager()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PluginManager::exist(QString name)
|
||||||
|
{
|
||||||
|
CoreInterface coreInterface;
|
||||||
|
QString PluginDir = coreInterface.getPluginDir();
|
||||||
|
QString pluginName = getPluginOsSpecificName(name);
|
||||||
|
QString filename;
|
||||||
|
filename.append(PluginDir);
|
||||||
|
filename.append(QDir::separator()).append(pluginName);
|
||||||
|
QFile file(filename);
|
||||||
|
bool exist = false;
|
||||||
|
if (file.exists()) {
|
||||||
|
exist = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return exist;
|
||||||
|
}
|
||||||
|
|
||||||
void PluginManager::downloadPlugins()
|
void PluginManager::downloadPlugins()
|
||||||
{
|
{
|
||||||
if (m_DataDownloader.isFinished()) {
|
if (m_DataDownloader.isFinished()) {
|
||||||
savePlugin();
|
if (!savePlugin()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_DownloadIndex != m_PluginList.size() - 1) {
|
if (m_DownloadIndex != m_PluginList.size() - 1) {
|
||||||
emit downloadNext();
|
emit downloadNext();
|
||||||
}
|
}
|
||||||
|
@ -101,59 +117,7 @@ void PluginManager::downloadPlugins()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginManager::saveOpenSslSetup()
|
bool PluginManager::savePlugin()
|
||||||
{
|
|
||||||
QDir dir(m_ProfileDir);
|
|
||||||
if (!dir.exists()) {
|
|
||||||
dir.mkpath(".");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
|
|
||||||
QString filename =
|
|
||||||
QString("%1\\%2")
|
|
||||||
.arg(m_ProfileDir)
|
|
||||||
.arg(kWinOpenSslSetup);
|
|
||||||
|
|
||||||
QFile file(filename);
|
|
||||||
if (!file.open(QIODevice::WriteOnly)) {
|
|
||||||
emit error(
|
|
||||||
tr("Failed to save certificate tool to: %1")
|
|
||||||
.arg(m_ProfileDir));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
file.write(m_DataDownloader.data());
|
|
||||||
file.close();
|
|
||||||
|
|
||||||
QStringList installArgs;
|
|
||||||
installArgs.append("-s");
|
|
||||||
installArgs.append("-y");
|
|
||||||
|
|
||||||
if (!runProgram(filename, installArgs, QStringList())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// openssl installer no longer needed
|
|
||||||
QFile::remove(filename);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
emit openSslBinaryReady();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginManager::generateCertificate()
|
|
||||||
{
|
|
||||||
connect(
|
|
||||||
this,
|
|
||||||
SIGNAL(openSslBinaryReady()),
|
|
||||||
this,
|
|
||||||
SLOT(doGenerateCertificate()));
|
|
||||||
|
|
||||||
downloadOpenSslSetup();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginManager::savePlugin()
|
|
||||||
{
|
{
|
||||||
// create the path if not exist
|
// create the path if not exist
|
||||||
QDir dir(m_PluginDir);
|
QDir dir(m_PluginDir);
|
||||||
|
@ -169,15 +133,19 @@ void PluginManager::savePlugin()
|
||||||
QFile file(filename);
|
QFile file(filename);
|
||||||
if (!file.open(QIODevice::WriteOnly)) {
|
if (!file.open(QIODevice::WriteOnly)) {
|
||||||
emit error(
|
emit error(
|
||||||
tr("Failed to download '%1' plugin to: %2")
|
tr("Failed to download plugin '%1' to: %2\n%3")
|
||||||
.arg(m_PluginList.at(m_DownloadIndex))
|
.arg(m_PluginList.at(m_DownloadIndex))
|
||||||
.arg(m_PluginDir));
|
.arg(m_PluginDir)
|
||||||
|
.arg(file.errorString()));
|
||||||
|
|
||||||
return;
|
file.close();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.write(m_DataDownloader.data());
|
file.write(m_DataDownloader.data());
|
||||||
file.close();
|
file.close();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PluginManager::getPluginUrl(const QString& pluginName)
|
QString PluginManager::getPluginUrl(const QString& pluginName)
|
||||||
|
@ -236,19 +204,6 @@ QString PluginManager::getPluginUrl(const QString& pluginName)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PluginManager::getOpenSslSetupUrl()
|
|
||||||
{
|
|
||||||
QString result;
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
result = kBaseUrl;
|
|
||||||
result.append("/tools/");
|
|
||||||
result.append(kWinOpenSslSetup);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString PluginManager::getPluginOsSpecificName(const QString& pluginName)
|
QString PluginManager::getPluginOsSpecificName(const QString& pluginName)
|
||||||
{
|
{
|
||||||
QString result = pluginName;
|
QString result = pluginName;
|
||||||
|
@ -261,127 +216,3 @@ QString PluginManager::getPluginOsSpecificName(const QString& pluginName)
|
||||||
#endif
|
#endif
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PluginManager::checkOpenSslBinary()
|
|
||||||
{
|
|
||||||
// assume OpenSsl is unavailable on Windows,
|
|
||||||
// but always available on both Mac and Linux
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
return false;
|
|
||||||
#else
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginManager::downloadOpenSslSetup()
|
|
||||||
{
|
|
||||||
if (checkOpenSslBinary()) {
|
|
||||||
emit openSslBinaryReady();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString urlString = getOpenSslSetupUrl();
|
|
||||||
|
|
||||||
QUrl url;
|
|
||||||
url.setUrl(urlString);
|
|
||||||
|
|
||||||
disconnect(
|
|
||||||
&m_DataDownloader,
|
|
||||||
SIGNAL(isComplete()),
|
|
||||||
this,
|
|
||||||
SLOT(downloadPlugins()));
|
|
||||||
|
|
||||||
connect(
|
|
||||||
&m_DataDownloader,
|
|
||||||
SIGNAL(isComplete()),
|
|
||||||
this,
|
|
||||||
SLOT(saveOpenSslSetup()));
|
|
||||||
|
|
||||||
m_DataDownloader.download(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginManager::doGenerateCertificate()
|
|
||||||
{
|
|
||||||
QString openSslProgramFile;
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
openSslProgramFile = m_ProfileDir;
|
|
||||||
openSslProgramFile.append("\\").append(kWinOpenSslBinary);
|
|
||||||
#else
|
|
||||||
openSslProgramFile = kUnixOpenSslCommand;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QStringList arguments;
|
|
||||||
|
|
||||||
// self signed certificate
|
|
||||||
arguments.append("req");
|
|
||||||
arguments.append("-x509");
|
|
||||||
arguments.append("-nodes");
|
|
||||||
|
|
||||||
// valide duration
|
|
||||||
arguments.append("-days");
|
|
||||||
arguments.append(kCertificateLifetime);
|
|
||||||
|
|
||||||
// subject information
|
|
||||||
arguments.append("-subj");
|
|
||||||
|
|
||||||
QString info(kCertificateSubjectInfo);
|
|
||||||
arguments.append(info);
|
|
||||||
|
|
||||||
// private key
|
|
||||||
arguments.append("-newkey");
|
|
||||||
arguments.append("rsa:1024");
|
|
||||||
|
|
||||||
// key output filename
|
|
||||||
arguments.append("-keyout");
|
|
||||||
QString filename = m_ProfileDir;
|
|
||||||
filename.append(QDir::separator()).append(kCertificateFilename);
|
|
||||||
arguments.append(filename);
|
|
||||||
|
|
||||||
// certificate output filename
|
|
||||||
arguments.append("-out");
|
|
||||||
arguments.append(filename);
|
|
||||||
|
|
||||||
QStringList environment;
|
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
|
||||||
environment << QString("OPENSSL_CONF=%1\\OpenSSL\\synergy.conf")
|
|
||||||
.arg(m_ProfileDir);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!runProgram(openSslProgramFile, arguments, environment)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit generateCertificateFinished();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PluginManager::runProgram(
|
|
||||||
const QString& program, const QStringList& args, const QStringList& env)
|
|
||||||
{
|
|
||||||
QProcess process;
|
|
||||||
process.setEnvironment(env);
|
|
||||||
process.start(program, args);
|
|
||||||
|
|
||||||
bool success = process.waitForStarted();
|
|
||||||
|
|
||||||
QString standardOutput, standardError;
|
|
||||||
if (success && process.waitForFinished())
|
|
||||||
{
|
|
||||||
standardOutput = process.readAllStandardOutput().trimmed();
|
|
||||||
standardError = process.readAllStandardError().trimmed();
|
|
||||||
}
|
|
||||||
|
|
||||||
int code = process.exitCode();
|
|
||||||
if (!success || code != 0)
|
|
||||||
{
|
|
||||||
emit error(
|
|
||||||
QString("Program failed: %1\n\nCode: %2\nError: %3")
|
|
||||||
.arg(program)
|
|
||||||
.arg(process.exitCode())
|
|
||||||
.arg(standardError.isEmpty() ? "Unknown" : standardError));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "SslCertificate.h"
|
||||||
#include "CoreInterface.h"
|
#include "CoreInterface.h"
|
||||||
#include "DataDownloader.h"
|
#include "DataDownloader.h"
|
||||||
|
|
||||||
|
@ -35,30 +36,26 @@ public:
|
||||||
|
|
||||||
int downloadIndex() { return m_DownloadIndex; }
|
int downloadIndex() { return m_DownloadIndex; }
|
||||||
|
|
||||||
|
static bool exist(QString name);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void downloadPlugins();
|
void downloadPlugins();
|
||||||
void saveOpenSslSetup();
|
|
||||||
void generateCertificate();
|
|
||||||
void doGenerateCertificate();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void savePlugin();
|
bool savePlugin();
|
||||||
QString getPluginUrl(const QString& pluginName);
|
QString getPluginUrl(const QString& pluginName);
|
||||||
QString getOpenSslSetupUrl();
|
|
||||||
QString getPluginOsSpecificName(const QString& pluginName);
|
|
||||||
bool checkOpenSslBinary();
|
|
||||||
void downloadOpenSslSetup();
|
|
||||||
bool runProgram(
|
bool runProgram(
|
||||||
const QString& program,
|
const QString& program,
|
||||||
const QStringList& args,
|
const QStringList& args,
|
||||||
const QStringList& env);
|
const QStringList& env);
|
||||||
|
|
||||||
|
static QString getPluginOsSpecificName(const QString& pluginName);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void error(QString e);
|
void error(QString e);
|
||||||
|
void info(QString i);
|
||||||
void downloadNext();
|
void downloadNext();
|
||||||
void downloadFinished();
|
void downloadFinished();
|
||||||
void openSslBinaryReady();
|
|
||||||
void generateCertificateFinished();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QStringList m_PluginList;
|
QStringList m_PluginList;
|
||||||
|
@ -67,6 +64,7 @@ private:
|
||||||
int m_DownloadIndex;
|
int m_DownloadIndex;
|
||||||
DataDownloader m_DataDownloader;
|
DataDownloader m_DataDownloader;
|
||||||
CoreInterface m_CoreInterface;
|
CoreInterface m_CoreInterface;
|
||||||
|
SslCertificate m_SslCertificate;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PLUGINMANAGER_H
|
#endif // PLUGINMANAGER_H
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "PluginWizardPage.h"
|
#include "PluginWizardPage.h"
|
||||||
#include "ui_PluginWizardPageBase.h"
|
#include "ui_PluginWizardPageBase.h"
|
||||||
|
|
||||||
|
#include "SslCertificate.h"
|
||||||
#include "WebClient.h"
|
#include "WebClient.h"
|
||||||
#include "PluginManager.h"
|
#include "PluginManager.h"
|
||||||
|
|
||||||
|
@ -29,6 +30,7 @@ PluginWizardPage::PluginWizardPage(AppConfig& appConfig, QWidget *parent) :
|
||||||
m_Finished(false),
|
m_Finished(false),
|
||||||
m_pWebClient(NULL),
|
m_pWebClient(NULL),
|
||||||
m_pPluginManager(NULL),
|
m_pPluginManager(NULL),
|
||||||
|
m_pSslCertificate(NULL),
|
||||||
m_AppConfig(appConfig)
|
m_AppConfig(appConfig)
|
||||||
{
|
{
|
||||||
setupUi(this);
|
setupUi(this);
|
||||||
|
@ -36,6 +38,8 @@ PluginWizardPage::PluginWizardPage(AppConfig& appConfig, QWidget *parent) :
|
||||||
QMovie *movie = new QMovie(":/res/image/spinning-wheel.gif");
|
QMovie *movie = new QMovie(":/res/image/spinning-wheel.gif");
|
||||||
m_pLabelSpinning->setMovie(movie);
|
m_pLabelSpinning->setMovie(movie);
|
||||||
movie->start();
|
movie->start();
|
||||||
|
|
||||||
|
m_pSslCertificate = new SslCertificate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
PluginWizardPage::~PluginWizardPage()
|
PluginWizardPage::~PluginWizardPage()
|
||||||
|
@ -47,6 +51,8 @@ PluginWizardPage::~PluginWizardPage()
|
||||||
if (m_pPluginManager != NULL) {
|
if (m_pPluginManager != NULL) {
|
||||||
delete m_pPluginManager;
|
delete m_pPluginManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete m_pSslCertificate;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginWizardPage::changeEvent(QEvent *e)
|
void PluginWizardPage::changeEvent(QEvent *e)
|
||||||
|
@ -101,20 +107,20 @@ void PluginWizardPage::finished()
|
||||||
|
|
||||||
void PluginWizardPage::generateCertificate()
|
void PluginWizardPage::generateCertificate()
|
||||||
{
|
{
|
||||||
connect(m_pPluginManager,
|
connect(m_pSslCertificate,
|
||||||
SIGNAL(generateCertificateFinished()),
|
SIGNAL(generateFinished()),
|
||||||
this,
|
this,
|
||||||
SLOT(finished()));
|
SLOT(finished()));
|
||||||
|
|
||||||
connect(m_pPluginManager,
|
connect(m_pSslCertificate,
|
||||||
SIGNAL(generateCertificateFinished()),
|
SIGNAL(generateFinished()),
|
||||||
m_pPluginManagerThread,
|
m_pThread,
|
||||||
SLOT(quit()));
|
SLOT(quit()));
|
||||||
|
|
||||||
updateStatus(tr("Generating SSL certificate..."));
|
updateStatus(tr("Generating SSL certificate..."));
|
||||||
|
|
||||||
QMetaObject::invokeMethod(
|
QMetaObject::invokeMethod(
|
||||||
m_pPluginManager,
|
m_pSslCertificate,
|
||||||
"generateCertificate",
|
"generateCertificate",
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
}
|
}
|
||||||
|
@ -128,13 +134,18 @@ void PluginWizardPage::downloadPlugins()
|
||||||
{
|
{
|
||||||
QStringList pluginList = m_pWebClient->getPluginList();
|
QStringList pluginList = m_pWebClient->getPluginList();
|
||||||
m_pPluginManager = new PluginManager(pluginList);
|
m_pPluginManager = new PluginManager(pluginList);
|
||||||
m_pPluginManagerThread = new QThread;
|
m_pThread = new QThread;
|
||||||
|
|
||||||
connect(m_pPluginManager,
|
connect(m_pPluginManager,
|
||||||
SIGNAL(error(QString)),
|
SIGNAL(error(QString)),
|
||||||
this,
|
this,
|
||||||
SLOT(showError(QString)));
|
SLOT(showError(QString)));
|
||||||
|
|
||||||
|
connect(m_pPluginManager,
|
||||||
|
SIGNAL(info(QString)),
|
||||||
|
this,
|
||||||
|
SLOT(updateStatus(QString)));
|
||||||
|
|
||||||
connect(m_pPluginManager,
|
connect(m_pPluginManager,
|
||||||
SIGNAL(downloadNext()),
|
SIGNAL(downloadNext()),
|
||||||
this,
|
this,
|
||||||
|
@ -147,12 +158,12 @@ void PluginWizardPage::downloadPlugins()
|
||||||
|
|
||||||
connect(m_pPluginManager,
|
connect(m_pPluginManager,
|
||||||
SIGNAL(error(QString)),
|
SIGNAL(error(QString)),
|
||||||
m_pPluginManagerThread,
|
m_pThread,
|
||||||
SLOT(quit()));
|
SLOT(quit()));
|
||||||
|
|
||||||
connect(m_pPluginManagerThread,
|
connect(m_pThread,
|
||||||
SIGNAL(finished()),
|
SIGNAL(finished()),
|
||||||
m_pPluginManagerThread,
|
m_pThread,
|
||||||
SLOT(deleteLater()));
|
SLOT(deleteLater()));
|
||||||
|
|
||||||
updateStatus(
|
updateStatus(
|
||||||
|
@ -160,8 +171,8 @@ void PluginWizardPage::downloadPlugins()
|
||||||
.arg(pluginList.at(0))
|
.arg(pluginList.at(0))
|
||||||
.arg(pluginList.size()));
|
.arg(pluginList.size()));
|
||||||
|
|
||||||
m_pPluginManager->moveToThread(m_pPluginManagerThread);
|
m_pPluginManager->moveToThread(m_pThread);
|
||||||
m_pPluginManagerThread->start();
|
m_pThread->start();
|
||||||
|
|
||||||
QMetaObject::invokeMethod(
|
QMetaObject::invokeMethod(
|
||||||
m_pPluginManager,
|
m_pPluginManager,
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
|
|
||||||
class WebClient;
|
class WebClient;
|
||||||
class PluginManager;
|
class PluginManager;
|
||||||
|
class SslCertificate;
|
||||||
|
|
||||||
class PluginWizardPage : public QWizardPage, public Ui::PluginWizardPage {
|
class PluginWizardPage : public QWizardPage, public Ui::PluginWizardPage {
|
||||||
|
|
||||||
|
@ -46,13 +47,13 @@ protected:
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
void showError(QString error);
|
void showError(QString error);
|
||||||
|
void updateStatus(QString info);
|
||||||
void queryPluginDone();
|
void queryPluginDone();
|
||||||
void updateDownloadStatus();
|
void updateDownloadStatus();
|
||||||
void finished();
|
void finished();
|
||||||
void generateCertificate();
|
void generateCertificate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void updateStatus(QString info);
|
|
||||||
void downloadPlugins();
|
void downloadPlugins();
|
||||||
void showFinished();
|
void showFinished();
|
||||||
|
|
||||||
|
@ -62,7 +63,8 @@ private:
|
||||||
QString m_Password;
|
QString m_Password;
|
||||||
WebClient* m_pWebClient;
|
WebClient* m_pWebClient;
|
||||||
PluginManager* m_pPluginManager;
|
PluginManager* m_pPluginManager;
|
||||||
QThread* m_pPluginManagerThread;
|
SslCertificate* m_pSslCertificate;
|
||||||
|
QThread* m_pThread;
|
||||||
AppConfig& m_AppConfig;
|
AppConfig& m_AppConfig;
|
||||||
};
|
};
|
||||||
#endif // PLUGINWIZARDPAGE_H
|
#endif // PLUGINWIZARDPAGE_H
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include "SettingsDialog.h"
|
#include "SettingsDialog.h"
|
||||||
|
|
||||||
|
#include "PluginManager.h"
|
||||||
#include "CoreInterface.h"
|
#include "CoreInterface.h"
|
||||||
#include "SynergyLocale.h"
|
#include "SynergyLocale.h"
|
||||||
#include "QSynergyApplication.h"
|
#include "QSynergyApplication.h"
|
||||||
|
@ -30,6 +31,8 @@
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|
||||||
|
static const char networkSecurity[] = "ns";
|
||||||
|
|
||||||
SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) :
|
SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) :
|
||||||
QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
|
QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
|
||||||
Ui::SettingsDialogBase(),
|
Ui::SettingsDialogBase(),
|
||||||
|
@ -57,10 +60,7 @@ SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) :
|
||||||
m_pCheckBoxElevateMode->hide();
|
m_pCheckBoxElevateMode->hide();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
QString pluginDir = m_CoreInterface.getPluginDir();
|
if (!PluginManager::exist(networkSecurity)) {
|
||||||
QDir dir(pluginDir);
|
|
||||||
int fileNum = dir.entryInfoList(QDir::NoDotAndDotDot|QDir::AllEntries).count();
|
|
||||||
if (fileNum == 0) {
|
|
||||||
m_pGroupNetworkSecurity->setEnabled(false);
|
m_pGroupNetworkSecurity->setEnabled(false);
|
||||||
m_pCheckBoxEnableCrypto->setChecked(false);
|
m_pCheckBoxEnableCrypto->setChecked(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,6 +169,7 @@ void SetupWizard::accept()
|
||||||
appConfig.setEdition(m_Edition);
|
appConfig.setEdition(m_Edition);
|
||||||
}
|
}
|
||||||
m_MainWindow.setEdition(m_Edition);
|
m_MainWindow.setEdition(m_Edition);
|
||||||
|
m_MainWindow.updateLocalFingerprint();
|
||||||
|
|
||||||
settings.sync();
|
settings.sync();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* 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 "SslCertificate.h"
|
||||||
|
|
||||||
|
#include "Fingerprint.h"
|
||||||
|
|
||||||
|
#include <QProcess>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
|
static const char kCertificateLifetime[] = "365";
|
||||||
|
static const char kCertificateSubjectInfo[] = "/CN=Synergy";
|
||||||
|
static const char kCertificateFilename[] = "Synergy.pem";
|
||||||
|
static const char kSslDir[] = "SSL";
|
||||||
|
static const char kUnixOpenSslCommand[] = "openssl";
|
||||||
|
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
static const char kWinOpenSslBinary[] = "OpenSSL\\openssl.exe";
|
||||||
|
static const char kConfigFile[] = "OpenSSL\\synergy.conf";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SslCertificate::SslCertificate(QObject *parent) :
|
||||||
|
QObject(parent)
|
||||||
|
{
|
||||||
|
m_ProfileDir = m_CoreInterface.getProfileDir();
|
||||||
|
if (m_ProfileDir.isEmpty()) {
|
||||||
|
emit error(tr("Failed to get profile directory."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SslCertificate::runTool(const QStringList& args)
|
||||||
|
{
|
||||||
|
QString program;
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
program = QCoreApplication::applicationDirPath();
|
||||||
|
program.append("\\").append(kWinOpenSslBinary);
|
||||||
|
#else
|
||||||
|
program = kUnixOpenSslCommand;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
QStringList environment;
|
||||||
|
#if defined(Q_OS_WIN)
|
||||||
|
environment << QString("OPENSSL_CONF=%1\\%2")
|
||||||
|
.arg(QCoreApplication::applicationDirPath())
|
||||||
|
.arg(kConfigFile);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QProcess process;
|
||||||
|
process.setEnvironment(environment);
|
||||||
|
process.start(program, args);
|
||||||
|
|
||||||
|
bool success = process.waitForStarted();
|
||||||
|
|
||||||
|
QString standardError;
|
||||||
|
if (success && process.waitForFinished())
|
||||||
|
{
|
||||||
|
m_ToolOutput = process.readAllStandardOutput().trimmed();
|
||||||
|
standardError = process.readAllStandardError().trimmed();
|
||||||
|
}
|
||||||
|
|
||||||
|
int code = process.exitCode();
|
||||||
|
if (!success || code != 0)
|
||||||
|
{
|
||||||
|
emit error(
|
||||||
|
QString("SSL tool failed: %1\n\nCode: %2\nError: %3")
|
||||||
|
.arg(program)
|
||||||
|
.arg(process.exitCode())
|
||||||
|
.arg(standardError.isEmpty() ? "Unknown" : standardError));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SslCertificate::generateCertificate()
|
||||||
|
{
|
||||||
|
QStringList arguments;
|
||||||
|
|
||||||
|
// self signed certificate
|
||||||
|
arguments.append("req");
|
||||||
|
arguments.append("-x509");
|
||||||
|
arguments.append("-nodes");
|
||||||
|
|
||||||
|
// valide duration
|
||||||
|
arguments.append("-days");
|
||||||
|
arguments.append(kCertificateLifetime);
|
||||||
|
|
||||||
|
// subject information
|
||||||
|
arguments.append("-subj");
|
||||||
|
|
||||||
|
QString subInfo(kCertificateSubjectInfo);
|
||||||
|
arguments.append(subInfo);
|
||||||
|
|
||||||
|
// private key
|
||||||
|
arguments.append("-newkey");
|
||||||
|
arguments.append("rsa:1024");
|
||||||
|
|
||||||
|
QString sslDirPath = QString("%1%2%3")
|
||||||
|
.arg(m_ProfileDir)
|
||||||
|
.arg(QDir::separator())
|
||||||
|
.arg(kSslDir);
|
||||||
|
|
||||||
|
QDir sslDir(sslDirPath);
|
||||||
|
if (!sslDir.exists()) {
|
||||||
|
sslDir.mkpath(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString filename = QString("%1%2%3")
|
||||||
|
.arg(sslDirPath)
|
||||||
|
.arg(QDir::separator())
|
||||||
|
.arg(kCertificateFilename);
|
||||||
|
|
||||||
|
// key output filename
|
||||||
|
arguments.append("-keyout");
|
||||||
|
arguments.append(filename);
|
||||||
|
|
||||||
|
// certificate output filename
|
||||||
|
arguments.append("-out");
|
||||||
|
arguments.append(filename);
|
||||||
|
|
||||||
|
if (!runTool(arguments)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit info(tr("SSL certificate generated."));
|
||||||
|
|
||||||
|
generateFingerprint(filename);
|
||||||
|
|
||||||
|
emit generateFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SslCertificate::generateFingerprint(const QString& certificateFilename)
|
||||||
|
{
|
||||||
|
QStringList arguments;
|
||||||
|
arguments.append("x509");
|
||||||
|
arguments.append("-fingerprint");
|
||||||
|
arguments.append("-sha1");
|
||||||
|
arguments.append("-noout");
|
||||||
|
arguments.append("-in");
|
||||||
|
arguments.append(certificateFilename);
|
||||||
|
|
||||||
|
if (!runTool(arguments)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the fingerprint from the tool output
|
||||||
|
int i = m_ToolOutput.indexOf("=");
|
||||||
|
if (i != -1) {
|
||||||
|
i++;
|
||||||
|
QString fingerprint = m_ToolOutput.mid(
|
||||||
|
i, m_ToolOutput.size() - i);
|
||||||
|
|
||||||
|
Fingerprint::local().trust(fingerprint, false);
|
||||||
|
emit info(tr("SSL fingerprint generated."));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
emit error(tr("Failed to find SSL fingerprint."));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* synergy -- mouse and keyboard sharing utility
|
* synergy -- mouse and keyboard sharing utility
|
||||||
* Copyright (C) 2012 Synergy Si Ltd.
|
* Copyright (C) 2015 Synergy Si Ltd.
|
||||||
* Copyright (C) 2011 Nick Bolton
|
|
||||||
*
|
*
|
||||||
* This package is free software; you can redistribute it and/or
|
* This package is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU General Public License
|
* modify it under the terms of the GNU General Public License
|
||||||
|
@ -18,20 +17,31 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define TEST_ENV
|
#include "CoreInterface.h"
|
||||||
|
|
||||||
#include "client/Client.h"
|
#include <QObject>
|
||||||
|
|
||||||
#include "test/global/gmock.h"
|
class SslCertificate : public QObject
|
||||||
|
|
||||||
class IEventQueue;
|
|
||||||
|
|
||||||
class MockClient : public Client
|
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MockClient() : Client() { }
|
explicit SslCertificate(QObject *parent = 0);
|
||||||
MOCK_METHOD2(mouseMove, void(SInt32, SInt32));
|
|
||||||
MOCK_METHOD1(setOptions, void(const OptionsList&));
|
public slots:
|
||||||
MOCK_METHOD0(handshakeComplete, void());
|
void generateCertificate();
|
||||||
MOCK_METHOD1(setDecryptIv, void(const UInt8*));
|
|
||||||
|
signals:
|
||||||
|
void error(QString e);
|
||||||
|
void info(QString i);
|
||||||
|
void generateFinished();
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool runTool(const QStringList& args);
|
||||||
|
void generateFingerprint(const QString& certificateFilename);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_ProfileDir;
|
||||||
|
QString m_ToolOutput;
|
||||||
|
CoreInterface m_CoreInterface;
|
||||||
};
|
};
|
|
@ -95,6 +95,7 @@ REGISTER_EVENT(IListenSocket, connecting)
|
||||||
//
|
//
|
||||||
|
|
||||||
REGISTER_EVENT(ISocket, disconnected)
|
REGISTER_EVENT(ISocket, disconnected)
|
||||||
|
REGISTER_EVENT(ISocket, stopRetry)
|
||||||
|
|
||||||
//
|
//
|
||||||
// OSXScreen
|
// OSXScreen
|
||||||
|
|
|
@ -281,7 +281,8 @@ private:
|
||||||
class ISocketEvents : public EventTypes {
|
class ISocketEvents : public EventTypes {
|
||||||
public:
|
public:
|
||||||
ISocketEvents() :
|
ISocketEvents() :
|
||||||
m_disconnected(Event::kUnknown) { }
|
m_disconnected(Event::kUnknown),
|
||||||
|
m_stopRetry(Event::kUnknown) { }
|
||||||
|
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
@ -294,10 +295,18 @@ public:
|
||||||
*/
|
*/
|
||||||
Event::Type disconnected();
|
Event::Type disconnected();
|
||||||
|
|
||||||
|
//! Get stop retry event type
|
||||||
|
/*!
|
||||||
|
Returns the stop retry event type. This is sent when the client
|
||||||
|
doesn't want to reconnect after it disconnects from the server.
|
||||||
|
*/
|
||||||
|
Event::Type stopRetry();
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Event::Type m_disconnected;
|
Event::Type m_disconnected;
|
||||||
|
Event::Type m_stopRetry;
|
||||||
};
|
};
|
||||||
|
|
||||||
class OSXScreenEvents : public EventTypes {
|
class OSXScreenEvents : public EventTypes {
|
||||||
|
|
|
@ -27,6 +27,9 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace synergy {
|
namespace synergy {
|
||||||
namespace string {
|
namespace string {
|
||||||
|
@ -180,6 +183,30 @@ removeFileExt(String filename)
|
||||||
return filename.substr(0, dot);
|
return filename.substr(0, dot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
toHex(String& subject, int width, const char fill)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << std::hex;
|
||||||
|
for (unsigned int i = 0; i < subject.length(); i++) {
|
||||||
|
ss << std::setw(width) << std::setfill(fill) << (int)(unsigned char)subject[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
subject = ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
uppercase(String& subject)
|
||||||
|
{
|
||||||
|
std::transform(subject.begin(), subject.end(), subject.begin(), ::toupper);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
removeChar(String& subject, const char c)
|
||||||
|
{
|
||||||
|
subject.erase(std::remove(subject.begin(), subject.end(), c), subject.end());
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// CaselessCmp
|
// CaselessCmp
|
||||||
//
|
//
|
||||||
|
|
|
@ -70,6 +70,25 @@ Finds the last dot and remove all characters from the dot to the end
|
||||||
*/
|
*/
|
||||||
String removeFileExt(String filename);
|
String removeFileExt(String filename);
|
||||||
|
|
||||||
|
//! Convert into hexdecimal
|
||||||
|
/*!
|
||||||
|
Convert each character in \c subject into hexdecimal form with \c width
|
||||||
|
*/
|
||||||
|
void toHex(String& subject, int width, const char fill = '0');
|
||||||
|
|
||||||
|
//! Convert to all uppercase
|
||||||
|
/*!
|
||||||
|
Convert each character in \c subject to uppercase
|
||||||
|
*/
|
||||||
|
void uppercase(String& subject);
|
||||||
|
|
||||||
|
//! Remove all specific char in suject
|
||||||
|
/*!
|
||||||
|
Remove all specific \c char in \c suject
|
||||||
|
*/
|
||||||
|
void removeChar(String& subject, const char c);
|
||||||
|
|
||||||
|
|
||||||
//! Case-insensitive comparisons
|
//! Case-insensitive comparisons
|
||||||
/*!
|
/*!
|
||||||
This class provides case-insensitve comparison functions.
|
This class provides case-insensitve comparison functions.
|
||||||
|
|
|
@ -60,8 +60,7 @@ Client::Client(
|
||||||
const String& name, const NetworkAddress& address,
|
const String& name, const NetworkAddress& address,
|
||||||
ISocketFactory* socketFactory,
|
ISocketFactory* socketFactory,
|
||||||
synergy::Screen* screen,
|
synergy::Screen* screen,
|
||||||
bool enableDragDrop,
|
ClientArgs& args) :
|
||||||
bool enableCrypto) :
|
|
||||||
m_mock(false),
|
m_mock(false),
|
||||||
m_name(name),
|
m_name(name),
|
||||||
m_serverAddress(address),
|
m_serverAddress(address),
|
||||||
|
@ -77,9 +76,9 @@ Client::Client(
|
||||||
m_events(events),
|
m_events(events),
|
||||||
m_sendFileThread(NULL),
|
m_sendFileThread(NULL),
|
||||||
m_writeToDropDirThread(NULL),
|
m_writeToDropDirThread(NULL),
|
||||||
m_enableDragDrop(enableDragDrop),
|
|
||||||
m_socket(NULL),
|
m_socket(NULL),
|
||||||
m_useSecureNetwork(false)
|
m_useSecureNetwork(false),
|
||||||
|
m_args(args)
|
||||||
{
|
{
|
||||||
assert(m_socketFactory != NULL);
|
assert(m_socketFactory != NULL);
|
||||||
assert(m_screen != NULL);
|
assert(m_screen != NULL);
|
||||||
|
@ -94,7 +93,7 @@ Client::Client(
|
||||||
new TMethodEventJob<Client>(this,
|
new TMethodEventJob<Client>(this,
|
||||||
&Client::handleResume));
|
&Client::handleResume));
|
||||||
|
|
||||||
if (m_enableDragDrop) {
|
if (m_args.m_enableDragDrop) {
|
||||||
m_events->adoptHandler(m_events->forIScreen().fileChunkSending(),
|
m_events->adoptHandler(m_events->forIScreen().fileChunkSending(),
|
||||||
this,
|
this,
|
||||||
new TMethodEventJob<Client>(this,
|
new TMethodEventJob<Client>(this,
|
||||||
|
@ -105,7 +104,7 @@ Client::Client(
|
||||||
&Client::handleFileRecieveCompleted));
|
&Client::handleFileRecieveCompleted));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enableCrypto) {
|
if (m_args.m_enableCrypto) {
|
||||||
m_useSecureNetwork = ARCH->plugin().exists(s_networkSecurity);
|
m_useSecureNetwork = ARCH->plugin().exists(s_networkSecurity);
|
||||||
if (m_useSecureNetwork == false) {
|
if (m_useSecureNetwork == false) {
|
||||||
LOG((CLOG_NOTE "crypto disabled because of ns plugin not available"));
|
LOG((CLOG_NOTE "crypto disabled because of ns plugin not available"));
|
||||||
|
@ -471,6 +470,10 @@ Client::setupConnection()
|
||||||
m_stream->getEventTarget(),
|
m_stream->getEventTarget(),
|
||||||
new TMethodEventJob<Client>(this,
|
new TMethodEventJob<Client>(this,
|
||||||
&Client::handleDisconnected));
|
&Client::handleDisconnected));
|
||||||
|
|
||||||
|
m_events->adoptHandler(m_events->forISocket().stopRetry(),
|
||||||
|
m_stream->getEventTarget(),
|
||||||
|
new TMethodEventJob<Client>(this, &Client::handleStopRetry));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -526,6 +529,8 @@ Client::cleanupConnection()
|
||||||
m_stream->getEventTarget());
|
m_stream->getEventTarget());
|
||||||
m_events->removeHandler(m_events->forISocket().disconnected(),
|
m_events->removeHandler(m_events->forISocket().disconnected(),
|
||||||
m_stream->getEventTarget());
|
m_stream->getEventTarget());
|
||||||
|
m_events->removeHandler(m_events->forISocket().stopRetry(),
|
||||||
|
m_stream->getEventTarget());
|
||||||
cleanupStream();
|
cleanupStream();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -744,6 +749,11 @@ Client::onFileRecieveCompleted()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Client::handleStopRetry(const Event&, void*)
|
||||||
|
{
|
||||||
|
m_args.m_restartable = false;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Client::writeToDropDirThread(void*)
|
Client::writeToDropDirThread(void*)
|
||||||
|
@ -780,7 +790,8 @@ Client::fileChunkReceived(String data)
|
||||||
void
|
void
|
||||||
Client::dragInfoReceived(UInt32 fileNum, String data)
|
Client::dragInfoReceived(UInt32 fileNum, String data)
|
||||||
{
|
{
|
||||||
if (!m_enableDragDrop) {
|
// TODO: fix duplicate function from CServer
|
||||||
|
if (!m_args.m_enableDragDrop) {
|
||||||
LOG((CLOG_DEBUG "drag drop not enabled, ignoring drag info."));
|
LOG((CLOG_DEBUG "drag drop not enabled, ignoring drag info."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "synergy/IClipboard.h"
|
#include "synergy/IClipboard.h"
|
||||||
#include "synergy/DragInformation.h"
|
#include "synergy/DragInformation.h"
|
||||||
#include "synergy/INode.h"
|
#include "synergy/INode.h"
|
||||||
|
#include "synergy/ClientArgs.h"
|
||||||
#include "net/NetworkAddress.h"
|
#include "net/NetworkAddress.h"
|
||||||
#include "base/EventTypes.h"
|
#include "base/EventTypes.h"
|
||||||
|
|
||||||
|
@ -59,14 +60,9 @@ public:
|
||||||
const String& name, const NetworkAddress& address,
|
const String& name, const NetworkAddress& address,
|
||||||
ISocketFactory* socketFactory,
|
ISocketFactory* socketFactory,
|
||||||
synergy::Screen* screen,
|
synergy::Screen* screen,
|
||||||
bool enableDragDrop,
|
ClientArgs& args);
|
||||||
bool enableCrypto);
|
|
||||||
~Client();
|
~Client();
|
||||||
|
|
||||||
#ifdef TEST_ENV
|
|
||||||
Client() : m_mock(true) { }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//! @name manipulators
|
//! @name manipulators
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
|
@ -196,6 +192,7 @@ private:
|
||||||
void handleResume(const Event& event, void*);
|
void handleResume(const Event& event, void*);
|
||||||
void handleFileChunkSending(const Event&, void*);
|
void handleFileChunkSending(const Event&, void*);
|
||||||
void handleFileRecieveCompleted(const Event&, void*);
|
void handleFileRecieveCompleted(const Event&, void*);
|
||||||
|
void handleStopRetry(const Event&, void*);
|
||||||
void onFileRecieveCompleted();
|
void onFileRecieveCompleted();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -224,7 +221,7 @@ private:
|
||||||
String m_dragFileExt;
|
String m_dragFileExt;
|
||||||
Thread* m_sendFileThread;
|
Thread* m_sendFileThread;
|
||||||
Thread* m_writeToDropDirThread;
|
Thread* m_writeToDropDirThread;
|
||||||
bool m_enableDragDrop;
|
|
||||||
TCPSocket* m_socket;
|
TCPSocket* m_socket;
|
||||||
bool m_useSecureNetwork;
|
bool m_useSecureNetwork;
|
||||||
|
ClientArgs& m_args;
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
#include "mt/Thread.h"
|
#include "mt/Thread.h"
|
||||||
|
|
||||||
#include "net/XSocket.h"
|
|
||||||
#include "mt/XMT.h"
|
#include "mt/XMT.h"
|
||||||
#include "mt/XThread.h"
|
#include "mt/XThread.h"
|
||||||
#include "arch/Arch.h"
|
#include "arch/Arch.h"
|
||||||
|
@ -158,11 +157,6 @@ Thread::threadFunc(void* vjob)
|
||||||
job->run();
|
job->run();
|
||||||
LOG((CLOG_DEBUG1 "thread 0x%08x exit", id));
|
LOG((CLOG_DEBUG1 "thread 0x%08x exit", id));
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (XSocket& e) {
|
|
||||||
// client called cancel()
|
|
||||||
LOG((CLOG_DEBUG "%s", e.what()));
|
|
||||||
}
|
|
||||||
catch (XThreadCancel&) {
|
catch (XThreadCancel&) {
|
||||||
// client called cancel()
|
// client called cancel()
|
||||||
LOG((CLOG_DEBUG1 "caught cancel on thread 0x%08x", id));
|
LOG((CLOG_DEBUG1 "caught cancel on thread 0x%08x", id));
|
||||||
|
|
|
@ -112,27 +112,35 @@ TCPListenSocket::accept()
|
||||||
try {
|
try {
|
||||||
socket = new TCPSocket(m_events, m_socketMultiplexer, ARCH->acceptSocket(m_socket, NULL));
|
socket = new TCPSocket(m_events, m_socketMultiplexer, ARCH->acceptSocket(m_socket, NULL));
|
||||||
if (socket != NULL) {
|
if (socket != NULL) {
|
||||||
m_socketMultiplexer->addSocket(this,
|
setListeningJob();
|
||||||
new TSocketMultiplexerMethodJob<TCPListenSocket>(
|
|
||||||
this, &TCPListenSocket::serviceListening,
|
|
||||||
m_socket, true, false));
|
|
||||||
}
|
}
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
catch (XArchNetwork&) {
|
catch (XArchNetwork&) {
|
||||||
if (socket != NULL) {
|
if (socket != NULL) {
|
||||||
delete socket;
|
delete socket;
|
||||||
|
setListeningJob();
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
catch (std::exception &ex) {
|
catch (std::exception &ex) {
|
||||||
if (socket != NULL) {
|
if (socket != NULL) {
|
||||||
delete socket;
|
delete socket;
|
||||||
|
setListeningJob();
|
||||||
}
|
}
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TCPListenSocket::setListeningJob()
|
||||||
|
{
|
||||||
|
m_socketMultiplexer->addSocket(this,
|
||||||
|
new TSocketMultiplexerMethodJob<TCPListenSocket>(
|
||||||
|
this, &TCPListenSocket::serviceListening,
|
||||||
|
m_socket, true, false));
|
||||||
|
}
|
||||||
|
|
||||||
ISocketMultiplexerJob*
|
ISocketMultiplexerJob*
|
||||||
TCPListenSocket::serviceListening(ISocketMultiplexerJob* job,
|
TCPListenSocket::serviceListening(ISocketMultiplexerJob* job,
|
||||||
bool read, bool, bool error)
|
bool read, bool, bool error)
|
||||||
|
|
|
@ -45,6 +45,9 @@ public:
|
||||||
accept();
|
accept();
|
||||||
virtual void deleteSocket(void*) { }
|
virtual void deleteSocket(void*) { }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void setListeningJob();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ISocketMultiplexerJob*
|
ISocketMultiplexerJob*
|
||||||
serviceListening(ISocketMultiplexerJob*,
|
serviceListening(ISocketMultiplexerJob*,
|
||||||
|
|
|
@ -461,15 +461,26 @@ TCPSocket::serviceConnected(ISocketMultiplexerJob* job,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool needNewJob = false;
|
bool needNewJob = false;
|
||||||
|
static UInt32 s_retryOutputBufferSize = 0;
|
||||||
|
|
||||||
if (write) {
|
if (write) {
|
||||||
try {
|
try {
|
||||||
// write data
|
// write data
|
||||||
UInt32 n = m_outputBuffer.getSize();
|
UInt32 n = m_outputBuffer.getSize();
|
||||||
|
|
||||||
|
if (s_retryOutputBufferSize > 0) {
|
||||||
|
n = s_retryOutputBufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
const void* buffer = m_outputBuffer.peek(n);
|
const void* buffer = m_outputBuffer.peek(n);
|
||||||
if (isSecure()) {
|
if (isSecure()) {
|
||||||
if (isSecureReady()) {
|
if (isSecureReady()) {
|
||||||
|
s_retryOutputBufferSize = n;
|
||||||
n = secureWrite(buffer, n);
|
n = secureWrite(buffer, n);
|
||||||
|
|
||||||
|
if (n > 0) {
|
||||||
|
s_retryOutputBufferSize = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return job;
|
return job;
|
||||||
|
@ -519,7 +530,8 @@ TCPSocket::serviceConnected(ISocketMultiplexerJob* job,
|
||||||
|
|
||||||
if (read && m_readable) {
|
if (read && m_readable) {
|
||||||
try {
|
try {
|
||||||
UInt8 buffer[4096];
|
static UInt8 buffer[4096];
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
|
|
||||||
if (isSecure()) {
|
if (isSecure()) {
|
||||||
|
|
|
@ -59,6 +59,7 @@ public:
|
||||||
|
|
||||||
virtual void secureConnect() {}
|
virtual void secureConnect() {}
|
||||||
virtual void secureAccept() {}
|
virtual void secureAccept() {}
|
||||||
|
virtual void setFingerprintFilename(String& f) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ArchSocket getSocket() { return m_socket; }
|
ArchSocket getSocket() { return m_socket; }
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "net/TSocketMultiplexerMethodJob.h"
|
#include "net/TSocketMultiplexerMethodJob.h"
|
||||||
#include "arch/XArch.h"
|
#include "arch/XArch.h"
|
||||||
|
|
||||||
|
static const char s_certificateDir[] = { "SSL" };
|
||||||
static const char s_certificateFilename[] = { "Synergy.pem" };
|
static const char s_certificateFilename[] = { "Synergy.pem" };
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -54,39 +55,41 @@ SecureListenSocket::accept()
|
||||||
m_events,
|
m_events,
|
||||||
m_socketMultiplexer,
|
m_socketMultiplexer,
|
||||||
ARCH->acceptSocket(m_socket, NULL));
|
ARCH->acceptSocket(m_socket, NULL));
|
||||||
|
socket->initSsl(true);
|
||||||
|
|
||||||
|
if (socket != NULL) {
|
||||||
|
setListeningJob();
|
||||||
|
}
|
||||||
|
|
||||||
|
String certificateFilename = synergy::string::sprintf(
|
||||||
|
"%s/%s/%s",
|
||||||
|
ARCH->getProfileDirectory().c_str(),
|
||||||
|
s_certificateDir,
|
||||||
|
s_certificateFilename);
|
||||||
|
|
||||||
|
bool loaded = socket->loadCertificates(certificateFilename);
|
||||||
|
if (!loaded) {
|
||||||
|
delete socket;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
socket->secureAccept();
|
||||||
|
|
||||||
m_secureSocketSet.insert(socket);
|
m_secureSocketSet.insert(socket);
|
||||||
|
|
||||||
socket->initSsl(true);
|
|
||||||
// TODO: customized certificate path
|
|
||||||
String certificateFilename = ARCH->getProfileDirectory();
|
|
||||||
#if SYSAPI_WIN32
|
|
||||||
certificateFilename.append("\\");
|
|
||||||
#elif SYSAPI_UNIX
|
|
||||||
certificateFilename.append("/");
|
|
||||||
#endif
|
|
||||||
certificateFilename.append(s_certificateFilename);
|
|
||||||
|
|
||||||
socket->loadCertificates(certificateFilename.c_str());
|
|
||||||
socket->secureAccept();
|
|
||||||
|
|
||||||
if (socket != NULL) {
|
|
||||||
m_socketMultiplexer->addSocket(this,
|
|
||||||
new TSocketMultiplexerMethodJob<TCPListenSocket>(
|
|
||||||
this, &TCPListenSocket::serviceListening,
|
|
||||||
m_socket, true, false));
|
|
||||||
}
|
|
||||||
return dynamic_cast<IDataSocket*>(socket);
|
return dynamic_cast<IDataSocket*>(socket);
|
||||||
}
|
}
|
||||||
catch (XArchNetwork&) {
|
catch (XArchNetwork&) {
|
||||||
if (socket != NULL) {
|
if (socket != NULL) {
|
||||||
delete socket;
|
delete socket;
|
||||||
|
setListeningJob();
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
catch (std::exception &ex) {
|
catch (std::exception &ex) {
|
||||||
if (socket != NULL) {
|
if (socket != NULL) {
|
||||||
delete socket;
|
delete socket;
|
||||||
|
setListeningJob();
|
||||||
}
|
}
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
//
|
//
|
||||||
// SecureSocket
|
// SecureSocket
|
||||||
|
@ -35,6 +36,11 @@
|
||||||
|
|
||||||
#define MAX_ERROR_SIZE 65535
|
#define MAX_ERROR_SIZE 65535
|
||||||
|
|
||||||
|
static const char kFingerprintDirName[] = "SSL/Fingerprints";
|
||||||
|
//static const char kFingerprintLocalFilename[] = "Local.txt";
|
||||||
|
static const char kFingerprintTrustedServersFilename[] = "TrustedServers.txt";
|
||||||
|
//static const char kFingerprintTrustedClientsFilename[] = "TrustedClients.txt";
|
||||||
|
|
||||||
struct Ssl {
|
struct Ssl {
|
||||||
SSL_CTX* m_context;
|
SSL_CTX* m_context;
|
||||||
SSL* m_ssl;
|
SSL* m_ssl;
|
||||||
|
@ -149,24 +155,46 @@ SecureSocket::initSsl(bool server)
|
||||||
initContext(server);
|
initContext(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
SecureSocket::loadCertificates(const char* filename)
|
SecureSocket::loadCertificates(String& filename)
|
||||||
{
|
{
|
||||||
int r = 0;
|
if (filename.empty()) {
|
||||||
r = SSL_CTX_use_certificate_file(m_ssl->m_context, filename, SSL_FILETYPE_PEM);
|
showError("ssl certificate is not specified");
|
||||||
if (r <= 0) {
|
return false;
|
||||||
throwError("could not use ssl certificate");
|
}
|
||||||
|
else {
|
||||||
|
std::ifstream file(filename.c_str());
|
||||||
|
bool exist = file.good();
|
||||||
|
file.close();
|
||||||
|
|
||||||
|
if (!exist) {
|
||||||
|
String errorMsg("ssl certificate doesn't exist: ");
|
||||||
|
errorMsg.append(filename);
|
||||||
|
showError(errorMsg.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = SSL_CTX_use_PrivateKey_file(m_ssl->m_context, filename, SSL_FILETYPE_PEM);
|
int r = 0;
|
||||||
|
r = SSL_CTX_use_certificate_file(m_ssl->m_context, filename.c_str(), SSL_FILETYPE_PEM);
|
||||||
if (r <= 0) {
|
if (r <= 0) {
|
||||||
throwError("could not use ssl private key");
|
showError("could not use ssl certificate");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = SSL_CTX_use_PrivateKey_file(m_ssl->m_context, filename.c_str(), SSL_FILETYPE_PEM);
|
||||||
|
if (r <= 0) {
|
||||||
|
showError("could not use ssl private key");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = SSL_CTX_check_private_key(m_ssl->m_context);
|
r = SSL_CTX_check_private_key(m_ssl->m_context);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
throwError("could not verify ssl private key");
|
showError("could not verify ssl private key");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -253,23 +281,30 @@ SecureSocket::secureConnect(int socket)
|
||||||
checkResult(r, fatal, retry);
|
checkResult(r, fatal, retry);
|
||||||
|
|
||||||
if (fatal) {
|
if (fatal) {
|
||||||
// tell user and sleep so the socket isn't hammered.
|
|
||||||
LOG((CLOG_ERR "failed to connect secure socket"));
|
LOG((CLOG_ERR "failed to connect secure socket"));
|
||||||
LOG((CLOG_INFO "server connection may not be secure"));
|
LOG((CLOG_INFO "server connection may not be secure"));
|
||||||
ARCH->sleep(1);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_secureReady = !retry;
|
m_secureReady = !retry;
|
||||||
|
|
||||||
if (m_secureReady) {
|
if (m_secureReady) {
|
||||||
LOG((CLOG_INFO "connected to secure socket"));
|
if (verifyCertFingerprint()) {
|
||||||
showCertificate();
|
LOG((CLOG_INFO "connected to secure socket"));
|
||||||
|
if (!showCertificate()) {
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
LOG((CLOG_ERR "failed to verify server certificate fingerprint"));
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retry;
|
return retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
SecureSocket::showCertificate()
|
SecureSocket::showCertificate()
|
||||||
{
|
{
|
||||||
X509* cert;
|
X509* cert;
|
||||||
|
@ -284,8 +319,11 @@ SecureSocket::showCertificate()
|
||||||
X509_free(cert);
|
X509_free(cert);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throwError("server has no ssl certificate");
|
showError("server has no ssl certificate");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -330,6 +368,21 @@ SecureSocket::checkResult(int n, bool& fatal, bool& retry)
|
||||||
|
|
||||||
case SSL_ERROR_SYSCALL:
|
case SSL_ERROR_SYSCALL:
|
||||||
LOG((CLOG_ERR "secure socket error: SSL_ERROR_SYSCALL"));
|
LOG((CLOG_ERR "secure socket error: SSL_ERROR_SYSCALL"));
|
||||||
|
if (ERR_peek_error() == 0) {
|
||||||
|
if (n == 0) {
|
||||||
|
LOG((CLOG_ERR "an EOF violates the protocol"));
|
||||||
|
}
|
||||||
|
else if (n == -1) {
|
||||||
|
// underlying socket I/O reproted an error
|
||||||
|
try {
|
||||||
|
ARCH->throwErrorOnSocket(getSocket());
|
||||||
|
}
|
||||||
|
catch (XArchNetwork& e) {
|
||||||
|
LOG((CLOG_ERR "%s", e.what()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fatal = true;
|
fatal = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -339,37 +392,27 @@ SecureSocket::checkResult(int n, bool& fatal, bool& retry)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG((CLOG_ERR "secure socket error: SSL_ERROR_SSL"));
|
LOG((CLOG_ERR "secure socket error: unknown"));
|
||||||
fatal = true;
|
fatal = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fatal) {
|
if (fatal) {
|
||||||
showError();
|
showError();
|
||||||
sendEvent(getEvents()->forISocket().disconnected());
|
disconnect();
|
||||||
sendEvent(getEvents()->forIStream().inputShutdown());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SecureSocket::showError()
|
SecureSocket::showError(const char* reason)
|
||||||
{
|
{
|
||||||
String error = getError();
|
if (reason != NULL) {
|
||||||
if (!error.empty()) {
|
LOG((CLOG_ERR "%s", reason));
|
||||||
LOG((CLOG_ERR "secure socket error: %s", error.c_str()));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SecureSocket::throwError(const char* reason)
|
|
||||||
{
|
|
||||||
String error = getError();
|
String error = getError();
|
||||||
if (!error.empty()) {
|
if (!error.empty()) {
|
||||||
throw XSocket(synergy::string::sprintf(
|
LOG((CLOG_ERR "%s", error.c_str()));
|
||||||
"%s: %s", reason, error.c_str()));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw XSocket(reason);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,6 +431,82 @@ SecureSocket::getError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SecureSocket::disconnect()
|
||||||
|
{
|
||||||
|
sendEvent(getEvents()->forISocket().stopRetry());
|
||||||
|
sendEvent(getEvents()->forISocket().disconnected());
|
||||||
|
sendEvent(getEvents()->forIStream().inputShutdown());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SecureSocket::formatFingerprint(String& fingerprint, bool hex, bool separator)
|
||||||
|
{
|
||||||
|
if (hex) {
|
||||||
|
// to hexidecimal
|
||||||
|
synergy::string::toHex(fingerprint, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// all uppercase
|
||||||
|
synergy::string::uppercase(fingerprint);
|
||||||
|
|
||||||
|
if (separator) {
|
||||||
|
// add colon to separate each 2 charactors
|
||||||
|
size_t separators = fingerprint.size() / 2;
|
||||||
|
for (size_t i = 1; i < separators; i++) {
|
||||||
|
fingerprint.insert(i * 3 - 1, ":");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SecureSocket::verifyCertFingerprint()
|
||||||
|
{
|
||||||
|
// calculate received certificate fingerprint
|
||||||
|
X509 *cert = cert = SSL_get_peer_certificate(m_ssl->m_ssl);
|
||||||
|
EVP_MD* tempDigest;
|
||||||
|
unsigned char tempFingerprint[EVP_MAX_MD_SIZE];
|
||||||
|
unsigned int tempFingerprintLen;
|
||||||
|
tempDigest = (EVP_MD*)EVP_sha1();
|
||||||
|
int digestResult = X509_digest(cert, tempDigest, tempFingerprint, &tempFingerprintLen);
|
||||||
|
|
||||||
|
if (digestResult <= 0) {
|
||||||
|
LOG((CLOG_ERR "failed to calculate fingerprint, digest result: %d", digestResult));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// format fingerprint into hexdecimal format with colon separator
|
||||||
|
String fingerprint(reinterpret_cast<char*>(tempFingerprint), tempFingerprintLen);
|
||||||
|
formatFingerprint(fingerprint);
|
||||||
|
LOG((CLOG_NOTE "server fingerprint: %s", fingerprint.c_str()));
|
||||||
|
|
||||||
|
String trustedServersFilename;
|
||||||
|
trustedServersFilename = synergy::string::sprintf(
|
||||||
|
"%s/%s/%s",
|
||||||
|
ARCH->getProfileDirectory().c_str(),
|
||||||
|
kFingerprintDirName,
|
||||||
|
kFingerprintTrustedServersFilename);
|
||||||
|
|
||||||
|
// check if this fingerprint exist
|
||||||
|
String fileLine;
|
||||||
|
std::ifstream file;
|
||||||
|
file.open(trustedServersFilename.c_str());
|
||||||
|
|
||||||
|
bool isValid = false;
|
||||||
|
while (!file.eof() && file.is_open()) {
|
||||||
|
getline(file,fileLine);
|
||||||
|
if (!fileLine.empty()) {
|
||||||
|
if (fileLine.compare(fingerprint) == 0) {
|
||||||
|
isValid = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file.close();
|
||||||
|
return isValid;
|
||||||
|
}
|
||||||
|
|
||||||
ISocketMultiplexerJob*
|
ISocketMultiplexerJob*
|
||||||
SecureSocket::serviceConnect(ISocketMultiplexerJob* job,
|
SecureSocket::serviceConnect(ISocketMultiplexerJob* job,
|
||||||
bool, bool write, bool error)
|
bool, bool write, bool error)
|
||||||
|
|
|
@ -49,7 +49,7 @@ public:
|
||||||
UInt32 secureRead(void* buffer, UInt32 n);
|
UInt32 secureRead(void* buffer, UInt32 n);
|
||||||
UInt32 secureWrite(const void* buffer, UInt32 n);
|
UInt32 secureWrite(const void* buffer, UInt32 n);
|
||||||
void initSsl(bool server);
|
void initSsl(bool server);
|
||||||
void loadCertificates(const char* CertFile);
|
bool loadCertificates(String& CertFile);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// SSL
|
// SSL
|
||||||
|
@ -57,11 +57,15 @@ private:
|
||||||
void createSSL();
|
void createSSL();
|
||||||
bool secureAccept(int s);
|
bool secureAccept(int s);
|
||||||
bool secureConnect(int s);
|
bool secureConnect(int s);
|
||||||
void showCertificate();
|
bool showCertificate();
|
||||||
void checkResult(int n, bool& fatal, bool& retry);
|
void checkResult(int n, bool& fatal, bool& retry);
|
||||||
void showError();
|
void showError(const char* reason = NULL);
|
||||||
void throwError(const char* reason);
|
|
||||||
String getError();
|
String getError();
|
||||||
|
void disconnect();
|
||||||
|
void formatFingerprint(String& fingerprint,
|
||||||
|
bool hex = true,
|
||||||
|
bool separator = true);
|
||||||
|
bool verifyCertFingerprint();
|
||||||
|
|
||||||
ISocketMultiplexerJob*
|
ISocketMultiplexerJob*
|
||||||
serviceConnect(ISocketMultiplexerJob*,
|
serviceConnect(ISocketMultiplexerJob*,
|
||||||
|
|
|
@ -24,25 +24,27 @@ class ArgsBase {
|
||||||
public:
|
public:
|
||||||
ArgsBase();
|
ArgsBase();
|
||||||
virtual ~ArgsBase();
|
virtual ~ArgsBase();
|
||||||
bool m_daemon;
|
|
||||||
bool m_backend;
|
public:
|
||||||
bool m_restartable;
|
bool m_daemon;
|
||||||
bool m_noHooks;
|
bool m_backend;
|
||||||
const char* m_pname;
|
bool m_restartable;
|
||||||
const char* m_logFilter;
|
bool m_noHooks;
|
||||||
const char* m_logFile;
|
const char* m_pname;
|
||||||
const char* m_display;
|
const char* m_logFilter;
|
||||||
String m_name;
|
const char* m_logFile;
|
||||||
bool m_disableTray;
|
const char* m_display;
|
||||||
bool m_enableIpc;
|
String m_name;
|
||||||
bool m_enableDragDrop;
|
bool m_disableTray;
|
||||||
|
bool m_enableIpc;
|
||||||
|
bool m_enableDragDrop;
|
||||||
#if SYSAPI_WIN32
|
#if SYSAPI_WIN32
|
||||||
bool m_debugServiceWait;
|
bool m_debugServiceWait;
|
||||||
bool m_pauseOnExit;
|
bool m_pauseOnExit;
|
||||||
bool m_stopOnDeskSwitch;
|
bool m_stopOnDeskSwitch;
|
||||||
#endif
|
#endif
|
||||||
#if WINAPI_XWINDOWS
|
#if WINAPI_XWINDOWS
|
||||||
bool m_disableXInitThreads;
|
bool m_disableXInitThreads;
|
||||||
#endif
|
#endif
|
||||||
bool m_shouldExit;
|
bool m_shouldExit;
|
||||||
String m_synergyAddress;
|
String m_synergyAddress;
|
||||||
|
|
|
@ -331,7 +331,6 @@ ClientApp::handleClientDisconnected(const Event&, void*)
|
||||||
updateStatus();
|
updateStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Client*
|
Client*
|
||||||
ClientApp::openClient(const String& name, const NetworkAddress& address,
|
ClientApp::openClient(const String& name, const NetworkAddress& address,
|
||||||
synergy::Screen* screen)
|
synergy::Screen* screen)
|
||||||
|
@ -342,8 +341,7 @@ ClientApp::openClient(const String& name, const NetworkAddress& address,
|
||||||
address,
|
address,
|
||||||
new TCPSocketFactory(m_events, getSocketMultiplexer()),
|
new TCPSocketFactory(m_events, getSocketMultiplexer()),
|
||||||
screen,
|
screen,
|
||||||
args().m_enableDragDrop,
|
args());
|
||||||
args().m_enableCrypto);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
m_events->adoptHandler(
|
m_events->adoptHandler(
|
||||||
|
|
|
@ -26,5 +26,5 @@ public:
|
||||||
ClientArgs();
|
ClientArgs();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
int m_yscroll;
|
int m_yscroll;
|
||||||
};
|
};
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
<Feature Id="ProductFeature" Title="$(var.Name)">
|
<Feature Id="ProductFeature" Title="$(var.Name)">
|
||||||
<ComponentGroupRef Id="ProductComponents" />
|
<ComponentGroupRef Id="ProductComponents" />
|
||||||
|
<ComponentGroupRef Id="OpenSslComponents" />
|
||||||
<MergeRef Id="CRT" />
|
<MergeRef Id="CRT" />
|
||||||
</Feature>
|
</Feature>
|
||||||
|
|
||||||
|
@ -61,6 +62,7 @@
|
||||||
<Directory Id="$(var.ProgramFilesFolder)">
|
<Directory Id="$(var.ProgramFilesFolder)">
|
||||||
<Directory Id="INSTALLFOLDER" Name="$(var.Name)">
|
<Directory Id="INSTALLFOLDER" Name="$(var.Name)">
|
||||||
<Merge Id="CRT" Language="0" SourceFile="$(var.CRT)" DiskId="1" />
|
<Merge Id="CRT" Language="0" SourceFile="$(var.CRT)" DiskId="1" />
|
||||||
|
<Directory Id="OpenSslDir" Name="OpenSSL" />
|
||||||
</Directory>
|
</Directory>
|
||||||
</Directory>
|
</Directory>
|
||||||
<Directory Id="ProgramMenuFolder" />
|
<Directory Id="ProgramMenuFolder" />
|
||||||
|
@ -68,6 +70,7 @@
|
||||||
</Fragment>
|
</Fragment>
|
||||||
|
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
|
||||||
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
|
<ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
|
||||||
|
|
||||||
<Component Id="Core" Guid="EC9AD3B0-277C-4157-B5C8-5FD5B6A5F4AD">
|
<Component Id="Core" Guid="EC9AD3B0-277C-4157-B5C8-5FD5B6A5F4AD">
|
||||||
|
@ -112,5 +115,14 @@
|
||||||
</Component>
|
</Component>
|
||||||
|
|
||||||
</ComponentGroup>
|
</ComponentGroup>
|
||||||
|
|
||||||
|
<ComponentGroup Id="OpenSslComponents" Directory="OpenSslDir">
|
||||||
|
<Component Id="OpenSsl" Guid="92648F77-65A6-4B16-AC59-A1F37BD341B1">
|
||||||
|
<File Source="$(var.ExtPath)/openssl/out32dll/libeay32.dll" Id="OpenSslDll1" />
|
||||||
|
<File Source="$(var.ExtPath)/openssl/out32dll/ssleay32.dll" Id="OpenSslDll2" />
|
||||||
|
<File Source="$(var.ExtPath)/openssl/out32dll/openssl.exe" />
|
||||||
|
<File Source="$(var.ResPath)/openssl/synergy.conf" />
|
||||||
|
</Component>
|
||||||
|
</ComponentGroup>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
</Wix>
|
</Wix>
|
||||||
|
|
|
@ -140,7 +140,11 @@ TEST_F(NetworkTests, sendToClient_mockData)
|
||||||
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
|
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
|
||||||
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
|
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
|
||||||
|
|
||||||
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, true, false);
|
|
||||||
|
ClientArgs args;
|
||||||
|
args.m_enableDragDrop = true;
|
||||||
|
args.m_enableCrypto = false;
|
||||||
|
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, args);
|
||||||
|
|
||||||
m_events.adoptHandler(
|
m_events.adoptHandler(
|
||||||
m_events.forIScreen().fileRecieveCompleted(), &client,
|
m_events.forIScreen().fileRecieveCompleted(), &client,
|
||||||
|
@ -192,7 +196,11 @@ TEST_F(NetworkTests, sendToClient_mockFile)
|
||||||
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
|
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
|
||||||
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
|
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
|
||||||
|
|
||||||
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, true, false);
|
|
||||||
|
ClientArgs args;
|
||||||
|
args.m_enableDragDrop = true;
|
||||||
|
args.m_enableCrypto = false;
|
||||||
|
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, args);
|
||||||
|
|
||||||
m_events.adoptHandler(
|
m_events.adoptHandler(
|
||||||
m_events.forIScreen().fileRecieveCompleted(), &client,
|
m_events.forIScreen().fileRecieveCompleted(), &client,
|
||||||
|
@ -238,7 +246,10 @@ TEST_F(NetworkTests, sendToServer_mockData)
|
||||||
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
|
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
|
||||||
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
|
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
|
||||||
|
|
||||||
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, true, false);
|
ClientArgs args;
|
||||||
|
args.m_enableDragDrop = true;
|
||||||
|
args.m_enableCrypto = false;
|
||||||
|
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, args);
|
||||||
|
|
||||||
m_events.adoptHandler(
|
m_events.adoptHandler(
|
||||||
m_events.forClientListener().connected(), &listener,
|
m_events.forClientListener().connected(), &listener,
|
||||||
|
@ -290,7 +301,10 @@ TEST_F(NetworkTests, sendToServer_mockFile)
|
||||||
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
|
ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape));
|
||||||
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
|
ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos));
|
||||||
|
|
||||||
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, true, false);
|
ClientArgs args;
|
||||||
|
args.m_enableDragDrop = true;
|
||||||
|
args.m_enableCrypto = false;
|
||||||
|
Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, args);
|
||||||
|
|
||||||
m_events.adoptHandler(
|
m_events.adoptHandler(
|
||||||
m_events.forClientListener().connected(), &listener,
|
m_events.forClientListener().connected(), &listener,
|
||||||
|
|
|
@ -53,3 +53,32 @@ TEST(StringTests, sprintf)
|
||||||
|
|
||||||
EXPECT_EQ("answer=42", result);
|
EXPECT_EQ("answer=42", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(StringTests, toHex)
|
||||||
|
{
|
||||||
|
String subject = "foobar";
|
||||||
|
int width = 2;
|
||||||
|
|
||||||
|
string::toHex(subject, width);
|
||||||
|
|
||||||
|
EXPECT_EQ("666f6f626172", subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringTests, uppercase)
|
||||||
|
{
|
||||||
|
String subject = "12foo3BaR";
|
||||||
|
|
||||||
|
string::uppercase(subject);
|
||||||
|
|
||||||
|
EXPECT_EQ("12FOO3BAR", subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringTests, removeChar)
|
||||||
|
{
|
||||||
|
String subject = "foobar";
|
||||||
|
const char c = 'o';
|
||||||
|
|
||||||
|
string::removeChar(subject, c);
|
||||||
|
|
||||||
|
EXPECT_EQ("fbar", subject);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue