From 6b9943447a27f09265289bc6562a37d81c863bfd Mon Sep 17 00:00:00 2001 From: Henrique Santiago Date: Tue, 5 Jun 2012 16:16:57 -0300 Subject: [PATCH] protocol login at lua --- modules/client_entergame/entergame.otmod | 1 + modules/client_entergame/protocollogin.lua | 184 +++++++++++++++++++++ src/framework/luafunctions.cpp | 11 +- src/framework/net/protocol.cpp | 14 ++ src/framework/net/protocol.h | 19 ++- src/otclient/luafunctions.cpp | 7 +- src/otclient/net/protocollogin.cpp | 63 +------ src/otclient/net/protocollogin.h | 4 - 8 files changed, 225 insertions(+), 78 deletions(-) create mode 100644 modules/client_entergame/protocollogin.lua diff --git a/modules/client_entergame/entergame.otmod b/modules/client_entergame/entergame.otmod index e56508b9..b8141fdf 100644 --- a/modules/client_entergame/entergame.otmod +++ b/modules/client_entergame/entergame.otmod @@ -8,6 +8,7 @@ Module - client_topmenu @onLoad: | + dofile 'protocollogin' dofile 'entergame' dofile 'characterlist' EnterGame.init() diff --git a/modules/client_entergame/protocollogin.lua b/modules/client_entergame/protocollogin.lua new file mode 100644 index 00000000..8f937a03 --- /dev/null +++ b/modules/client_entergame/protocollogin.lua @@ -0,0 +1,184 @@ +ProtocolLogin = extends(Protocol) + +function ProtocolLogin.create() + local protocolLogin = ProtocolLogin.internalCreate() + return protocolLogin +end + +LoginServerError = 10 +LoginServerMotd = 20 +LoginServerUpdateNeeded = 30 +LoginServerCharacterList = 100 + +GameExtendedOpcode = 0 +GameProtocolChecksum = 1 +GameAccountNames = 2 +GameChallangeOnLogin = 3 +GameStackposOnTileAddThing = 4 +GamePenalityOnDeath = 5 +GameNameOnNpcTrade = 6 +GameDoubleFreeCapacity = 7 +GameDoubleExperience = 8 +GameTotalCapacity = 9 +GameSkillsBase = 10 +GameAdditionalPlayerStats = 11 +GameIdOnCancelAttack = 12 +GameChannelPlayerList = 13 +GamePlayerMounts = 14 +GameEnvironmentEffect = 15 +GameCreatureType = 16 +GameCreatureAdditionalInfo = 17 +GameCreaturePassableInfo = 18 +GameItemAnimationPhase = 19 +GameTrucatedPingOpcode = 20 +GameReverseCreatureStack = 21 + +RSA = "109120132967399429278860960508995541528237502902798129123468757937266291492576446330739696001110603907230888610072655818825358503429057592827629436413108566029093628212635953836686562675849720620786279431090218017681061521755056710823876476444260558147179707119674283982419152118103759076030616683978566631413" + +function ProtocolLogin:parseError(msg) + local errorMessage = msg:getString() + signalcall(self.onError, self, errorMessage, false) +end + +function ProtocolLogin:parseMotd(msg) + local motd = msg:getString() + signalcall(self.onMotd, self, motd) +end + +function ProtocolLogin:parseCharacterList(msg) + local characters = {} + local charactersCount = msg:getU8() + for i=1,charactersCount do + local character = {} + character[1] = msg:getString() + character[2] = msg:getString() + character[3] = iptostring(msg:getU32()) + character[4] = msg:getU16() + characters[i] = character + end + local premDays = msg:getU16() + signalcall(self.onCharacterList, self, characters, premDays) +end + +function ProtocolLogin:onOpcode(opcode, msg) + if opcode == LoginServerError then + self:parseError(msg) + elseif opcode == LoginServerMotd then + self:parseMotd(msg) + elseif opcode == LoginServerUpdateNeeded then + return false + elseif opcode == LoginServerCharacterList then + self:parseCharacterList(msg) + else + return false + end + return true +end + +function ProtocolLogin:sendLoginPacket() + local msg = OutputMessage.create() + msg:addU8(1) -- ClientEnterAccount + msg:addU16(1) -- ClientOs + msg:addU16(g_game.getClientVersion()) + + msg:addU32(g_thingsType.getSignature()) + msg:addU32(g_sprites.getSignature()) + msg:addU32(0) -- pic sig + + local paddingBytes = 128 + msg:addU8(0) -- first RSA byte must be 0 + paddingBytes = paddingBytes - 1 + + -- xtea key + self:generateXteaKey() + local xteaKey = self:getXteaKey() + msg:addU32(xteaKey[1]) + msg:addU32(xteaKey[2]) + msg:addU32(xteaKey[3]) + msg:addU32(xteaKey[4]) + paddingBytes = paddingBytes - 16 + + if g_game.getFeature(GameProtocolChecksum) then + self:enableChecksum() + end + + if g_game.getFeature(GameAccountNames) then + msg:addString(self.accountName) + msg:addString(self.accountPassword) + paddingBytes = paddingBytes - (4 + string.len(self.accountName) + string.len(self.accountPassword)) + else + msg:addU32(tonumber(self.accountName)) + msg:addString(self.accountPassword) + paddingBytes = paddingBytes - (6 + string.len(self.accountPassword)) + end + + msg:addPaddingBytes(paddingBytes) -- this crashes without 0 + msg:encryptRSA(128, RSA) + + self:send(msg) + self:enableChecksum() + self:recv() +end + +-- void ProtocolLogin::sendLoginPacket() +-- { +-- OutputMessagePtr msg(new OutputMessage); + +-- msg->addU8(Proto::ClientEnterAccount); +-- msg->addU16(Proto::ClientOs); +-- msg->addU16(Proto::ClientVersion); + +-- msg->addU32(g_thingsType.getSignature()); // data signature +-- msg->addU32(g_sprites.getSignature()); // sprite signature +-- msg->addU32(Proto::PicSignature); // pic signature + +-- int paddingBytes = 128; +-- msg->addU8(0); // first RSA byte must be 0 +-- paddingBytes -= 1; + +-- // xtea key +-- generateXteaKey(); + +-- msg->addU32(m_xteaKey[0]); +-- msg->addU32(m_xteaKey[1]); +-- msg->addU32(m_xteaKey[2]); +-- msg->addU32(m_xteaKey[3]); +-- paddingBytes -= 16; + +-- if(g_game.getFeature(Otc::GameProtocolChecksum)) +-- enableChecksum(); + +-- if(g_game.getFeature(Otc::GameAccountNames)) { +-- msg->addString(m_accountName); +-- msg->addString(m_accountPassword); +-- paddingBytes -= 4 + m_accountName.length() + m_accountPassword.length(); +-- } else { +-- msg->addU32(stdext::from_string(m_accountName)); +-- msg->addString(m_accountPassword); +-- paddingBytes -= 6 + m_accountPassword.length(); +-- } + +-- msg->addPaddingBytes(paddingBytes); // complete the 128 bytes for rsa encryption with zeros +-- msg->encryptRSA(128, Proto::RSA); + +-- send(msg); +-- enableXteaEncryption(); +-- recv(); +-- } + +-- events +function ProtocolLogin:onConnect() + self:sendLoginPacket() +end + +-- public functions +function ProtocolLogin:login(host, port, accountName, accountPassword) + if string.len(accountName) == 0 or string.len(accountPassword) == 0 then + signalcall(self.onError, self, "You must enter an account name and password.", false) + end + + self.accountName = accountName + self.accountPassword = accountPassword + + self:connect(host, port) +end diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp index 31fc715e..bbdf1143 100644 --- a/src/framework/luafunctions.cpp +++ b/src/framework/luafunctions.cpp @@ -46,6 +46,7 @@ void Application::registerLuaFunctions() g_lua.bindGlobalFunction("pointtostring", [](const Point& v) { return stdext::to_string(v); }); g_lua.bindGlobalFunction("colortostring", [](const Color& v) { return stdext::to_string(v); }); g_lua.bindGlobalFunction("sizetostring", [](const Size& v) { return stdext::to_string(v); }); + g_lua.bindGlobalFunction("iptostring", [](int v) { return stdext::ip_to_string(v); }); g_lua.registerStaticClass("g_crypt"); g_lua.bindClassStaticFunction("g_crypt", "encrypt", Crypt::encrypt); @@ -397,11 +398,17 @@ void Application::registerLuaFunctions() // Protocol g_lua.registerClass(); - //g_lua.bindClassMemberFunction("connect", &Protocol::connect); + g_lua.bindClassStaticFunction("create", []{ return ProtocolPtr(new Protocol); }); + g_lua.bindClassMemberFunction("connect", &Protocol::connect); g_lua.bindClassMemberFunction("disconnect", &Protocol::disconnect); g_lua.bindClassMemberFunction("isConnected", &Protocol::isConnected); g_lua.bindClassMemberFunction("isConnecting", &Protocol::isConnecting); - g_lua.bindClassMemberFunction("send", &Protocol::send); + g_lua.bindClassMemberFunction("send", &Protocol::send); // must change to safeSend + g_lua.bindClassMemberFunction("recv", &Protocol::recv); + g_lua.bindClassMemberFunction("getXteaKey", &Protocol::getXteaKey); + g_lua.bindClassMemberFunction("generateXteaKey", &Protocol::generateXteaKey); + g_lua.bindClassMemberFunction("enableXteaEncryption", &Protocol::enableXteaEncryption); + g_lua.bindClassMemberFunction("enableChecksum", &Protocol::enableChecksum); // Module g_lua.registerClass(); diff --git a/src/framework/net/protocol.cpp b/src/framework/net/protocol.cpp index 8f07216c..8b8f0f86 100644 --- a/src/framework/net/protocol.cpp +++ b/src/framework/net/protocol.cpp @@ -151,6 +151,15 @@ void Protocol::generateXteaKey() m_xteaKey[3] = unif(eng); } +std::vector Protocol::getXteaKey() +{ + std::vector xteaKey; + xteaKey.resize(4); + for(int i = 0; i < 4; ++i) + xteaKey[i] = m_xteaKey[i]; + return xteaKey; +} + bool Protocol::xteaDecrypt(const InputMessagePtr& inputMessage) { uint16 encryptedSize = inputMessage->getUnreadSize(); @@ -215,3 +224,8 @@ void Protocol::xteaEncrypt(const OutputMessagePtr& outputMessage) readPos = readPos + 2; } } + +void Protocol::onConnect() +{ + callLuaField("onConnect"); +} diff --git a/src/framework/net/protocol.h b/src/framework/net/protocol.h index 2ffd249b..89baa1b0 100644 --- a/src/framework/net/protocol.h +++ b/src/framework/net/protocol.h @@ -41,20 +41,21 @@ public: bool isConnected(); bool isConnecting(); - virtual void send(const OutputMessagePtr& outputMessage); + void generateXteaKey(); + std::vector getXteaKey(); + void enableXteaEncryption() { m_xteaEncryptionEnabled = true; } - ProtocolPtr asProtocol() { return std::static_pointer_cast(shared_from_this()); } + void enableChecksum() { m_checksumEnabled = true; } -protected: + virtual void send(const OutputMessagePtr& outputMessage); void recv(); - virtual void onConnect() = 0; - virtual void onRecv(const InputMessagePtr& inputMessage) = 0; - virtual void onError(const boost::system::error_code& err) = 0; + ProtocolPtr asProtocol() { return std::static_pointer_cast(shared_from_this()); } - void enableChecksum() { m_checksumEnabled = true; } - void enableXteaEncryption() { m_xteaEncryptionEnabled = true; } - void generateXteaKey(); +protected: + virtual void onConnect(); + virtual void onRecv(const InputMessagePtr& inputMessage) {} + virtual void onError(const boost::system::error_code& err) {} uint32 m_xteaKey[4]; diff --git a/src/otclient/luafunctions.cpp b/src/otclient/luafunctions.cpp index 4505a37d..1dbe9b74 100644 --- a/src/otclient/luafunctions.cpp +++ b/src/otclient/luafunctions.cpp @@ -167,14 +167,11 @@ void OTClient::registerLuaFunctions() g_lua.bindClassStaticFunction("g_game", "getCharacterName", std::bind(&Game::getCharacterName, &g_game)); g_lua.bindClassStaticFunction("g_game", "getWorldName", std::bind(&Game::getWorldName, &g_game)); g_lua.bindClassStaticFunction("g_game", "getGMActions", std::bind(&Game::getGMActions, &g_game)); + g_lua.bindClassStaticFunction("g_game", "getClientVersion", std::bind(&Game::getClientVersion, &g_game)); + g_lua.bindClassStaticFunction("g_game", "getFeature", std::bind(&Game::getFeature, &g_game, std::placeholders::_1)); g_lua.bindGlobalFunction("getOufitColor", Outfit::getColor); - g_lua.registerClass(); - g_lua.bindClassStaticFunction("create", &ProtocolLogin::create); - g_lua.bindClassMemberFunction("login", &ProtocolLogin::login); - g_lua.bindClassMemberFunction("cancelLogin", &ProtocolLogin::cancelLogin); - g_lua.registerClass(); g_lua.bindClassStaticFunction("create", []{ return ProtocolGamePtr(new ProtocolGame); }); g_lua.bindClassMemberFunction("login", &ProtocolGame::login); diff --git a/src/otclient/net/protocollogin.cpp b/src/otclient/net/protocollogin.cpp index 5fc973f9..387fd959 100644 --- a/src/otclient/net/protocollogin.cpp +++ b/src/otclient/net/protocollogin.cpp @@ -28,42 +28,20 @@ #include #include -void ProtocolLogin::login(const std::string& host, int port, const std::string& accountName, const std::string& accountPassword) -{ - if(accountName.empty() || accountPassword.empty()) { - callLuaField("onError", "You must enter an account name and password."); - return; - } - - m_accountName = accountName; - m_accountPassword = accountPassword; - - connect(host, port); -} - -void ProtocolLogin::onConnect() -{ - sendLoginPacket(); -} - void ProtocolLogin::onRecv(const InputMessagePtr& msg) { try { while(!msg->eof()) { int opcode = msg->getU8(); + + // try to parse in lua first + if(callLuaField("onOpcode", opcode, msg)) + continue; + switch(opcode) { - case Proto::LoginServerError: - parseError(msg); - break; - case Proto::LoginServerMotd: - parseMOTD(msg); - break; case Proto::LoginServerUpdateNeeded: callLuaField("onError", "Client needs update."); break; - case Proto::LoginServerCharacterList: - parseCharacterList(msg); - break; default: stdext::throw_exception(stdext::format("unknown opcode %d", opcode)); break; @@ -126,34 +104,3 @@ void ProtocolLogin::sendLoginPacket() enableXteaEncryption(); recv(); } - -void ProtocolLogin::parseError(const InputMessagePtr& msg) -{ - std::string error = msg->getString(); - callLuaField("onError", error, false); -} - -void ProtocolLogin::parseMOTD(const InputMessagePtr& msg) -{ - std::string motd = msg->getString(); - callLuaField("onMotd", motd); -} - -void ProtocolLogin::parseCharacterList(const InputMessagePtr& msg) -{ - typedef std::tuple CharacterInfo; - typedef std::vector CharaterList; - CharaterList charList; - - int numCharacters = msg->getU8(); - for(int i = 0; i < numCharacters; ++i) { - std::string name = msg->getString(); - std::string world = msg->getString(); - uint32 ip = msg->getU32(); - uint16 port = msg->getU16(); - charList.push_back(CharacterInfo(name, world, stdext::ip_to_string(ip), port)); - } - int premDays = msg->getU16(); - - callLuaField("onCharacterList", charList, premDays); -} diff --git a/src/otclient/net/protocollogin.h b/src/otclient/net/protocollogin.h index 9d1320df..72049dc2 100644 --- a/src/otclient/net/protocollogin.h +++ b/src/otclient/net/protocollogin.h @@ -46,10 +46,6 @@ public: private: void sendLoginPacket(); - void parseError(const InputMessagePtr& inputMessage); - void parseMOTD(const InputMessagePtr& inputMessage); - void parseCharacterList(const InputMessagePtr& inputMessage); - std::string m_accountName, m_accountPassword; };