diff -r a2d09a597fbb -r fb7a9b0119d3 qmlfrontend/net_session.cpp --- a/qmlfrontend/net_session.cpp Wed May 29 01:05:20 2019 +0200 +++ b/qmlfrontend/net_session.cpp Thu May 30 18:31:02 2019 +0200 @@ -1,12 +1,15 @@ #include "net_session.h" +#include + #include "players_model.h" #include "rooms_model.h" NetSession::NetSession(QObject *parent) : QObject(parent), m_playersModel(new PlayersListModel()), - m_roomsModel(new RoomsListModel()) {} + m_roomsModel(new RoomsListModel()), + m_sessionState(NotConnected) {} NetSession::~NetSession() { close(); } @@ -33,14 +36,14 @@ QString NetSession::nickname() const { return m_nickname; } -QString NetSession::password() const { return m_password; } - NetSession::SessionState NetSession::sessionState() const { return m_sessionState; } QString NetSession::room() const { return m_room; } +QString NetSession::passwordHash() const { return m_passwordHash; } + void NetSession::setUrl(const QUrl &url) { if (m_url == url) return; @@ -55,11 +58,13 @@ emit nicknameChanged(m_nickname); } -void NetSession::setPassword(const QString &password) { - if (m_password == password) return; +void NetSession::setPasswordHash(const QString &passwordHash) { + if (m_passwordHash == passwordHash) return; - m_password = password; - emit passwordChanged(m_password); + m_passwordHash = passwordHash; + emit passwordHashChanged(m_passwordHash); + + if (m_sessionState == Authentication) sendPassword(); } void NetSession::setRoom(const QString &room) { @@ -174,7 +179,23 @@ void NetSession::handleAddTeam(const QStringList ¶meters) {} -void NetSession::handleAskPassword(const QStringList ¶meters) {} +void NetSession::handleAskPassword(const QStringList ¶meters) { + if (parameters.length() != 1 || parameters[0].length() < 16) { + qWarning("Bad ASKPASSWORD message"); + return; + } + + setSessionState(Authentication); + + m_serverSalt = parameters[0]; + m_clientSalt = QUuid::createUuid().toString(); + + if (m_passwordHash.isEmpty()) { + emit passwordAsked(); + } else { + sendPassword(); + } +} void NetSession::handleBanList(const QStringList ¶meters) {} @@ -306,6 +327,37 @@ m_socket->write(message.join('\n').toUtf8() + "\n\n"); } +void NetSession::sendPassword() { + /* When we got password hash, and server asked us for a password, perform + * mutual authentication: at this point we have salt chosen by server. Client + * sends client salt and hash of secret (password hash) salted with client + * salt, server salt, and static salt (predefined string + protocol number). + * Server should respond with hash of the same set in different order. + */ + + if (m_passwordHash.isEmpty() || m_serverSalt.isEmpty()) return; + + QString hash = + QCryptographicHash::hash(m_clientSalt.toLatin1() + .append(m_serverSalt.toLatin1()) + .append(m_passwordHash) + .append(QByteArray::number(cProtocolVersion)) + .append("!hedgewars"), + QCryptographicHash::Sha1) + .toHex(); + + m_serverHash = + QCryptographicHash::hash(m_serverSalt.toLatin1() + .append(m_clientSalt.toLatin1()) + .append(m_passwordHash) + .append(QByteArray::number(cProtocolVersion)) + .append("!hedgewars"), + QCryptographicHash::Sha1) + .toHex(); + + send("PASSWORD", QStringList{hash, m_clientSalt}); +} + void NetSession::setSessionState(NetSession::SessionState sessionState) { if (m_sessionState == sessionState) return;