From 4aed4b037ea6feaeec09743e5d6018f58d47a535 Mon Sep 17 00:00:00 2001 From: Marcus Eggenberger Date: Thu, 29 Jan 2009 00:01:32 +0100 Subject: [PATCH 1/1] Quassel warns you now properly about SSL Errors --- src/client/clientsyncer.cpp | 69 +++++++++--- src/client/clientsyncer.h | 17 ++- src/qtui/coreconnectdlg.cpp | 100 ++++++++++++++++- src/qtui/coreconnectdlg.h | 18 +++ src/qtui/ui/coreconnectdlg.ui | 206 +++++++++++++++++++++++++++------- 5 files changed, 351 insertions(+), 59 deletions(-) diff --git a/src/client/clientsyncer.cpp b/src/client/clientsyncer.cpp index fb8bebc2..e9d64f32 100644 --- a/src/client/clientsyncer.cpp +++ b/src/client/clientsyncer.cpp @@ -222,33 +222,42 @@ void ClientSyncer::clientInitAck(const QVariantMap &msg) { } emit connectionMsg(msg["CoreInfo"].toString()); +#ifndef QT_NO_COMPRESS + if(msg["SupportsCompression"].toBool()) { + socket->setProperty("UseCompression", true); + } +#endif + + _coreMsgBuffer = msg; #ifdef HAVE_SSL if(coreConnectionInfo["useSsl"].toBool()) { if(msg["SupportSsl"].toBool()) { QSslSocket *sslSocket = qobject_cast(socket); Q_ASSERT(sslSocket); + connect(sslSocket, SIGNAL(encrypted()), this, SLOT(sslSocketEncrypted())); connect(sslSocket, SIGNAL(sslErrors(const QList &)), this, SLOT(sslErrors(const QList &))); + sslSocket->startClientEncryption(); } else { emit connectionError(tr("The Quassel Core you are trying to connect to does not support SSL!
If you want to connect anyways, disable the usage of SSL in the account settings.")); disconnectFromCore(); - return; } + return; } #endif + // if we use SSL we wait for the next step until every SSL warning has been cleared + connectionReady(); +} -#ifndef QT_NO_COMPRESS - if(msg["SupportsCompression"].toBool()) { - socket->setProperty("UseCompression", true); - } -#endif - - if(!msg["Configured"].toBool()) { +void ClientSyncer::connectionReady() { + if(!_coreMsgBuffer["Configured"].toBool()) { // start wizard - emit startCoreSetup(msg["StorageBackends"].toList()); - } else if(msg["LoginEnabled"].toBool()) { + emit startCoreSetup(_coreMsgBuffer["StorageBackends"].toList()); + } else if(_coreMsgBuffer["LoginEnabled"].toBool()) { emit startLogin(); } + _coreMsgBuffer.clear(); + resetWarningsHandler(); } void ClientSyncer::doCoreSetup(const QVariant &setupData) { @@ -329,14 +338,44 @@ void ClientSyncer::checkSyncState() { } } +void ClientSyncer::setWarningsHandler(const char *slot) { + resetWarningsHandler(); + connect(this, SIGNAL(handleIgnoreWarnings(bool)), this, slot); +} + +void ClientSyncer::resetWarningsHandler() { + disconnect(this, SIGNAL(handleIgnoreWarnings(bool)), this, 0); +} + #ifdef HAVE_SSL -void ClientSyncer::sslErrors(const QList &errors) { - qDebug() << "SSL Errors:"; - foreach(QSslError err, errors) - qDebug() << " " << err; +void ClientSyncer::ignoreSslWarnings(bool permanently) { + QAbstractSocket *sock = qobject_cast(socket); + if(sock) { + // ensure that a proper state is displayed and no longer a warning + emit socketStateChanged(sock->state()); + } + emit connectionMsg(_coreMsgBuffer["CoreInfo"].toString()); + connectionReady(); +} + +void ClientSyncer::sslSocketEncrypted() { + QSslSocket *socket = qobject_cast(sender()); + if(socket) { + QByteArray digest = socket->peerCertificate().digest(); + } +} +void ClientSyncer::sslErrors(const QList &errors) { QSslSocket *socket = qobject_cast(sender()); - if(socket) + if(socket) { socket->ignoreSslErrors(); + } + + QStringList warnings; + foreach(QSslError err, errors) + warnings << err.errorString(); + + setWarningsHandler(SLOT(ignoreSslWarnings(bool))); + emit connectionWarnings(warnings); } #endif diff --git a/src/client/clientsyncer.h b/src/client/clientsyncer.h index ea65d48f..7ff5399b 100644 --- a/src/client/clientsyncer.h +++ b/src/client/clientsyncer.h @@ -44,9 +44,12 @@ public: ClientSyncer(QObject *parent = 0); ~ClientSyncer(); + inline const QIODevice *currentDevice() { return socket; } + signals: void recvPartialItem(quint32 avail, quint32 size); void connectionError(const QString &errorMsg); + void connectionWarnings(const QStringList &warnings); void connectionMsg(const QString &msg); void sessionProgress(quint32 part, quint32 total); void networksProgress(quint32 part, quint32 total); @@ -66,12 +69,16 @@ signals: void startInternalCore(ClientSyncer *syncer); void connectToInternalCore(SignalProxy *proxy); + void handleIgnoreWarnings(bool permanently); + public slots: void connectToCore(const QVariantMap &); void loginToCore(const QString &user, const QString &passwd); void disconnectFromCore(); void useInternalCore(); + inline void ignoreWarnings(bool permanently) { emit handleIgnoreWarnings(permanently); } + private slots: void coreSocketError(QAbstractSocket::SocketError); void coreHasData(); @@ -88,15 +95,23 @@ private slots: void internalSessionStateReceived(const QVariant &packedState); void sessionStateReceived(const QVariantMap &state); + void connectionReady(); void doCoreSetup(const QVariant &setupData); + + void setWarningsHandler(const char *slot); + void resetWarningsHandler(); + #ifdef HAVE_SSL - void sslErrors(const QList &errors); + void ignoreSslWarnings(bool permanently); + void sslSocketEncrypted(); + void sslErrors(const QList &errors); #endif private: QPointer socket; quint32 blockSize; QVariantMap coreConnectionInfo; + QVariantMap _coreMsgBuffer; QSet netsToSync; int numNetsToSync; diff --git a/src/qtui/coreconnectdlg.cpp b/src/qtui/coreconnectdlg.cpp index f44ba0f4..16655ffd 100644 --- a/src/qtui/coreconnectdlg.cpp +++ b/src/qtui/coreconnectdlg.cpp @@ -18,11 +18,17 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ +#include "coreconnectdlg.h" + #include +#include #include #include -#include "coreconnectdlg.h" +#ifdef HAVE_SSL +#include +#include +#endif #include "client.h" #include "clientsettings.h" @@ -51,8 +57,6 @@ CoreConnectDlg::CoreConnectDlg(bool autoconnect, QWidget *parent) clientSyncer = new ClientSyncer(this); Client::registerClientSyncer(clientSyncer); -// connect(this, SIGNAL(newClientSyncer(ClientSyncer *)), Client::instance(), SIGNAL(newClientSyncer(ClientSyncer *))); -// emit newClientSyncer(clientSyncer); // announce the new client syncer via the client. wizard = 0; @@ -87,6 +91,7 @@ CoreConnectDlg::CoreConnectDlg(bool autoconnect, QWidget *parent) 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(connectionWarnings(const QStringList &)), this, SLOT(initPhaseWarnings(const QStringList &))); connect(clientSyncer, SIGNAL(connectionMsg(const QString &)), this, SLOT(initPhaseMsg(const QString &))); connect(clientSyncer, SIGNAL(startLogin()), this, SLOT(startLogin())); connect(clientSyncer, SIGNAL(loginFailed(const QString &)), this, SLOT(loginFailed(const QString &))); @@ -259,6 +264,39 @@ void CoreConnectDlg::initPhaseError(const QString &error) { connect(ui.loginButtonBox, SIGNAL(rejected()), this, SLOT(reject())); } +void CoreConnectDlg::initPhaseWarnings(const QStringList &warnings) { + doingAutoConnect = false; + ui.secureConnection->hide(); + ui.connectIcon->setPixmap(BarIcon("dialog-warning")); + ui.connectLabel->setText(tr("
Errors occurred while connecting to \"%1\":
").arg(accountData["Host"].toString())); + QStringList warningItems; + foreach(QString warning, warnings) { + warningItems << QString("
  • %1
  • ").arg(warning); + } + ui.coreInfoLabel->setText(QString("
      %1
    ").arg(warningItems.join(""))); + ui.loginStack->setCurrentWidget(ui.connectionWarningsPage); + ui.loginButtonBox->setStandardButtons(QDialogButtonBox::Cancel); + ui.loginButtonBox->button(QDialogButtonBox::Cancel)->setFocus(); + disconnect(ui.loginButtonBox, 0, this, 0); + connect(ui.loginButtonBox, SIGNAL(rejected()), this, SLOT(restartPhaseNull())); +} + +void CoreConnectDlg::on_viewSslCertButton_clicked() { +#ifdef HAVE_SSL + const QSslSocket *socket = qobject_cast(clientSyncer->currentDevice()); + if(!socket) + return; + + SslCertDisplayDialog dialog(socket->peerName(), socket->peerCertificate()); + dialog.exec(); +#endif +} + +void CoreConnectDlg::on_ignoreWarningsButton_clicked() { + clientSyncer->ignoreWarnings(ui.ignoreWarningsPermanently->isChecked()); +} + + void CoreConnectDlg::initPhaseMsg(const QString &msg) { ui.coreInfoLabel->setText(msg); } @@ -516,3 +554,59 @@ void CoreAccountEditDlg::on_accountName_textChanged(const QString &text) { Q_UNUSED(text); setWidgetStates(); } + + +// ======================================== +// SslCertDisplayDialog +// ======================================== +SslCertDisplayDialog::SslCertDisplayDialog(const QString &host, const QSslCertificate &cert, QWidget *parent) + : QDialog(parent) +{ +#ifndef HAVE_SSL + Q_UNUSED(cert) +#else + + setWindowTitle(tr("SSL Certificate used by %1").arg(host)); + + QVBoxLayout *mainLayout = new QVBoxLayout(this); + + QGroupBox *issuerBox = new QGroupBox(tr("Issuer Info"), this); + QFormLayout *issuerLayout = new QFormLayout(issuerBox); + issuerLayout->addRow(tr("Organization:"), new QLabel(cert.issuerInfo(QSslCertificate::Organization), this)); + issuerLayout->addRow(tr("Locality Name:"), new QLabel(cert.issuerInfo(QSslCertificate::LocalityName), this)); + issuerLayout->addRow(tr("Organizational Unit Name:"), new QLabel(cert.issuerInfo(QSslCertificate::OrganizationalUnitName), this)); + issuerLayout->addRow(tr("Country Name:"), new QLabel(cert.issuerInfo(QSslCertificate::CountryName), this)); + issuerLayout->addRow(tr("State or Province Name:"), new QLabel(cert.issuerInfo(QSslCertificate::StateOrProvinceName), this)); + mainLayout->addWidget(issuerBox); + + QGroupBox *subjectBox = new QGroupBox(tr("Subject Info"), this); + QFormLayout *subjectLayout = new QFormLayout(subjectBox); + subjectLayout->addRow(tr("Organization:"), new QLabel(cert.subjectInfo(QSslCertificate::Organization), this)); + subjectLayout->addRow(tr("Locality Name:"), new QLabel(cert.subjectInfo(QSslCertificate::LocalityName), this)); + subjectLayout->addRow(tr("Organizational Unit Name:"), new QLabel(cert.subjectInfo(QSslCertificate::OrganizationalUnitName), this)); + subjectLayout->addRow(tr("Country Name:"), new QLabel(cert.subjectInfo(QSslCertificate::CountryName), this)); + subjectLayout->addRow(tr("State or Province Name:"), new QLabel(cert.subjectInfo(QSslCertificate::StateOrProvinceName), this)); + mainLayout->addWidget(subjectBox); + + QGroupBox *additionalBox = new QGroupBox(tr("Additional Info"), this); + QFormLayout *additionalLayout = new QFormLayout(additionalBox); + additionalLayout->addRow(tr("Valid From:"), new QLabel(cert.effectiveDate().toString(), this)); + additionalLayout->addRow(tr("Valid To:"), new QLabel(cert.expiryDate().toString(), this)); + QStringList hostnames = cert.alternateSubjectNames().values(QSsl::DnsEntry); + for(int i = 0; i < hostnames.count(); i++) { + additionalLayout->addRow(tr("Hostname %1:").arg(i + 1), new QLabel(hostnames[i], this)); + } + QStringList mailaddresses = cert.alternateSubjectNames().values(QSsl::EmailEntry); + for(int i = 0; i < mailaddresses.count(); i++) { + additionalLayout->addRow(tr("E-Mail Address %1:").arg(i + 1), new QLabel(mailaddresses[i], this)); + } + mainLayout->addWidget(additionalBox); + + + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, this); + mainLayout->addWidget(buttonBox); + + connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); +#endif +}; diff --git a/src/qtui/coreconnectdlg.h b/src/qtui/coreconnectdlg.h index cac4721e..01bc75a6 100644 --- a/src/qtui/coreconnectdlg.h +++ b/src/qtui/coreconnectdlg.h @@ -52,6 +52,8 @@ private slots: void on_editAccount_clicked(); void on_deleteAccount_clicked(); void on_useInternalCore_clicked(); + void on_viewSslCertButton_clicked(); + void on_ignoreWarningsButton_clicked(); void on_accountList_itemDoubleClicked(QListWidgetItem *item); void on_accountButtonBox_accepted(); @@ -62,6 +64,7 @@ private slots: void connectToCore(); void initPhaseError(const QString &error); + void initPhaseWarnings(const QStringList &warnings); void initPhaseMsg(const QString &msg); void initPhaseSocketState(QAbstractSocket::SocketState); @@ -103,6 +106,10 @@ private: CoreConfigWizard *wizard; }; + +// ======================================== +// CoreAccountEditDlg +// ======================================== class CoreAccountEditDlg : public QDialog { Q_OBJECT @@ -124,4 +131,15 @@ private: QVariantMap account; }; +// ======================================== +// SslCertDisplayDialog +// ======================================== +class QSslCertificate; + +class SslCertDisplayDialog : public QDialog { + Q_OBJECT + +public: + SslCertDisplayDialog(const QString &host, const QSslCertificate &cert, QWidget *parent = 0); +}; #endif diff --git a/src/qtui/ui/coreconnectdlg.ui b/src/qtui/ui/coreconnectdlg.ui index e172e8a0..7f2094db 100644 --- a/src/qtui/ui/coreconnectdlg.ui +++ b/src/qtui/ui/coreconnectdlg.ui @@ -5,8 +5,8 @@ 0 0 - 563 - 356 + 539 + 347 @@ -23,6 +23,9 @@ :/16x16/actions/network-disconnect:/16x16/actions/network-disconnect + + 0 + @@ -32,9 +35,17 @@ - 0 + 1 + + + 0 + 0 + 539 + 340 + + @@ -133,6 +144,14 @@ + + + 0 + 0 + 539 + 347 + + @@ -146,12 +165,6 @@ Initializing your connection - - 0 - - - 4 - @@ -233,23 +246,21 @@ SOME SPACE - 0 + 1 + + + 0 + 0 + 485 + 135 + + - - - - Qt::Vertical - - - - 20 - 40 - - - - + + 0 + @@ -275,9 +286,6 @@ SOME SPACE Login - - 4 - @@ -322,8 +330,120 @@ SOME SPACE + + + + 0 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + view SSL Certificate + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Vertical + + + + 20 + 48 + + + + + + + + + + add to known hosts + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Continue connection + + + + + + + + + + 0 + 0 + 485 + 135 + + + + 0 + + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -387,24 +507,22 @@ SOME SPACE + label_7 + - - - - Qt::Vertical - - - - 20 - 40 - - - - - + + + + 0 + 0 + 485 + 135 + + + @@ -420,6 +538,14 @@ SOME SPACE + + + 0 + 0 + 100 + 30 + + -- 2.20.1