uisupport: Provide helpers for dealing with widget changes
[quassel.git] / src / core / coreauthhandler.cpp
index 4bd3628..ade356e 100644 (file)
@@ -1,5 +1,5 @@
 /***************************************************************************
- *   Copyright (C) 2005-2016 by the Quassel Project                        *
+ *   Copyright (C) 2005-2018 by the Quassel Project                        *
  *   devel@quassel-irc.org                                                 *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 #endif
 
 #include "core.h"
-#include "logger.h"
+#include "logmessage.h"
 
 using namespace Protocol;
 
 CoreAuthHandler::CoreAuthHandler(QTcpSocket *socket, QObject *parent)
     : AuthHandler(parent),
-    _peer(0),
+    _peer(nullptr),
     _magicReceived(false),
     _legacy(false),
     _clientRegistered(false),
     _connectionFeatures(0)
 {
     setSocket(socket);
-    connect(socket, SIGNAL(readyRead()), SLOT(onReadyRead()));
+    connect(socket, &QIODevice::readyRead, this, &CoreAuthHandler::onReadyRead);
 
     // TODO: Timeout for the handshake phase
 
@@ -64,7 +64,7 @@ void CoreAuthHandler::onReadyRead()
             qDebug() << "Legacy client detected, switching to compatibility mode";
             _legacy = true;
             RemotePeer *peer = PeerFactory::createPeer(PeerFactory::ProtoDescriptor(Protocol::LegacyProtocol, 0), this, socket(), Compressor::NoCompression, this);
-            connect(peer, SIGNAL(protocolVersionMismatch(int,int)), SLOT(onProtocolVersionMismatch(int,int)));
+            connect(peer, &RemotePeer::protocolVersionMismatch, this, &CoreAuthHandler::onProtocolVersionMismatch);
             setPeer(peer);
             return;
         }
@@ -86,8 +86,8 @@ void CoreAuthHandler::onReadyRead()
         socket()->read((char*)&data, 4);
         data = qFromBigEndian<quint32>(data);
 
-        Protocol::Type type = static_cast<Protocol::Type>(data & 0xff);
-        quint16 protoFeatures = static_cast<quint16>(data>>8 & 0xffff);
+        auto type = static_cast<Protocol::Type>(data & 0xff);
+        auto protoFeatures = static_cast<quint16>(data>>8 & 0xffff);
         _supportedProtos.append(PeerFactory::ProtoDescriptor(type, protoFeatures));
 
         if (data >= 0x80000000) { // last protocol
@@ -106,7 +106,7 @@ void CoreAuthHandler::onReadyRead()
 
             if (peer->protocol() == Protocol::LegacyProtocol) {
                 _legacy = true;
-                connect(peer, SIGNAL(protocolVersionMismatch(int,int)), SLOT(onProtocolVersionMismatch(int,int)));
+                connect(peer, &RemotePeer::protocolVersionMismatch, this, &CoreAuthHandler::onProtocolVersionMismatch);
             }
             setPeer(peer);
 
@@ -129,7 +129,7 @@ void CoreAuthHandler::setPeer(RemotePeer *peer)
     qDebug().nospace() << "Using " << qPrintable(peer->protocolName()) << "...";
 
     _peer = peer;
-    disconnect(socket(), SIGNAL(readyRead()), this, SLOT(onReadyRead()));
+    disconnect(socket(), &QIODevice::readyRead, this, &CoreAuthHandler::onReadyRead);
 }
 
 // only in compat mode
@@ -171,24 +171,23 @@ void CoreAuthHandler::handle(const RegisterClient &msg)
         return;
     }
 
+    _peer->setFeatures(std::move(msg.features));
+    _peer->setBuildDate(msg.buildDate);
+    _peer->setClientVersion(msg.clientVersion);
+
     QVariantList backends;
+    QVariantList authenticators;
     bool configured = Core::isConfigured();
-    if (!configured)
+    if (!configured) {
         backends = Core::backendInfo();
+        if (_peer->hasFeature(Quassel::Feature::Authenticators)) {
+            authenticators = Core::authenticatorInfo();
+        }
+    }
 
-    int uptime = Core::instance()->startTime().secsTo(QDateTime::currentDateTime().toUTC());
-    int updays = uptime / 86400; uptime %= 86400;
-    int uphours = uptime / 3600; uptime %= 3600;
-    int upmins = uptime / 60;
-    QString coreInfo = tr("<b>Quassel Core Version %1</b><br>"
-                          "Built: %2<br>"
-                          "Up %3d%4h%5m (since %6)").arg(Quassel::buildInfo().fancyVersionString)
-                          .arg(Quassel::buildInfo().buildDate)
-                          .arg(updays).arg(uphours, 2, 10, QChar('0')).arg(upmins, 2, 10, QChar('0')).arg(Core::instance()->startTime().toString(Qt::TextDate));
-
-    // useSsl and coreInfo are only used for the legacy protocol
-    _peer->dispatch(ClientRegistered(Quassel::features(), configured, backends, useSsl, coreInfo));
+    _peer->dispatch(ClientRegistered(Quassel::Features{}, configured, backends, authenticators, useSsl));
 
+    // useSsl is only used for the legacy protocol
     if (_legacy && useSsl)
         startSsl();
 
@@ -201,7 +200,15 @@ void CoreAuthHandler::handle(const SetupData &msg)
     if (!checkClientRegistered())
         return;
 
-    QString result = Core::setup(msg.adminUser, msg.adminPassword, msg.backend, msg.setupData);
+    // The default parameter to authenticator is Database.
+    // Maybe this should be hardcoded elsewhere, i.e. as a define.
+    QString authenticator = msg.authenticator;
+    quInfo() << "[" << authenticator << "]";
+    if (authenticator.trimmed().isEmpty()) {
+        authenticator = QString("Database");
+    }
+
+    QString result = Core::setup(msg.adminUser, msg.adminPassword, msg.backend, msg.setupData, authenticator, msg.authSetupData);
     if (!result.isEmpty())
         _peer->dispatch(SetupFailed(result));
     else
@@ -214,7 +221,19 @@ void CoreAuthHandler::handle(const Login &msg)
     if (!checkClientRegistered())
         return;
 
+    if (!Core::isConfigured()) {
+        qWarning() << qPrintable(tr("Client")) << qPrintable(socket()->peerAddress().toString()) << qPrintable(tr("attempted to login before the core was configured, rejecting."));
+        _peer->dispatch(ClientDenied(tr("<b>Attempted to login before core was configured!</b><br>The core must be configured before attempting to login.")));
+        return;
+    }
+
+    // First attempt local auth using the real username and password.
+    // If that fails, move onto the auth provider.
     UserId uid = Core::validateUser(msg.user, msg.password);
+    if (uid == 0) {
+        uid = Core::authenticateUser(msg.user, msg.password);
+    }
+
     if (uid == 0) {
         quInfo() << qPrintable(tr("Invalid login attempt from %1 as \"%2\"").arg(socket()->peerAddress().toString(), msg.user));
         _peer->dispatch(LoginFailed(tr("<b>Invalid username or password!</b><br>The username/password combination you supplied could not be found in the database.")));
@@ -224,9 +243,22 @@ void CoreAuthHandler::handle(const Login &msg)
 
     quInfo() << qPrintable(tr("Client %1 initialized and authenticated successfully as \"%2\" (UserId: %3).").arg(socket()->peerAddress().toString(), msg.user, QString::number(uid.toInt())));
 
-    disconnect(socket(), 0, this, 0);
-    disconnect(_peer, 0, this, 0);
-    _peer->setParent(0); // Core needs to take care of this one now!
+    const auto &clientFeatures = _peer->features();
+    auto unsupported = clientFeatures.toStringList(false);
+    if (!unsupported.isEmpty()) {
+        if (unsupported.contains("NoFeatures"))
+            quInfo() << qPrintable(tr("Client does not support extended features."));
+        else
+            quInfo() << qPrintable(tr("Client does not support the following features: %1").arg(unsupported.join(", ")));
+    }
+
+    if (!clientFeatures.unknownFeatures().isEmpty()) {
+        quInfo() << qPrintable(tr("Client supports unknown features: %1").arg(clientFeatures.unknownFeatures().join(", ")));
+    }
+
+    disconnect(socket(), nullptr, this, nullptr);
+    disconnect(_peer, nullptr, this, nullptr);
+    _peer->setParent(nullptr); // Core needs to take care of this one now!
 
     socket()->flush(); // Make sure all data is sent before handing over the peer (and socket) to the session thread (bug 682)
     emit handshakeComplete(_peer, uid);
@@ -238,11 +270,11 @@ void CoreAuthHandler::handle(const Login &msg)
 void CoreAuthHandler::startSsl()
 {
     #ifdef HAVE_SSL
-    QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket());
+    auto *sslSocket = qobject_cast<QSslSocket *>(socket());
     Q_ASSERT(sslSocket);
 
     qDebug() << qPrintable(tr("Starting encryption for Client:"))  << _peer->description();
-    connect(sslSocket, SIGNAL(sslErrors(const QList<QSslError> &)), SLOT(onSslErrors()));
+    connect(sslSocket, selectOverload<const QList<QSslError> &>(&QSslSocket::sslErrors), this, &CoreAuthHandler::onSslErrors);
     sslSocket->flush(); // ensure that the write cache is flushed before we switch to ssl (bug 682)
     sslSocket->startServerEncryption();
     #endif /* HAVE_SSL */
@@ -252,7 +284,7 @@ void CoreAuthHandler::startSsl()
 #ifdef HAVE_SSL
 void CoreAuthHandler::onSslErrors()
 {
-    QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket());
+    auto *sslSocket = qobject_cast<QSslSocket *>(socket());
     Q_ASSERT(sslSocket);
     sslSocket->ignoreSslErrors();
 }