This reintroduces and improves SSL support, and comes complete with new shiny dialogs.
setProgressMaximum(-1); // disable
setState(Disconnected);
emit connectionMsg(tr("Disconnected from core."));
+ emit encrypted(false);
+}
+
+bool CoreConnection::isEncrypted() const {
+#ifndef HAVE_SSL
+ return false;
+#else
+ QSslSocket *sock = qobject_cast<QSslSocket *>(_socket);
+ return isConnected() && sock && sock->isEncrypted();
+#endif
}
void CoreConnection::socketStateChanged(QAbstractSocket::SocketState socketState) {
}
}
-void CoreConnection::setWarningsHandler(const char *slot) {
- resetWarningsHandler();
- connect(this, SIGNAL(handleIgnoreWarnings(bool)), this, slot);
-}
-
-void CoreConnection::resetWarningsHandler() {
- disconnect(this, SIGNAL(handleIgnoreWarnings(bool)), this, 0);
-}
-
void CoreConnection::coreSocketError(QAbstractSocket::SocketError) {
qDebug() << "coreSocketError" << _socket << _socket->errorString();
emit connectionError(_socket->errorString());
return;
}
+ CoreAccountSettings s;
+
Q_ASSERT(!_socket);
#ifdef HAVE_SSL
QSslSocket *sock = new QSslSocket(Client::instance());
+ // make sure the warning is shown if we happen to connect without SSL support later
+ s.setAccountValue("ShowNoClientSslWarning", true);
#else
if(_account.useSsl()) {
- emit connectionError(tr("<b>This client is built without SSL Support!</b><br />Disable the usage of SSL in the account settings."));
- return;
+ if(s.accountValue("ShowNoClientSslWarning", true).toBool()) {
+ bool accepted = false;
+ emit handleNoSslInClient(&accepted);
+ if(!accepted) {
+ emit connectionError(tr("Unencrypted connection canceled"));
+ return;
+ }
+ s.setAccountValue("ShowNoClientSslWarning", false);
+ }
}
QTcpSocket *sock = new QTcpSocket(Client::instance());
#endif
#endif
_coreMsgBuffer = msg;
+
#ifdef HAVE_SSL
+ CoreAccountSettings s;
if(currentAccount().useSsl()) {
if(msg["SupportSsl"].toBool()) {
+ // Make sure the warning is shown next time we don't have SSL in the core
+ s.setAccountValue("ShowNoCoreSslWarning", true);
+
QSslSocket *sslSocket = qobject_cast<QSslSocket *>(_socket);
Q_ASSERT(sslSocket);
- connect(sslSocket, SIGNAL(encrypted()), this, SLOT(sslSocketEncrypted()));
- connect(sslSocket, SIGNAL(sslErrors(const QList<QSslError> &)), this, SLOT(sslErrors(const QList<QSslError> &)));
-
+ connect(sslSocket, SIGNAL(encrypted()), SLOT(sslSocketEncrypted()));
+ connect(sslSocket, SIGNAL(sslErrors(const QList<QSslError> &)), SLOT(sslErrors()));
sslSocket->startClientEncryption();
} 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."));
- disconnectFromCore();
+ if(s.accountValue("ShowNoCoreSslWarning", true).toBool()) {
+ bool accepted = false;
+ emit handleNoSslInCore(&accepted);
+ if(!accepted) {
+ emit connectionError(tr("Unencrypted connection canceled"));
+ disconnectFromCore();
+ return;
+ }
+ s.setAccountValue("ShowNoCoreSslWarning", false);
+ s.setAccountValue("SslCert", QString());
+ }
+ connectionReady();
}
return;
}
#endif
// if we use SSL we wait for the next step until every SSL warning has been cleared
connectionReady();
+}
+#ifdef HAVE_SSL
+
+void CoreConnection::sslSocketEncrypted() {
+ QSslSocket *socket = qobject_cast<QSslSocket *>(sender());
+ Q_ASSERT(socket);
+
+ if(!socket->sslErrors().count()) {
+ // Cert is valid, so we don't want to store it as known
+ // That way, a warning will appear in case it becomes invalid at some point
+ CoreAccountSettings s;
+ s.setAccountValue("SSLCert", QString());
+ }
+
+ emit encrypted(true);
+ connectionReady();
+}
+
+void CoreConnection::sslErrors() {
+ QSslSocket *socket = qobject_cast<QSslSocket *>(sender());
+ Q_ASSERT(socket);
+
+ CoreAccountSettings s;
+ QByteArray knownDigest = s.accountValue("SslCert").toByteArray();
+
+ if(knownDigest != socket->peerCertificate().digest()) {
+ bool accepted = false;
+ bool permanently = false;
+ emit handleSslErrors(socket, &accepted, &permanently);
+
+ if(!accepted) {
+ emit connectionError(tr("Unencrypted connection canceled"));
+ disconnectFromCore();
+ return;
+ }
+
+ if(permanently)
+ s.setAccountValue("SslCert", socket->peerCertificate().digest());
+ else
+ s.setAccountValue("SslCert", QString());
+ }
+
+ socket->ignoreSslErrors();
}
+#endif /* HAVE_SSL */
+
void CoreConnection::connectionReady() {
if(!_coreMsgBuffer["Configured"].toBool()) {
// start wizard
loginToCore();
}
_coreMsgBuffer.clear();
- resetWarningsHandler();
}
void CoreConnection::loginToCore(const QString &prevError) {
inline bool isConnected() const;
inline CoreAccount currentAccount() const;
+ bool isEncrypted() const;
+
inline int progressMinimum() const;
inline int progressMaximum() const;
inline int progressValue() const;
inline QString progressText() const;
+#ifdef HAVE_SSL
+ inline const QSslSocket *sslSocket() const;
+#endif
+
public slots:
bool connectToCore(AccountId = 0);
void reconnectToCore();
void disconnectFromCore();
-// void useInternalCore();
-
signals:
void stateChanged(CoreConnection::ConnectionState);
+ void encrypted(bool isEncrypted = true);
void synchronized();
void connectionError(const QString &errorMsg);
void startInternalCore();
void connectToInternalCore(SignalProxy *proxy);
- // This signal MUST be handled synchronously!
+ // These signals MUST be handled synchronously!
void userAuthenticationRequired(CoreAccount *, bool *valid, const QString &errorMessage = QString());
-
- void handleIgnoreWarnings(bool permanently);
+ void handleNoSslInClient(bool *accepted);
+ void handleNoSslInCore(bool *accepted);
+#ifdef HAVE_SSL
+ void handleSslErrors(const QSslSocket *socket, bool *accepted, bool *permanently);
+#endif
private slots:
void connectToCurrentAccount();
void internalSessionStateReceived(const QVariant &packedState);
void sessionStateReceived(const QVariantMap &state);
- void setWarningsHandler(const char *slot);
- void resetWarningsHandler();
void resetConnection();
void connectionReady();
//void doCoreSetup(const QVariant &setupData);
void setState(QAbstractSocket::SocketState socketState);
void setState(ConnectionState state);
+#ifdef HAVE_SSL
+ void sslSocketEncrypted();
+ void sslErrors();
+#endif
+
private:
CoreAccountModel *_model;
CoreAccount _account;
CoreAccount CoreConnection::currentAccount() const { return _account; }
CoreAccountModel *CoreConnection::accountModel() const { return _model; }
+#ifdef HAVE_SSL
+const QSslSocket *CoreConnection::sslSocket() const { return qobject_cast<QSslSocket *>(_socket); }
+#endif
+
#endif
# include "knotificationbackend.h"
#endif /* HAVE_KDE */
+#ifdef HAVE_SSL
+# include "sslinfodlg.h"
+#endif
+
#ifdef HAVE_INDICATEQT
#include "indicatornotificationbackend.h"
#endif
connect(GraphicalUi::contextMenuActionProvider(), SIGNAL(showChannelList(NetworkId)), SLOT(showChannelList(NetworkId)));
connect(GraphicalUi::contextMenuActionProvider(), SIGNAL(showIgnoreList(QString)), SLOT(showIgnoreList(QString)));
connect(Client::coreConnection(), SIGNAL(userAuthenticationRequired(CoreAccount *, bool *, QString)), SLOT(userAuthenticationRequired(CoreAccount *, bool *, QString)));
+ connect(Client::coreConnection(), SIGNAL(handleNoSslInClient(bool*)), SLOT(handleNoSslInClient(bool *)));
+ connect(Client::coreConnection(), SIGNAL(handleNoSslInCore(bool*)), SLOT(handleNoSslInCore(bool *)));
+#ifdef HAVE_SSL
+ connect(Client::coreConnection(), SIGNAL(handleSslErrors(const QSslSocket *, bool *, bool *)), SLOT(handleSslErrors(const QSslSocket *, bool *, bool *)));
+#endif
// Setup Dock Areas
setDockNestingEnabled(true);
}
+void MainWin::userAuthenticationRequired(CoreAccount *account, bool *valid, const QString &errorMessage) {
+ Q_UNUSED(errorMessage)
+ CoreConnectAuthDlg dlg(account, this);
+ *valid = (dlg.exec() == QDialog::Accepted);
+}
+
+void MainWin::handleNoSslInClient(bool *accepted) {
+ QMessageBox box(QMessageBox::Warning, tr("Unencrypted Connection"), tr("<b>Your client does not support SSL encryption</b>"),
+ QMessageBox::Ignore|QMessageBox::Cancel, this);
+ box.setInformativeText(tr("Sensitive data, like passwords, will be transmitted unencrypted to your Quassel core."));
+ box.setDefaultButton(QMessageBox::Ignore);
+ *accepted = box.exec() == QMessageBox::Ignore;
+}
+
+void MainWin::handleNoSslInCore(bool *accepted) {
+ QMessageBox box(QMessageBox::Warning, tr("Unencrypted Connection"), tr("<b>Your core does not support SSL encryption</b>"),
+ QMessageBox::Ignore|QMessageBox::Cancel, this);
+ box.setInformativeText(tr("Sensitive data, like passwords, will be transmitted unencrypted to your Quassel core."));
+ box.setDefaultButton(QMessageBox::Ignore);
+ *accepted = box.exec() == QMessageBox::Ignore;
+
+}
+
+#ifdef HAVE_SSL
+
+void MainWin::handleSslErrors(const QSslSocket *socket, bool *accepted, bool *permanently) {
+ QString errorString = "<ul>";
+ foreach(const QSslError error, socket->sslErrors())
+ errorString += QString("<li>%1</li>").arg(error.errorString());
+ errorString += "</ul>";
+
+ QMessageBox box(QMessageBox::Warning,
+ tr("Untrusted Security Certificate"),
+ tr("<b>The SSL certificate provided by the core at %1 is untrusted for the following reasons:</b>").arg(socket->peerName()),
+ QMessageBox::Cancel, this);
+ box.setInformativeText(errorString);
+ box.addButton(tr("Continue"), QMessageBox::AcceptRole);
+ box.setDefaultButton(box.addButton(tr("Show Certificate"), QMessageBox::HelpRole));
+
+ QMessageBox::ButtonRole role;
+ do {
+ box.exec();
+ role = box.buttonRole(box.clickedButton());
+ if(role == QMessageBox::HelpRole) {
+ SslInfoDlg dlg(socket, this);
+ dlg.exec();
+ }
+ } while(role == QMessageBox::HelpRole);
+
+ *accepted = role == QMessageBox::AcceptRole;
+ if(*accepted) {
+ QMessageBox box2(QMessageBox::Warning,
+ tr("Untrusted Security Certificate"),
+ tr("Would you like to accept this certificate forever without being prompted?"),
+ 0, this);
+ box2.setDefaultButton(box2.addButton(tr("Current Session Only"), QMessageBox::NoRole));
+ box2.addButton(tr("Forever"), QMessageBox::YesRole);
+ box2.exec();
+ *permanently = box2.buttonRole(box2.clickedButton()) == QMessageBox::YesRole;
+ }
+}
+
+#endif /* HAVE_SSL */
+
void MainWin::showCoreConnectionDlg() {
CoreConnectDlg dlg(this);
if(dlg.exec() == QDialog::Accepted) {
}
}
-void MainWin::userAuthenticationRequired(CoreAccount *account, bool *valid, const QString &errorMessage) {
- Q_UNUSED(errorMessage)
- CoreConnectAuthDlg dlg(account, this);
- *valid = (dlg.exec() == QDialog::Accepted);
-}
-
void MainWin::showChannelList(NetworkId netId) {
ChannelListDlg *channelListDlg = new ChannelListDlg();
void messagesInserted(const QModelIndex &parent, int start, int end);
void showAboutDlg();
void showChannelList(NetworkId netId = NetworkId());
- void startInternalCore();
- void userAuthenticationRequired(CoreAccount *, bool *valid, const QString &errorMessage);
void showCoreConnectionDlg();
void showCoreInfoDlg();
void showAwayLog();
#ifdef HAVE_KDE
void showShortcutsDlg();
#endif
+ void startInternalCore();
+ void userAuthenticationRequired(CoreAccount *, bool *valid, const QString &errorMessage);
+ void handleNoSslInClient(bool *accepted);
+ void handleNoSslInCore(bool *accepted);
+#ifdef HAVE_SSL
+ void handleSslErrors(const QSslSocket *socket, bool *accepted, bool *permanently);
+#endif
+
void on_actionConfigureNetworks_triggered();
void on_actionConfigureViews_triggered();
void on_actionLockLayout_toggled(bool lock);