diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c8dee0b2e0d..4b99993225f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -67,8 +67,8 @@ set(mudlet_SRCS dlgConnectionProfiles.cpp dlgIRC.cpp dlgKeysMainArea.cpp - dlgMapper.cpp dlgMapLabel.cpp + dlgMapper.cpp dlgModuleManager.cpp dlgNotepad.cpp dlgPackageExporter.cpp @@ -87,10 +87,10 @@ set(mudlet_SRCS dlgVarsMainArea.cpp EAction.cpp exitstreewidget.cpp - FontManager.cpp FileOpenHandler.cpp + FontManager.cpp GifTracker.cpp - TrailingWhitespaceMarker.cpp + GMCPAuthenticator.cpp Host.cpp HostManager.cpp ircmessageformatter.cpp @@ -100,8 +100,9 @@ set(mudlet_SRCS mapInfoContributorManager.cpp mudlet.cpp MudletInstanceCoordinator.cpp - ShortcutsManager.cpp + MxpTag.cpp ScriptUnit.cpp + ShortcutsManager.cpp T2DMap.cpp TAccessibleTextEdit.cpp TAction.cpp @@ -121,7 +122,6 @@ set(mudlet_SRCS TimerUnit.cpp TKey.cpp TLabel.cpp - TScrollBox.cpp TLinkStore.cpp TLuaInterpreter.cpp @@ -142,26 +142,30 @@ set(mudlet_SRCS TMxpBRTagHandler.cpp TMxpColorTagHandler.cpp TMxpCustomElementTagHandler.cpp + TMxpElementDefinitionHandler.cpp + TMxpElementRegistry.cpp TMxpEntityTagHandler.cpp TMxpFontTagHandler.cpp + TMxpFormattingTagsHandler.cpp TMxpLinkTagHandler.cpp + TMxpMudlet.cpp TMxpMusicTagHandler.cpp TMxpNodeBuilder.cpp - TMxpMudlet.cpp TMxpProcessor.cpp TMxpSendTagHandler.cpp TMxpSoundTagHandler.cpp TMxpSupportTagHandler.cpp - MxpTag.cpp TMxpTagHandler.cpp TMxpTagParser.cpp TMxpTagProcessor.cpp TMxpVarTagHandler.cpp TMxpVersionTagHandler.cpp + TrailingWhitespaceMarker.cpp TriggerUnit.cpp TRoom.cpp TRoomDB.cpp TScript.cpp + TScrollBox.cpp TSplitter.cpp TSplitterHandle.cpp TStringUtils.cpp @@ -218,9 +222,9 @@ set(mudlet_UIS set(mudlet_HDRS ActionUnit.h - Announcer.h AliasUnit.h AltFocusMenuBarDisable.h + Announcer.h ctelnet.h DarkTheme.h discord.h @@ -255,7 +259,7 @@ set(mudlet_HDRS FileOpenHandler.h FontManager.h GifTracker.h - TrailingWhitespaceMarker.h + GMCPAuthenticator.h Host.h HostManager.h ircmessageformatter.h @@ -264,10 +268,11 @@ set(mudlet_HDRS mapInfoContributorManager.h mudlet.h MudletInstanceCoordinator.h + MxpTag.h post_guard.h pre_guard.h - ShortcutsManager.h ScriptUnit.h + ShortcutsManager.h T2DMap.h TAccessibleConsole.h TAccessibleTextEdit.h @@ -286,12 +291,11 @@ set(mudlet_HDRS TEntityResolver.h testdbg.h TEvent.h - TForkedProcess.h TFlipButton.h + TForkedProcess.h TimerUnit.h TKey.h TLabel.h - TScrollBox.h TLinkStore.h TLuaInterpreter.h TMainConsole.h @@ -302,32 +306,33 @@ set(mudlet_HDRS TMxpBRTagHandler.h TMxpClient.h TMxpColorTagHandler.h + TMxpContext.h TMxpCustomElementTagHandler.h - TMxpEntityTagHandler.h - TMxpFontTagHandler.h - TMxpLinkTagHandler.h - TMxpMusicTagHandler.h - TMxpSoundTagHandler.h TMxpElementDefinitionHandler.h TMxpElementRegistry.h - TMxpContext.h + TMxpEntityTagHandler.h + TMxpFontTagHandler.h TMxpFormattingTagsHandler.h + TMxpLinkTagHandler.h TMxpMudlet.h + TMxpMusicTagHandler.h TMxpNodeBuilder.h TMxpProcessor.h TMxpSendTagHandler.h - MxpTag.h + TMxpSoundTagHandler.h + TMxpSupportTagHandler.cpp TMxpTagHandler.h TMxpTagParser.h TMxpTagProcessor.h - TMxpSupportTagHandler.cpp TMxpVarTagHandler.h TMxpVersionTagHandler.h + TrailingWhitespaceMarker.h Tree.h TriggerUnit.h TRoom.h TRoomDB.h TScript.h + TScrollBox.h TSplitter.h TSplitterHandle.h TStringUtils.h @@ -339,8 +344,8 @@ set(mudlet_HDRS TTreeWidget.h TTrigger.h TVar.h - VarUnit.h utils.h + VarUnit.h widechar_width.h XMLexport.h XMLimport.h) diff --git a/src/GMCPAuthenticator.cpp b/src/GMCPAuthenticator.cpp new file mode 100644 index 00000000000..6e2f7d3da1c --- /dev/null +++ b/src/GMCPAuthenticator.cpp @@ -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 + +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 +} diff --git a/src/GMCPAuthenticator.h b/src/GMCPAuthenticator.h new file mode 100644 index 00000000000..65e87398d2b --- /dev/null +++ b/src/GMCPAuthenticator.h @@ -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 +#include +#include +#include +#include +#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 diff --git a/src/Host.cpp b/src/Host.cpp index 7790fdafe38..1c8a1ea1275 100644 --- a/src/Host.cpp +++ b/src/Host.cpp @@ -25,16 +25,24 @@ #include "Host.h" - +#include "dlgIRC.h" +#include "dlgMapper.h" +#include "dlgModuleManager.h" +#include "dlgNotepad.h" +#include "dlgPackageManager.h" +#include "dlgProfilePreferences.h" +#include "GifTracker.h" +#include "GMCPAuthenticator.h" #include "LuaInterface.h" +#include "mudlet.h" +#include "TCommandLine.h" #include "TConsole.h" #include "TDebug.h" -#include "TMainConsole.h" -#include "TCommandLine.h" #include "TDebug.h" #include "TDockWidget.h" #include "TEvent.h" #include "TLabel.h" +#include "TMainConsole.h" #include "TMap.h" #include "TMedia.h" #include "TRoomDB.h" @@ -42,15 +50,7 @@ #include "TTextEdit.h" #include "TToolBar.h" #include "VarUnit.h" -#include "GifTracker.h" #include "XMLimport.h" -#include "dlgMapper.h" -#include "dlgModuleManager.h" -#include "dlgNotepad.h" -#include "dlgPackageManager.h" -#include "dlgProfilePreferences.h" -#include "dlgIRC.h" -#include "mudlet.h" #include "pre_guard.h" #include @@ -242,6 +242,7 @@ Host::Host(int port, const QString& hostname, const QString& login, const QStrin , mpEditorDialog(nullptr) , mpMap(new TMap(this, hostname)) , mpMedia(new TMedia(this, hostname)) +, mpAuth(new GMCPAuthenticator(this)) , mpNotePad(nullptr) , mPrintCommand(true) , mIsRemoteEchoingActive(false) diff --git a/src/Host.h b/src/Host.h index ed68a20ffc5..cd909cea9a4 100644 --- a/src/Host.h +++ b/src/Host.h @@ -63,6 +63,7 @@ class TEvent; class TArea; class LuaInterface; class TMedia; +class GMCPAuthenticator; class TRoom; class TConsole; class TMainConsole; @@ -72,6 +73,7 @@ class dlgIRC; class dlgPackageManager; class dlgModuleManager; class dlgProfilePreferences; +class cTelnet; class stopWatch { friend class XMLimport; @@ -484,6 +486,7 @@ class Host : public QObject dlgTriggerEditor* mpEditorDialog; QScopedPointer mpMap; QScopedPointer mpMedia; + QScopedPointer mpAuth; dlgNotepad* mpNotePad; // This is set when we want commands we typed to be shown on the main diff --git a/src/ctelnet.cpp b/src/ctelnet.cpp index 129cd3472a6..d785d0e6c8f 100644 --- a/src/ctelnet.cpp +++ b/src/ctelnet.cpp @@ -37,6 +37,7 @@ #include "TMainConsole.h" #include "TMap.h" #include "TMedia.h" +#include "GMCPAuthenticator.h" #include "TTextCodec.h" #include "dlgComposer.h" #include "dlgMapper.h" @@ -185,6 +186,17 @@ cTelnet::~cTelnet() socket.deleteLater(); } +void cTelnet::cancelLoginTimers() +{ + if (mTimerLogin) { + mTimerLogin->stop(); + } + + if (mTimerPass) { + mTimerPass->stop(); + } +} + // This configures two out of three of the QTextCodec used by this profile: // 1) A single or multi-byte encoder for all outgoing data // 2) A single or multi-byte encoder for incoming OutOfBand data @@ -1774,7 +1786,7 @@ void cTelnet::processTelnetCommand(const std::string& telnetCommand) output = TN_IAC; output += TN_SB; output += OPT_GMCP; - output += R"(Core.Supports.Set [ "Char 1", "Char.Skills 1", "Char.Items 1", "Room 1", "IRE.Rift 1", "IRE.Composer 1", "External.Discord 1", "Client.Media 1"])"; + output += R"(Core.Supports.Set [ "Char 1", "Char.Skills 1", "Char.Items 1", "Room 1", "IRE.Rift 1", "IRE.Composer 1", "External.Discord 1", "Client.Media 1", "Char.Login 1"])"; output += TN_IAC; output += TN_SE; socketOutRaw(output); @@ -2829,6 +2841,10 @@ void cTelnet::setGMCPVariables(const QByteArray& msg) mpHost->mpMedia->parseGMCP(packageMessage, data); } + if (packageMessage.startsWith(qsl("Char.Login"), Qt::CaseInsensitive)) { + mpHost->mpAuth->handleAuthGMCP(packageMessage, data); + } + mpHost->mLuaInterpreter.setGMCPTable(packageMessage, data); } diff --git a/src/ctelnet.h b/src/ctelnet.h index 69d22456668..399f48a151d 100644 --- a/src/ctelnet.h +++ b/src/ctelnet.h @@ -194,6 +194,7 @@ class cTelnet : public QObject void setAutoReconnect(bool status); void encodingChanged(const QByteArray&); void set_USE_IRE_DRIVER_BUGFIX(bool b) { mUSE_IRE_DRIVER_BUGFIX = b; } + void setDontReconnect(bool b) { mDontReconnect = b; } void recordReplay(); bool loadReplay(const QString&, QString* pErrMsg = nullptr); void loadReplayChunk(); @@ -227,6 +228,7 @@ class cTelnet : public QObject void setPostingTimeout(const int); int getPostingTimeout() const { return mTimeOut; } void loopbackTest(QByteArray& data) { processSocketData(data.data(), data.size(), true); } + void cancelLoginTimers(); QMap supportedTelnetOptions; @@ -275,6 +277,7 @@ public slots: void initStreamDecompressor(); int decompressBuffer(char*& in_buffer, int& length, char* out_buffer); void reset(); + void sendLoginAndPass(); QByteArray prepareNewEnvironData(const QString&); QString getNewEnvironValueUser(); diff --git a/src/mudlet.pro b/src/mudlet.pro index 25de9c05ff3..86c51cb1c23 100644 --- a/src/mudlet.pro +++ b/src/mudlet.pro @@ -623,6 +623,7 @@ SOURCES += \ FontManager.cpp \ FileOpenHandler.cpp \ GifTracker.cpp \ + GMCPAuthenticator.cpp \ TrailingWhitespaceMarker.cpp \ Host.cpp \ HostManager.cpp \ @@ -749,6 +750,7 @@ HEADERS += \ exitstreewidget.h \ FileOpenHandler.h \ GifTracker.h \ + GMCPAuthenticator.h \ TrailingWhitespaceMarker.h \ Host.h \ HostManager.h \