X-Git-Url: https://git.quassel-irc.org/?p=quassel.git;a=blobdiff_plain;f=src%2Fclient%2Fclientauthhandler.cpp;h=2c96a1c9a81ad6da85f9e828644db75d6141b61f;hp=415a7ddbe44010e552210e1ae16608e8da1c05f5;hb=9ddb5712b16b3219338871d346765bc649007de0;hpb=d1bf207d30fe62a15d0e8669d186374c68e6eae8 diff --git a/src/client/clientauthhandler.cpp b/src/client/clientauthhandler.cpp index 415a7ddb..2c96a1c9 100644 --- a/src/client/clientauthhandler.cpp +++ b/src/client/clientauthhandler.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005-2014 by the Quassel Project * + * Copyright (C) 2005-2016 by the Quassel Project * * devel@quassel-irc.org * * * * This program is free software; you can redistribute it and/or modify * @@ -34,7 +34,9 @@ #include "clientsettings.h" #include "peerfactory.h" -#include "protocols/legacy/legacypeer.h" +#if QT_VERSION < 0x050000 +# include "../../3rdparty/sha512/sha512.h" +#endif using namespace Protocol; @@ -73,10 +75,21 @@ void ClientAuthHandler::connectToCore() QTcpSocket *socket = new QTcpSocket(this); #endif -// TODO: Handle system proxy #ifndef QT_NO_NETWORKPROXY - if (_account.useProxy()) { - QNetworkProxy proxy(_account.proxyType(), _account.proxyHostName(), _account.proxyPort(), _account.proxyUser(), _account.proxyPassword()); + QNetworkProxy proxy; + proxy.setType(_account.proxyType()); + if (_account.proxyType() == QNetworkProxy::Socks5Proxy || + _account.proxyType() == QNetworkProxy::HttpProxy) { + proxy.setHostName(_account.proxyHostName()); + proxy.setPort(_account.proxyPort()); + proxy.setUser(_account.proxyUser()); + proxy.setPassword(_account.proxyPassword()); + } + + if (_account.proxyType() == QNetworkProxy::DefaultProxy) { + QNetworkProxyFactory::setUseSystemConfiguration(true); + } else { + QNetworkProxyFactory::setUseSystemConfiguration(false); socket->setProxy(proxy); } #endif @@ -116,7 +129,9 @@ void ClientAuthHandler::onSocketStateChanged(QAbstractSocket::SocketState socket text = tr("Disconnected"); // Ensure the disconnected() signal is sent even if we haven't reached the Connected state yet. // The baseclass implementation will make sure to only send the signal once. - onSocketDisconnected(); + // However, we do want to prefer a potential socket error signal that may be on route already, so + // give this a chance to overtake us by spinning the loop... + QTimer::singleShot(0, this, SLOT(onSocketDisconnected())); } break; default: @@ -169,18 +184,26 @@ void ClientAuthHandler::onSocketConnected() _probing = true; QDataStream stream(socket()); // stream handles the endianness for us + stream.setVersion(QDataStream::Qt_4_2); quint32 magic = Protocol::magic; #ifdef HAVE_SSL if (_account.useSsl()) magic |= Protocol::Encryption; #endif - //magic |= Protocol::Compression; // not implemented yet + magic |= Protocol::Compression; stream << magic; // here goes the list of protocols we support, in order of preference - stream << ((quint32)Protocol::LegacyProtocol | 0x80000000); // end list + PeerFactory::ProtoList protos = PeerFactory::supportedProtocols(); + for (int i = 0; i < protos.count(); ++i) { + quint32 reply = protos[i].first; + reply |= protos[i].second<<8; + if (i == protos.count() - 1) + reply |= 0x80000000; // end list + stream << reply; + } socket()->flush(); // make sure the probing data is sent immediately return; @@ -190,7 +213,7 @@ void ClientAuthHandler::onSocketConnected() qDebug() << "Legacy core detected, switching to compatibility mode"; - RemotePeer *peer = new LegacyPeer(this, socket(), this); + RemotePeer *peer = PeerFactory::createPeer(PeerFactory::ProtoDescriptor(Protocol::LegacyProtocol, 0), this, socket(), Compressor::NoCompression, this); // Only needed for the legacy peer, as all others check the protocol version before instantiation connect(peer, SIGNAL(protocolVersionMismatch(int,int)), SLOT(onProtocolVersionMismatch(int,int))); @@ -217,7 +240,13 @@ void ClientAuthHandler::onReadyRead() quint16 protoFeatures = static_cast(reply>>8 & 0xffff); _connectionFeatures = static_cast(reply>>24); - RemotePeer *peer = PeerFactory::createPeer(PeerFactory::ProtoDescriptor(type, protoFeatures), this, socket(), this); + Compressor::CompressionLevel level; + if (_connectionFeatures & Protocol::Compression) + level = Compressor::BestCompression; + else + level = Compressor::NoCompression; + + RemotePeer *peer = PeerFactory::createPeer(PeerFactory::ProtoDescriptor(type, protoFeatures), this, socket(), level, this); if (!peer) { qWarning() << "No valid protocol supported for this core!"; emit errorPopup(tr("Incompatible Quassel Core!
" @@ -246,6 +275,8 @@ void ClientAuthHandler::onProtocolVersionMismatch(int actual, int expected) void ClientAuthHandler::setPeer(RemotePeer *peer) { + qDebug().nospace() << "Using " << qPrintable(peer->protocolName()) << "..."; + _peer = peer; connect(_peer, SIGNAL(transferProgress(int,int)), SIGNAL(transferProgress(int,int))); @@ -268,7 +299,7 @@ void ClientAuthHandler::startRegistration() useSsl = _account.useSsl(); #endif - _peer->dispatch(RegisterClient(Quassel::buildInfo().fancyVersionString, useSsl)); + _peer->dispatch(RegisterClient(Quassel::buildInfo().fancyVersionString, Quassel::buildInfo().commitDate, useSsl, Quassel::features())); } @@ -283,8 +314,10 @@ void ClientAuthHandler::handle(const ClientRegistered &msg) { _coreConfigured = msg.coreConfigured; _backendInfo = msg.backendInfo; + _authenticatorInfo = msg.authenticatorInfo; - Client::setCoreFeatures(static_cast(msg.coreFeatures)); + Client::setCoreFeatures(Quassel::Features(msg.coreFeatures)); + SignalProxy::current()->sourcePeer()->setFeatures(Quassel::Features(msg.coreFeatures)); // The legacy protocol enables SSL at this point if(_legacy && _account.useSsl()) @@ -301,7 +334,7 @@ void ClientAuthHandler::onConnectionReady() if (!_coreConfigured) { // start wizard - emit startCoreSetup(_backendInfo); + emit startCoreSetup(_backendInfo, _authenticatorInfo); } else // TODO: check if we need LoginEnabled login(); @@ -407,6 +440,7 @@ void ClientAuthHandler::checkAndEnableSsl(bool coreSupportsSsl) } s.setAccountValue("ShowNoCoreSslWarning", false); s.setAccountValue("SslCert", QString()); + s.setAccountValue("SslCertDigestVersion", QVariant(QVariant::Int)); } if (_legacy) onConnectionReady(); @@ -428,6 +462,7 @@ void ClientAuthHandler::onSslSocketEncrypted() // That way, a warning will appear in case it becomes invalid at some point CoreAccountSettings s; s.setAccountValue("SSLCert", QString()); + s.setAccountValue("SslCertDigestVersion", QVariant(QVariant::Int)); } emit encrypted(true); @@ -446,8 +481,27 @@ void ClientAuthHandler::onSslErrors() CoreAccountSettings s; QByteArray knownDigest = s.accountValue("SslCert").toByteArray(); + ClientAuthHandler::DigestVersion knownDigestVersion = static_cast(s.accountValue("SslCertDigestVersion").toInt()); + + QByteArray calculatedDigest; + switch (knownDigestVersion) { + case ClientAuthHandler::DigestVersion::Md5: + calculatedDigest = socket->peerCertificate().digest(QCryptographicHash::Md5); + break; + + case ClientAuthHandler::DigestVersion::Sha2_512: +#if QT_VERSION >= 0x050000 + calculatedDigest = socket->peerCertificate().digest(QCryptographicHash::Sha512); +#else + calculatedDigest = sha2_512(socket->peerCertificate().toDer()); +#endif + break; + + default: + qWarning() << "Certificate digest version" << QString(knownDigestVersion) << "is not supported"; + } - if (knownDigest != socket->peerCertificate().digest()) { + if (knownDigest != calculatedDigest) { bool accepted = false; bool permanently = false; emit handleSslErrors(socket, &accepted, &permanently); @@ -457,13 +511,42 @@ void ClientAuthHandler::onSslErrors() return; } - if (permanently) - s.setAccountValue("SslCert", socket->peerCertificate().digest()); - else + if (permanently) { +#if QT_VERSION >= 0x050000 + s.setAccountValue("SslCert", socket->peerCertificate().digest(QCryptographicHash::Sha512)); +#else + s.setAccountValue("SslCert", sha2_512(socket->peerCertificate().toDer())); +#endif + s.setAccountValue("SslCertDigestVersion", ClientAuthHandler::DigestVersion::Latest); + } + else { s.setAccountValue("SslCert", QString()); + s.setAccountValue("SslCertDigestVersion", QVariant(QVariant::Int)); + } + } + else if (knownDigestVersion != ClientAuthHandler::DigestVersion::Latest) { +#if QT_VERSION >= 0x050000 + s.setAccountValue("SslCert", socket->peerCertificate().digest(QCryptographicHash::Sha512)); +#else + s.setAccountValue("SslCert", sha2_512(socket->peerCertificate().toDer())); +#endif + s.setAccountValue("SslCertDigestVersion", ClientAuthHandler::DigestVersion::Latest); } socket->ignoreSslErrors(); } +#if QT_VERSION < 0x050000 +QByteArray ClientAuthHandler::sha2_512(const QByteArray &input) { + unsigned char output[64]; + sha512((unsigned char*) input.constData(), input.size(), output, false); + // QByteArray::fromRawData() cannot be used here because that constructor + // does not copy "output" and the data is clobbered when the variable goes + // out of scope. + QByteArray result; + result.append((char*) output, 64); + return result; +} +#endif + #endif /* HAVE_SSL */