From a1145aced4971e3c09b7c3aac1f0625c1b07aa9c Mon Sep 17 00:00:00 2001 From: dongresource Date: Sat, 31 Oct 2020 21:31:25 +0100 Subject: [PATCH] Chat strings are now sanitized. * Only plain, printable ASCII is allowed for now. * Local chat is now printed to the server console, but group chat is still private * Added a helper function to print character names and IDs --- src/ChatManager.cpp | 35 ++++++++++++++++++++++++++++++++--- src/ChatManager.hpp | 2 ++ src/GroupManager.cpp | 12 ++++++++++-- src/NanoManager.cpp | 8 ++++---- src/PlayerManager.cpp | 17 +++++++++++++++-- src/PlayerManager.hpp | 1 + 6 files changed, 64 insertions(+), 11 deletions(-) diff --git a/src/ChatManager.cpp b/src/ChatManager.cpp index 03ba987..5731939 100644 --- a/src/ChatManager.cpp +++ b/src/ChatManager.cpp @@ -474,7 +474,9 @@ void ChatManager::chatHandler(CNSocket* sock, CNPacketData* data) { sP_CL2FE_REQ_SEND_FREECHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_FREECHAT_MESSAGE*)data->buf; Player* plr = PlayerManager::getPlayer(sock); - std::string fullChat = U16toU8(chat->szFreeChat); + std::string fullChat = sanitizeText(U16toU8(chat->szFreeChat)); + + std::cout << "[FreeChat] " << PlayerManager::getPlayerName(plr, false) << ": " << fullChat << std::endl; if (fullChat.length() > 1 && fullChat[0] == CMD_PREFIX) { // PREFIX runCmd(fullChat, sock); @@ -483,9 +485,11 @@ void ChatManager::chatHandler(CNSocket* sock, CNPacketData* data) { // send to client INITSTRUCT(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, resp); - memcpy(resp.szFreeChat, chat->szFreeChat, sizeof(chat->szFreeChat)); + + U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat)); resp.iPC_ID = plr->iID; resp.iEmoteCode = chat->iEmoteCode; + sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_FREECHAT_MESSAGE_SUCC)); // send to visible players @@ -495,13 +499,21 @@ void ChatManager::chatHandler(CNSocket* sock, CNPacketData* data) { void ChatManager::menuChatHandler(CNSocket* sock, CNPacketData* data) { if (data->size != sizeof(sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE)) return; // malformed packet + sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE* chat = (sP_CL2FE_REQ_SEND_MENUCHAT_MESSAGE*)data->buf; + Player *plr = PlayerManager::getPlayer(sock); + + std::string fullChat = sanitizeText(U16toU8(chat->szFreeChat)); + + std::cout << "[MenuChat] " << PlayerManager::getPlayerName(plr, false) << ": " << fullChat << std::endl; // send to client INITSTRUCT(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, resp); - memcpy(resp.szFreeChat, chat->szFreeChat, sizeof(chat->szFreeChat)); + + U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat)); resp.iPC_ID = PlayerManager::players[sock].plr->iID; resp.iEmoteCode = chat->iEmoteCode; + sock->sendPacket((void*)&resp, P_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_MENUCHAT_MESSAGE_SUCC)); // send to visible players @@ -537,3 +549,20 @@ void ChatManager::sendServerMessage(CNSocket* sock, std::string msg) { // send the packet :) sock->sendPacket((void*)&motd, P_FE2CL_PC_MOTD_LOGIN, sizeof(sP_FE2CL_PC_MOTD_LOGIN)); } + +// we only allow plain ascii, at least for now +std::string ChatManager::sanitizeText(std::string text) { + int i; + char buf[128]; + + i = 0; + for (char c : text) { + if (i >= 127) + break; + if (c >= ' ' && c <= '~') + buf[i++] = c; + } + buf[i] = 0; + + return std::string(buf); +} diff --git a/src/ChatManager.hpp b/src/ChatManager.hpp index 10a169c..5917b16 100644 --- a/src/ChatManager.hpp +++ b/src/ChatManager.hpp @@ -26,4 +26,6 @@ namespace ChatManager { void emoteHandler(CNSocket* sock, CNPacketData* data); void menuChatHandler(CNSocket* sock, CNPacketData* data); void sendServerMessage(CNSocket* sock, std::string msg); // uses MOTD + + std::string sanitizeText(std::string text); } diff --git a/src/GroupManager.cpp b/src/GroupManager.cpp index b06b88b..9be39c7 100644 --- a/src/GroupManager.cpp +++ b/src/GroupManager.cpp @@ -171,14 +171,18 @@ void GroupManager::chatGroup(CNSocket* sock, CNPacketData* data) { Player* plr = PlayerManager::getPlayer(sock); Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup); + std::string fullChat = ChatManager::sanitizeText(U16toU8(chat->szFreeChat)); + if (plr == nullptr || otherPlr == nullptr) return; // send to client INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, resp); - memcpy(resp.szFreeChat, chat->szFreeChat, sizeof(chat->szFreeChat)); + + U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat)); resp.iSendPCID = plr->iID; resp.iEmoteCode = chat->iEmoteCode; + sendToGroup(otherPlr, (void*)&resp, P_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_ALL_GROUP_FREECHAT_MESSAGE_SUCC)); } @@ -190,14 +194,18 @@ void GroupManager::menuChatGroup(CNSocket* sock, CNPacketData* data) { Player* plr = PlayerManager::getPlayer(sock); Player* otherPlr = PlayerManager::getPlayerFromID(plr->iIDGroup); + std::string fullChat = ChatManager::sanitizeText(U16toU8(chat->szFreeChat)); + if (plr == nullptr || otherPlr == nullptr) return; // send to client INITSTRUCT(sP_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC, resp); - memcpy(resp.szFreeChat, chat->szFreeChat, sizeof(chat->szFreeChat)); + + U8toU16(fullChat, (char16_t*)&resp.szFreeChat, sizeof(resp.szFreeChat)); resp.iSendPCID = plr->iID; resp.iEmoteCode = chat->iEmoteCode; + sendToGroup(otherPlr, (void*)&resp, P_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC, sizeof(sP_FE2CL_REP_SEND_ALL_GROUP_MENUCHAT_MESSAGE_SUCC)); } diff --git a/src/NanoManager.cpp b/src/NanoManager.cpp index 2cd4472..72d1a40 100644 --- a/src/NanoManager.cpp +++ b/src/NanoManager.cpp @@ -124,7 +124,7 @@ void NanoManager::nanoGMGiveHandler(CNSocket* sock, CNPacketData* data) { addNano(sock, nano->iNanoID, 0); DEBUGLOG( - std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " requested to add nano id: " << nano->iNanoID << std::endl; + std::cout << PlayerManager::getPlayerName(plr) << " requested to add nano id: " << nano->iNanoID << std::endl; ) } @@ -142,7 +142,7 @@ void NanoManager::nanoSummonHandler(CNSocket* sock, CNPacketData* data) { // Send to client DEBUGLOG( - std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " requested to summon nano slot: " << pkt->iNanoSlotNum << std::endl; + std::cout << PlayerManager::getPlayerName(plr) << " requested to summon nano slot: " << pkt->iNanoSlotNum << std::endl; ) } @@ -156,7 +156,7 @@ void NanoManager::nanoSkillUseHandler(CNSocket* sock, CNPacketData* data) { int16_t skillId = plr->Nanos[nanoId].iSkillID; DEBUGLOG( - std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " requested to summon nano skill " << std::endl; + std::cout << PlayerManager::getPlayerName(plr) << " requested to summon nano skill " << std::endl; ) for (auto& pwr : ActivePowers) @@ -418,7 +418,7 @@ void NanoManager::setNanoSkill(CNSocket* sock, sP_CL2FE_REQ_NANO_TUNE* skill) { sock->sendPacket((void*)&resp, P_FE2CL_REP_NANO_TUNE_SUCC, sizeof(sP_FE2CL_REP_NANO_TUNE_SUCC)); DEBUGLOG( - std::cout << U16toU8(plr->PCStyle.szFirstName) << U16toU8(plr->PCStyle.szLastName) << " set skill id " << skill->iTuneID << " for nano: " << skill->iNanoID << std::endl; + std::cout << PlayerManager::getPlayerName(plr) << " set skill id " << skill->iTuneID << " for nano: " << skill->iNanoID << std::endl; ) } diff --git a/src/PlayerManager.cpp b/src/PlayerManager.cpp index 80e9a06..46f6ccf 100644 --- a/src/PlayerManager.cpp +++ b/src/PlayerManager.cpp @@ -58,7 +58,7 @@ void PlayerManager::addPlayer(CNSocket* key, Player plr) { key->plr = p; - std::cout << U16toU8(plr.PCStyle.szFirstName) << " " << U16toU8(plr.PCStyle.szLastName) << " has joined!" << std::endl; + std::cout << getPlayerName(p) << " has joined!" << std::endl; std::cout << players.size() << " players" << std::endl; } @@ -78,7 +78,7 @@ void PlayerManager::removePlayer(CNSocket* key) { if (ChunkManager::chunks.find(view.chunkPos) != ChunkManager::chunks.end()) ChunkManager::chunks[view.chunkPos]->players.erase(key); - std::cout << U16toU8(view.plr->PCStyle.szFirstName) << " " << U16toU8(view.plr->PCStyle.szLastName) << " (PlayerId = " << view.plr->iID << ") has left!" << std::endl; + std::cout << getPlayerName(key->plr) << " has left!" << std::endl; key->plr = nullptr; delete view.plr; @@ -945,6 +945,19 @@ Player *PlayerManager::getPlayer(CNSocket* key) { return nullptr; } +std::string PlayerManager::getPlayerName(Player *plr, bool id) { + // the print in CNShardServer can print packets from players that haven't yet joined + if (plr == nullptr) + return "NOT IN GAME"; + + std::string ret = U16toU8(plr->PCStyle.szFirstName) + " " + U16toU8(plr->PCStyle.szLastName); + + if (id) + ret += " [" + std::to_string(plr->iID) + "]"; + + return ret; +} + WarpLocation PlayerManager::getRespawnPoint(Player *plr) { WarpLocation best; uint32_t curDist, bestDist = UINT32_MAX; diff --git a/src/PlayerManager.hpp b/src/PlayerManager.hpp index 70f1731..6214988 100644 --- a/src/PlayerManager.hpp +++ b/src/PlayerManager.hpp @@ -64,6 +64,7 @@ namespace PlayerManager { void exitPlayerVehicle(CNSocket* sock, CNPacketData* data); Player *getPlayer(CNSocket* key); + std::string getPlayerName(Player *plr, bool id=true); WarpLocation getRespawnPoint(Player *plr); bool isAccountInUse(int accountId);