Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add: GMCP authenticate spec implementation (#7152)
<!-- Keep the title short & concise so anyone non-technical can understand it, the title appears in PTB changelogs --> #### Brief overview of PR changes/additions Add the GMCP authenticate spec and client credentials: https://wiki.mudlet.org/w/Standards:GMCP_Authentication #### Motivation for adding to Mudlet To solve the issues we have in trying to login to games - not every game accepts "character\npassword" kind of login - while not getting into a security quagmire that comes with exposing passwords to the Lua subsystem. #### Other info (issues closed, discussion etc) --------- Co-authored-by: Vadim Peretokin <vadim.peretokin@carasent.com> Co-authored-by: Marco Fontani <mf@marcofontani.it> Co-authored-by: Stephen Lyons <slysven@virginmedia.com>
- Loading branch information
1 parent
598ec5a
commit 0ac53a3
Showing
8 changed files
with
246 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
/*************************************************************************** | ||
* Copyright (C) 2024 by Vadim Peretokin - vperetokin@gmail.com * | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
* This program is distributed in the hope that it will be useful, * | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
* GNU General Public License for more details. * | ||
* * | ||
* You should have received a copy of the GNU General Public License * | ||
* along with this program; if not, write to the * | ||
* Free Software Foundation, Inc., * | ||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | ||
***************************************************************************/ | ||
|
||
#include "GMCPAuthenticator.h" | ||
|
||
#include "Host.h" | ||
#include "ctelnet.h" | ||
#include <QDebug> | ||
|
||
GMCPAuthenticator::GMCPAuthenticator(Host* pHost) | ||
: mpHost(pHost) | ||
{} | ||
|
||
void GMCPAuthenticator::saveSupportsSet(const QString& data) | ||
{ | ||
auto jsonDoc = QJsonDocument::fromJson(data.toUtf8()); | ||
auto jsonObj = jsonDoc.object(); | ||
|
||
if (jsonObj.contains("type")) { | ||
QJsonArray typesArray = jsonObj["type"].toArray(); | ||
for (const auto& type : typesArray) { | ||
mSupportedAuthTypes.append(type.toString()); | ||
} | ||
} | ||
|
||
#if defined(DEBUG_GMCP_AUTHENTICATION) | ||
qDebug() << "Supported auth types:" << mSupportedAuthTypes; | ||
#endif | ||
} | ||
|
||
void GMCPAuthenticator::sendCredentials() | ||
{ | ||
auto character = mpHost->getLogin(); | ||
auto password = mpHost->getPass(); | ||
QJsonObject credentials; | ||
if (!character.isEmpty() && !password.isEmpty()) { | ||
credentials["account"] = character; | ||
credentials["password"] = password; | ||
} | ||
QJsonDocument doc(credentials); | ||
QString gmcpMessage = doc.toJson(QJsonDocument::Compact); | ||
|
||
std::string output; | ||
output += TN_IAC; | ||
output += TN_SB; | ||
output += OPT_GMCP; | ||
output += "Char.Login.Credentials "; | ||
output += mpHost->mTelnet.encodeAndCookBytes(gmcpMessage.toStdString()); | ||
output += TN_IAC; | ||
output += TN_SE; | ||
|
||
// Send credentials to server | ||
mpHost->mTelnet.socketOutRaw(output); | ||
#if defined(DEBUG_GMCP_AUTHENTICATION) | ||
qDebug() << "Sent GMCP credentials"; | ||
#endif | ||
} | ||
|
||
|
||
void GMCPAuthenticator::handleAuthResult(const QString& data) | ||
{ | ||
auto doc = QJsonDocument::fromJson(data.toUtf8()); | ||
auto obj = doc.object(); | ||
|
||
// some game drivers can parse JSON for true or false, but may not be able to write booleans back | ||
auto result = obj[qsl("success")]; | ||
bool success = (result.isBool() && result.toBool()) || (result.isString() && result.toString() == "true"); | ||
auto message = obj[qsl("message")].toString(); | ||
|
||
if (success) { | ||
#if defined(DEBUG_GMCP_AUTHENTICATION) | ||
qDebug() << "GMCP login successful"; | ||
#endif | ||
} else { | ||
#if defined(DEBUG_GMCP_AUTHENTICATION) | ||
qDebug() << "GMCP login failed:" << message; | ||
#endif | ||
mpHost->mTelnet.setDontReconnect(true); | ||
if (message.isEmpty()) { | ||
mpHost->postMessage(tr("[ WARN ] - Could not log in to the game, is the login information correct?")); | ||
} else { | ||
mpHost->postMessage(tr("[ WARN ] - Could not log in to the game: %1").arg(message)); | ||
} | ||
|
||
} | ||
} | ||
|
||
// controller for GMCP authentication | ||
void GMCPAuthenticator::handleAuthGMCP(const QString& packageMessage, const QString& data) | ||
{ | ||
if (packageMessage == qsl("Char.Login.Default")) { | ||
saveSupportsSet(data); | ||
|
||
if (mSupportedAuthTypes.contains(qsl("password-credentials"))) { | ||
mpHost->mTelnet.cancelLoginTimers(); | ||
sendCredentials(); | ||
} else { | ||
#if defined(DEBUG_GMCP_AUTHENTICATION) | ||
qDebug() << "Server does not support credentials authentication and we don't support any other"; | ||
#endif | ||
} | ||
return; | ||
} | ||
|
||
if (packageMessage == qsl("Char.Login.Result")) { | ||
handleAuthResult(data); | ||
return; | ||
} | ||
|
||
#if defined(DEBUG_GMCP_AUTHENTICATION) | ||
qDebug() << "Unknown GMCP auth package:" << packageMessage; | ||
#endif | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#ifndef MUDLET_AUTHENTICATOR_H | ||
#define MUDLET_AUTHENTICATOR_H | ||
|
||
/*************************************************************************** | ||
* Copyright (C) 2024 by Vadim Peretokin - vperetokin@gmail.com * | ||
* * | ||
* This program is free software; you can redistribute it and/or modify * | ||
* it under the terms of the GNU General Public License as published by * | ||
* the Free Software Foundation; either version 2 of the License, or * | ||
* (at your option) any later version. * | ||
* * | ||
* This program is distributed in the hope that it will be useful, * | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of * | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | ||
* GNU General Public License for more details. * | ||
* * | ||
* You should have received a copy of the GNU General Public License * | ||
* along with this program; if not, write to the * | ||
* Free Software Foundation, Inc., * | ||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * | ||
***************************************************************************/ | ||
|
||
#include "Host.h" | ||
#include "utils.h" | ||
|
||
#include "pre_guard.h" | ||
#include <QJsonArray> | ||
#include <QJsonDocument> | ||
#include <QJsonObject> | ||
#include <QString> | ||
#include <QVariantMap> | ||
#include "post_guard.h" | ||
|
||
|
||
class GMCPAuthenticator | ||
{ | ||
Q_DECLARE_TR_FUNCTIONS(GMCPAuthenticator) | ||
|
||
public: | ||
|
||
explicit GMCPAuthenticator(Host* pHost); | ||
~GMCPAuthenticator() = default; | ||
|
||
void saveSupportsSet(const QString& data); | ||
void sendCredentials(); | ||
void handleAuthResult(const QString& data); | ||
void handleAuthGMCP(const QString& packageMessage, const QString& data); | ||
|
||
private: | ||
Host* mpHost; | ||
QStringList mSupportedAuthTypes; | ||
}; | ||
|
||
#endif // MUDLET_AUTHENTICATOR_H |
Oops, something went wrong.