}
void ClientSyncer::coreSocketError(QAbstractSocket::SocketError) {
+ qDebug() << "coreSocketError" << socket << socket->errorString();
emit connectionError(socket->errorString());
socket->deleteLater();
}
//clientMode = RemoteCore;
//emit coreConnectionMsg(tr("Connecting..."));
Q_ASSERT(!socket);
+
+#ifndef QT_NO_OPENSSL
+ QSslSocket *sock = new QSslSocket(Client::instance());
+#else
QTcpSocket *sock = new QTcpSocket(Client::instance());
+#endif
+
if(conn.contains("useProxy") && conn["useProxy"].toBool()) {
QNetworkProxy proxy((QNetworkProxy::ProxyType)conn["proxyType"].toInt(), conn["proxyHost"].toString(), conn["proxyPort"].toUInt(), conn["proxyUser"].toString(), conn["proxyPassword"].toString());
sock->setProxy(proxy);
clientInit["ClientVersion"] = Global::quasselVersion;
clientInit["ClientDate"] = Global::quasselDate;
clientInit["ClientBuild"] = Global::quasselBuild; // this is a minimum, since we probably won't update for every commit
- clientInit["UseSsl"] = false; // FIXME implement SSL
+ clientInit["UseSsl"] = coreConnectionInfo["useSsl"];
+
SignalProxy::writeDataToDevice(socket, clientInit);
}
return;
}
emit connectionMsg(msg["CoreInfo"].toString());
+ if(coreConnectionInfo["useSsl"].toBool()) {
+ if(msg["SupportSsl"].toBool()) {
+ QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket);
+ if(sslSocket) {
+ connect(sslSocket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
+ sslSocket->startClientEncryption();
+ emit encrypted(true);
+ } else {
+ emit connectionError(tr("<b>This client is built without SSL Support!</b><br />Disable the usage of SSL in the account settings."));
+ emit encrypted(false);
+ disconnectFromCore();
+ return;
+ }
+ } else {
+ emit connectionError(tr("<b>The Quassel Core you are trying to connect to does not support SSL!</b><br />If you want to connect anyways, disable the usage of SSL in the account settings."));
+ emit encrypted(false);
+ disconnectFromCore();
+ return;
+ }
+ }
+
if(!msg["Configured"].toBool()) {
// start wizard
emit startCoreSetup(msg["StorageBackends"].toList());
}
}
+void ClientSyncer::sslErrors(const QList<QSslError> &errors) {
+ qDebug() << "SSL Errors:";
+ foreach(QSslError err, errors)
+ qDebug() << " " << err;
+
+ QSslSocket *socket = qobject_cast<QSslSocket *>(sender());
+ if(socket)
+ socket->ignoreSslErrors();
+}
#include <QPointer>
#include <QString>
#include <QTcpSocket>
+#include <QSslSocket>
#include <QVariantMap>
class IrcUser;
void coreSetupSuccess();
void coreSetupFailed(const QString &error);
+ void encrypted(bool);
public slots:
void connectToCore(const QVariantMap &);
void sessionStateReceived(const QVariantMap &state);
void doCoreSetup(const QVariant &setupData);
-
+ void sslErrors(const QList<QSslError> &errors);
+
private:
QPointer<QIODevice> socket;
quint32 blockSize;
QByteArray sig(method.signature());
return sig.left(sig.indexOf("("));
}
+
+QDir quasselDir() {
+ // kinda ugly, but I currently see no other way to do that
+#ifdef Q_OS_WIN32
+ QString quasselDir = QDir::homePath() + qgetenv("APPDATA") + "/quassel/";
+#else
+ QString quasselDir = QDir::homePath() + "/.quassel/";
+#endif
+
+ QDir qDir(quasselDir);
+ if(!qDir.exists(quasselDir))
+ qDir.mkpath(quasselDir);
+
+ return qDir;
+}
#ifndef _UTIL_H_
#define _UTIL_H_
+#include <QDir>
#include <QIODevice>
#include <QVariant>
#include <QString>
QByteArray methodName(const QMetaMethod &method);
+QDir quasselDir();
+
#endif
#include "sqlitestorage.h"
#include "network.h"
+#include "util.h"
+
Core *Core::instanceptr = 0;
QMutex Core::mutex;
QTcpSocket *socket = server.nextPendingConnection();
connect(socket, SIGNAL(disconnected()), this, SLOT(clientDisconnected()));
connect(socket, SIGNAL(readyRead()), this, SLOT(clientHasData()));
+ connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)));
+
QVariantMap clientInfo;
blocksizes.insert(socket, (quint32)0);
qDebug() << "Client connected from" << qPrintable(socket->peerAddress().toString());
"Up %3d%4h%5m (since %6)").arg(Global::quasselVersion).arg(Global::quasselBuild)
.arg(updays).arg(uphours,2,10,QChar('0')).arg(upmins,2,10,QChar('0')).arg(startTime.toString(Qt::TextDate));
- reply["SupportSsl"] = false;
+ SslServer *sslServer = qobject_cast<SslServer *>(&server);
+ QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket);
+ bool supportSsl = (bool)sslServer && (bool)sslSocket && sslServer->certIsValid();
+ reply["SupportSsl"] = supportSsl;
+ // switch to ssl after client has been informed about our capabilities (see below)
+
reply["LoginEnabled"] = true;
// Just version information -- check it!
clientInfo[socket] = msg; // store for future reference
reply["MsgType"] = "ClientInitAck";
SignalProxy::writeDataToDevice(socket, reply);
+
+ // after we told the client that we are ssl capable we switch to ssl mode
+ if(supportSsl && msg["UseSsl"].toBool()) {
+ qDebug() << "Starting TLS for Client:" << qPrintable(socket->peerAddress().toString());
+ connect(sslSocket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
+ sslSocket->startServerEncryption();
+ }
+
+
} else {
// for the rest, we need an initialized connection
if(!clientInfo.contains(socket)) {
sess->start();
return sess;
}
+
+void Core::sslErrors(const QList<QSslError> &errors) {
+ Q_UNUSED(errors);
+ QSslSocket *socket = qobject_cast<QSslSocket *>(sender());
+ if(socket)
+ socket->ignoreSslErrors();
+}
+
+void Core::socketError(QAbstractSocket::SocketError err) {
+ QAbstractSocket *socket = qobject_cast<QAbstractSocket *>(sender());
+ if(socket && err != QAbstractSocket::RemoteHostClosedError)
+ qDebug() << "Core::socketError()" << socket << err << socket->errorString();
+}
#include <QString>
#include <QVariant>
#include <QTimer>
-#include <QTcpServer>
#include <QTcpSocket>
+#include <QSslSocket>
#include "bufferinfo.h"
#include "message.h"
#include "global.h"
#include "sessionthread.h"
+#include "sslserver.h"
#include "types.h"
class CoreSession;
bool initStorage(QVariantMap dbSettings, bool setup = false);
+ void sslErrors(const QList<QSslError> &errors);
+ void socketError(QAbstractSocket::SocketError);
+
private:
Core();
~Core();
Storage *storage;
QTimer _storageSyncTimer;
- QTcpServer server; // TODO: implement SSL
+#ifndef QT_NO_OPENSSL
+ SslServer server;
+#else
+ QTcpServer server;
+#endif
+
QHash<QTcpSocket *, quint32> blocksizes;
QHash<QTcpSocket *, QVariantMap> clientInfo;
DEPMOD = common
QT_MOD = core network sql script
SRCS = core.cpp corebacklogmanager.cpp corebufferviewconfig.cpp corebufferviewmanager.cpp coresession.cpp coresettings.cpp networkconnection.cpp sqlitestorage.cpp abstractsqlstorage.cpp storage.cpp basichandler.cpp \
- ircserverhandler.cpp userinputhandler.cpp ctcphandler.cpp coreusersettings.cpp sessionthread.cpp
+ ircserverhandler.cpp userinputhandler.cpp ctcphandler.cpp coreusersettings.cpp sessionthread.cpp sslserver.cpp
HDRS = core.h corebacklogmanager.h corebufferviewconfig.h corebufferviewmanager.h coresession.h coresettings.h networkconnection.h sqlitestorage.h abstractsqlstorage.h storage.h basichandler.h \
- ircserverhandler.h userinputhandler.h ctcphandler.h coreusersettings.h sessionthread.h
+ ircserverhandler.h userinputhandler.h ctcphandler.h coreusersettings.h sessionthread.h sslserver.h
#include "network.h"
+#include "util.h"
+
SqliteStorage::SqliteStorage(QObject *parent)
: AbstractSqlStorage(parent)
{
}
QString SqliteStorage::backlogFile() {
- // kinda ugly, but I currently see no other way to do that
-#ifdef Q_OS_WIN32
- QString quasselDir = QDir::homePath() + qgetenv("APPDATA") + "\\quassel\\";
-#else
- QString quasselDir = QDir::homePath() + "/.quassel/";
-#endif
-
- QDir qDir(quasselDir);
- if(!qDir.exists(quasselDir))
- qDir.mkpath(quasselDir);
-
- return quasselDir + "quassel-storage.sqlite";
+ return quasselDir().absolutePath() + "/quassel-storage.sqlite";
}
connect(clientSyncer, SIGNAL(socketStateChanged(QAbstractSocket::SocketState)),this, SLOT(initPhaseSocketState(QAbstractSocket::SocketState)));
connect(clientSyncer, SIGNAL(connectionError(const QString &)), this, SLOT(initPhaseError(const QString &)));
connect(clientSyncer, SIGNAL(connectionMsg(const QString &)), this, SLOT(initPhaseMsg(const QString &)));
+ connect(clientSyncer, SIGNAL(encrypted(bool)), this, SLOT(encrypted(bool)));
connect(clientSyncer, SIGNAL(startLogin()), this, SLOT(startLogin()));
connect(clientSyncer, SIGNAL(loginFailed(const QString &)), this, SLOT(loginFailed(const QString &)));
connect(clientSyncer, SIGNAL(loginSuccess()), this, SLOT(startSync()));
/*** Phase One: initializing the core connection ***/
void CoreConnectDlg::connectToCore() {
+ ui.secureConnection->hide();
ui.connectIcon->setPixmap(QPixmap::fromImage(QImage(":/22x22/actions/network-disconnect")));
ui.connectLabel->setText(tr("Connect to %1").arg(accountData["Host"].toString()));
ui.coreInfoLabel->setText("");
void CoreConnectDlg::initPhaseError(const QString &error) {
doingAutoConnect = false;
+ ui.secureConnection->hide();
ui.connectIcon->setPixmap(QPixmap::fromImage(QImage(":/22x22/status/dialog-error")));
//ui.connectLabel->setBrush(QBrush("red"));
ui.connectLabel->setText(tr("<div style=color:red;>Connection to %1 failed!</div>").arg(accountData["Host"].toString()));
ui.coreInfoLabel->setText(msg);
}
+void CoreConnectDlg::encrypted(bool useSsl) {
+ if(useSsl)
+ ui.secureConnection->show();
+ else
+ ui.secureConnection->hide();
+}
+
void CoreConnectDlg::initPhaseSocketState(QAbstractSocket::SocketState state) {
QString s;
QString host = accountData["Host"].toString();
ui.port->setValue(acct["Port"].toUInt());
ui.useInternal->setChecked(acct["UseInternal"].toBool());
ui.accountName->setText(acct["AccountName"].toString());
+ ui.useSsl->setChecked(account["useSsl"].toBool());
ui.useProxy->setChecked(account["useProxy"].toBool());
ui.proxyHost->setText(account["proxyHost"].toString());
ui.proxyPort->setValue(account["proxyPort"].toUInt());
account["Host"] = ui.host->text().trimmed();
account["Port"] = ui.port->value();
account["UseInternal"] = ui.useInternal->isChecked();
+ account["useSsl"] = ui.useSsl->isChecked();
account["useProxy"] = ui.useProxy->isChecked();
account["proxyHost"] = ui.proxyHost->text().trimmed();
account["proxyPort"] = ui.proxyPort->value();
void initPhaseError(const QString &error);
void initPhaseMsg(const QString &msg);
void initPhaseSocketState(QAbstractSocket::SocketState);
+ void encrypted(bool);
/*** Phase Two: Login ***/
void startLogin();
</widget>
</item>
<item row="3" column="1" colspan="2" >
- <widget class="QCheckBox" name="useSSL" >
- <property name="enabled" >
- <bool>false</bool>
- </property>
+ <widget class="QCheckBox" name="useSsl" >
<property name="text" >
<string>Use secure connection (SSL)</string>
</property>
</sizepolicy>
</property>
<property name="currentIndex" >
- <number>0</number>
+ <number>1</number>
</property>
<widget class="QWidget" name="accountPage" >
<layout class="QVBoxLayout" >
</property>
</widget>
</item>
+ <item row="0" column="3" >
+ <widget class="QLabel" name="secureConnection" >
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="pixmap" >
+ <pixmap resource="../../icons/icons.qrc" >:/22x22/actions/oxygen/22x22/actions/document-encrypt.png</pixmap>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>
{ using namespace Global;
quasselVersion = "0.2.0-alpha4-pre";
- quasselDate = "2008-03-29";
- quasselBuild = 664;
+ quasselDate = "2008-03-30";
+ quasselBuild = 668;
//! Minimum client build number the core needs
clientBuildNeeded = 642;