Abstract away the protocol handshake code
[quassel.git] / src / core / coreauthhandler.cpp
1 /***************************************************************************
2  *   Copyright (C) 2005-2013 by the Quassel Project                        *
3  *   devel@quassel-irc.org                                                 *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) version 3.                                           *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
19  ***************************************************************************/
20
21 #include "coreauthhandler.h"
22
23 #ifdef HAVE_SSL
24 #  include <QSslSocket>
25 #endif
26
27 #include "core.h"
28 #include "logger.h"
29
30 #include "protocols/legacy/legacypeer.h"
31
32 using namespace Protocol;
33
34 CoreAuthHandler::CoreAuthHandler(QTcpSocket *socket, QObject *parent)
35     : AuthHandler(parent)
36     , _peer(0)
37     , _clientRegistered(false)
38 {
39     setSocket(socket);
40
41     // TODO: protocol detection
42
43     // FIXME: make sure _peer gets deleted
44     // TODO: socket ownership goes to the peer! (-> use shared ptr later...)
45     _peer = new LegacyPeer(this, socket, this);
46     // only in compat mode
47     connect(_peer, SIGNAL(protocolVersionMismatch(int,int)), SLOT(onProtocolVersionMismatch(int,int)));
48 }
49
50
51 // only in compat mode
52 void CoreAuthHandler::onProtocolVersionMismatch(int actual, int expected)
53 {
54     qWarning() << qPrintable(tr("Client")) << _peer->description() << qPrintable(tr("too old, rejecting."));
55     QString errorString = tr("<b>Your Quassel Client is too old!</b><br>"
56                              "This core needs at least client/core protocol version %1 (got: %2).<br>"
57                              "Please consider upgrading your client.").arg(expected, actual);
58     _peer->dispatch(ClientDenied(errorString));
59     _peer->close();
60 }
61
62
63 void CoreAuthHandler::startSsl()
64 {
65 #ifdef HAVE_SSL
66     QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket());
67     Q_ASSERT(sslSocket);
68
69     qDebug() << qPrintable(tr("Starting encryption for Client:"))  << _peer->description();
70     connect(sslSocket, SIGNAL(sslErrors(const QList<QSslError> &)), SLOT(onSslErrors()));
71     sslSocket->startServerEncryption();
72 #endif
73 }
74
75
76 #ifdef HAVE_SSL
77 void CoreAuthHandler::onSslErrors()
78 {
79     QSslSocket *sslSocket = qobject_cast<QSslSocket *>(socket());
80     Q_ASSERT(sslSocket);
81     sslSocket->ignoreSslErrors();
82 }
83 #endif
84
85
86 bool CoreAuthHandler::checkClientRegistered()
87 {
88     if (!_clientRegistered) {
89         qWarning() << qPrintable(tr("Client")) << qPrintable(socket()->peerAddress().toString()) << qPrintable(tr("did not send an init message before trying to login, rejecting."));
90         _peer->dispatch(ClientDenied(tr("<b>Client not initialized!</b><br>You need to send an init message before trying to login.")));
91         _peer->close();
92         return false;
93     }
94     return true;
95 }
96
97
98 void CoreAuthHandler::handle(const RegisterClient &msg)
99 {
100     // TODO: only in compat mode
101     bool useSsl = false;
102 #ifdef HAVE_SSL
103     if (Core::sslSupported() && msg.sslSupported)
104         useSsl = true;
105 #endif
106     QVariantList backends;
107     bool configured = Core::isConfigured();
108     if (!configured)
109         backends = Core::backendInfo();
110
111     _peer->dispatch(ClientRegistered(Quassel::features(), configured, backends, useSsl, Core::instance()->startTime()));
112     // TODO: only in compat mode
113     if (useSsl)
114         startSsl();
115
116     _clientRegistered = true;
117 }
118
119
120 void CoreAuthHandler::handle(const SetupData &msg)
121 {
122     if (!checkClientRegistered())
123         return;
124
125     QString result = Core::setup(msg.adminUser, msg.adminPassword, msg.backend, msg.setupData);
126     if (!result.isEmpty())
127         _peer->dispatch(SetupFailed(result));
128     else
129         _peer->dispatch(SetupDone());
130 }
131
132
133 void CoreAuthHandler::handle(const Login &msg)
134 {
135     if (!checkClientRegistered())
136         return;
137
138     UserId uid = Core::validateUser(msg.user, msg.password);
139     if (uid == 0) {
140         _peer->dispatch(LoginFailed(tr("<b>Invalid username or password!</b><br>The username/password combination you supplied could not be found in the database.")));
141         return;
142     }
143     _peer->dispatch(LoginSuccess());
144
145     quInfo() << qPrintable(tr("Client %1 initialized and authenticated successfully as \"%2\" (UserId: %3).").arg(socket()->peerAddress().toString(), msg.user, QString::number(uid.toInt())));
146
147     disconnect(socket(), 0, this, 0);
148     disconnect(_peer, 0, this, 0);
149     _peer->setParent(0); // Core needs to take care of this one now!
150
151     emit handshakeComplete(_peer, uid);
152 }