From 5c18d6c48182db4428af0cf292d824f093233e86 Mon Sep 17 00:00:00 2001 From: Dennis Felsing Date: Wed, 12 Dec 2018 09:59:42 +0100 Subject: [PATCH] Remove /modhelp (fixes #1401) --- CMakeLists.txt | 15 +++--- src/engine/client/client.cpp | 2 +- src/engine/client/client.h | 2 +- src/engine/{shared => client}/http.cpp | 71 ------------------------ src/engine/{shared => client}/http.h | 8 ++- src/engine/client/updater.h | 2 +- src/engine/server/server.cpp | 3 -- src/engine/shared/config_variables.h | 1 - src/engine/shared/json.cpp | 73 +++++++++++++++++++++++++ src/engine/shared/json.h | 7 +++ src/game/server/ddracechat.cpp | 74 -------------------------- src/game/server/ddracechat.h | 2 - src/game/server/gamecontext.cpp | 16 ------ src/game/server/gamecontext.h | 1 - src/game/server/player.cpp | 1 - src/game/server/player.h | 3 -- src/game/server/teehistorian.cpp | 1 + src/game/server/teehistorian.h | 1 - src/game/variables.h | 2 - src/modhelp/server.py | 51 ------------------ src/test/json.cpp | 2 +- 21 files changed, 97 insertions(+), 241 deletions(-) rename src/engine/{shared => client}/http.cpp (86%) rename src/engine/{shared => client}/http.h (92%) create mode 100644 src/engine/shared/json.cpp create mode 100644 src/engine/shared/json.h delete mode 100755 src/modhelp/server.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c396aed4..8a2507788 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -361,8 +361,8 @@ if(WEBSOCKETS) show_dependency_status("Websockets" WEBSOCKETS) endif() -if(NOT(CURL_FOUND)) - message(SEND_ERROR "You must install Curl to compile the DDNet") +if(CLIENT AND NOT(CURL_FOUND)) + message(SEND_ERROR "You must install Curl to compile DDNet") endif() if(NOT(PYTHONINTERP_FOUND)) message(SEND_ERROR "You must install Python to compile DDNet") @@ -632,12 +632,12 @@ set_glob(ENGINE_SHARED GLOB src/engine/shared ghost.cpp ghost.h global_uuid_manager.cpp - http.cpp - http.h huffman.cpp huffman.h jobs.cpp jobs.h + json.cpp + json.h kernel.cpp linereader.cpp linereader.h @@ -725,7 +725,7 @@ set(GAME_GENERATED_SHARED set(DEPS ${DEP_JSON} ${DEP_MD5} ${ZLIB_DEP}) # Libraries -set(LIBS ${CURL_LIBRARIES} ${CRYPTO_LIBRARIES} ${WEBSOCKETS_LIBRARIES} ${ZLIB_LIBRARIES} ${PLATFORM_LIBS}) +set(LIBS ${CRYPTO_LIBRARIES} ${WEBSOCKETS_LIBRARIES} ${ZLIB_LIBRARIES} ${PLATFORM_LIBS}) # Add pthreads (on non-Windows) at the end, so that other libraries can depend # on it. list(APPEND LIBS ${CMAKE_THREAD_LIBS_INIT}) @@ -751,6 +751,8 @@ if(CLIENT) friends.h graphics_threaded.cpp graphics_threaded.h + http.cpp + http.h input.cpp input.h keynames.h @@ -873,6 +875,7 @@ if(CLIENT) # Libraries set(LIBS_CLIENT ${LIBS} + ${CURL_LIBRARIES} ${FREETYPE_LIBRARIES} ${GLEW_LIBRARIES} ${PNGLITE_LIBRARIES} @@ -912,6 +915,7 @@ if(CLIENT) target_link_libraries(${TARGET_CLIENT} ${LIBS_CLIENT}) target_include_directories(${TARGET_CLIENT} PRIVATE + ${CURL_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIRS} ${GLEW_INCLUDE_DIRS} ${OGG_INCLUDE_DIRS} @@ -1554,7 +1558,6 @@ foreach(target ${TARGETS_OWN}) target_include_directories(${target} PRIVATE ${PROJECT_BINARY_DIR}/src) target_include_directories(${target} PRIVATE src) target_compile_definitions(${target} PRIVATE $<$:CONF_DEBUG>) - target_include_directories(${target} PRIVATE ${CURL_INCLUDE_DIRS}) target_include_directories(${target} PRIVATE ${ZLIB_INCLUDE_DIRS}) target_compile_definitions(${target} PRIVATE GLEW_STATIC) if(CRYPTO_FOUND) diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 85b961c98..72403395b 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -36,13 +36,13 @@ #include +#include #include #include #include #include #include #include -#include #include #include #include diff --git a/src/engine/client/client.h b/src/engine/client/client.h index 2997d8760..3ff19958c 100644 --- a/src/engine/client/client.h +++ b/src/engine/client/client.h @@ -6,7 +6,7 @@ #include #include -#include +#include class CGraph { diff --git a/src/engine/shared/http.cpp b/src/engine/client/http.cpp similarity index 86% rename from src/engine/shared/http.cpp rename to src/engine/client/http.cpp index e30c5d53b..188864837 100644 --- a/src/engine/shared/http.cpp +++ b/src/engine/client/http.cpp @@ -312,74 +312,3 @@ int CPostJson::AfterInit(void *pCurl) return 0; } - -static char EscapeJsonChar(char c) -{ - switch(c) - { - case '\"': return '\"'; - case '\\': return '\\'; - case '\b': return 'b'; - case '\n': return 'n'; - case '\r': return 'r'; - case '\t': return 't'; - // Don't escape '\f', who uses that. :) - default: return 0; - } -} - -char *EscapeJson(char *pBuffer, int BufferSize, const char *pString) -{ - dbg_assert(BufferSize > 0, "can't null-terminate the string"); - // Subtract the space for null termination early. - BufferSize--; - - char *pResult = pBuffer; - while(BufferSize && *pString) - { - char c = *pString; - pString++; - char Escaped = EscapeJsonChar(c); - if(Escaped) - { - if(BufferSize < 2) - { - break; - } - *pBuffer++ = '\\'; - *pBuffer++ = Escaped; - BufferSize -= 2; - } - // Assuming ASCII/UTF-8, "if control character". - else if((unsigned char)c < 0x20) - { - // \uXXXX - if(BufferSize < 6) - { - break; - } - str_format(pBuffer, BufferSize, "\\u%04x", c); - pBuffer += 6; - BufferSize -= 6; - } - else - { - *pBuffer++ = c; - BufferSize--; - } - } - *pBuffer = 0; - return pResult; -} - -const char *JsonBool(bool Bool) -{ - if(Bool) - { - return "true"; - } - else - { - return "false"; - } -} diff --git a/src/engine/shared/http.h b/src/engine/client/http.h similarity index 92% rename from src/engine/shared/http.h rename to src/engine/client/http.h index 3c21921fb..ca8c794ae 100644 --- a/src/engine/shared/http.h +++ b/src/engine/client/http.h @@ -1,5 +1,5 @@ -#ifndef ENGINE_SHARED_HTTP_H -#define ENGINE_SHARED_HTTP_H +#ifndef ENGINE_CLIENT_HTTP_H +#define ENGINE_CLIENT_HTTP_H #include #include @@ -104,6 +104,4 @@ public: bool HttpInit(IStorage *pStorage); void EscapeUrl(char *pBuf, int Size, const char *pStr); -char *EscapeJson(char *pBuffer, int BufferSize, const char *pString); -const char *JsonBool(bool Bool); -#endif // ENGINE_SHARED_HTTP_H +#endif // ENGINE_CLIENT_HTTP_H diff --git a/src/engine/client/updater.h b/src/engine/client/updater.h index 2dab900ae..079cc1496 100644 --- a/src/engine/client/updater.h +++ b/src/engine/client/updater.h @@ -2,7 +2,7 @@ #define ENGINE_CLIENT_UPDATER_H #include -#include +#include #include #include diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 3d86e842d..12eda3d2f 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -2940,8 +2939,6 @@ int main(int argc, const char **argv) // ignore_convention pEngineMasterServer->Init(); pEngineMasterServer->Load(); - HttpInit(pStorage); - // register all console commands pServer->RegisterCommands(); diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index c35cf66e6..0a44d71a7 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -159,7 +159,6 @@ MACRO_CONFIG_INT(SvPlayerDemoRecord, sv_player_demo_record, 0, 0, 1, CFGFLAG_SER MACRO_CONFIG_INT(SvDemoChat, sv_demo_chat, 0, 0, 1, CFGFLAG_SERVER, "Record chat for demos") MACRO_CONFIG_INT(SvServerInfoPerSecond, sv_server_info_per_second, 50, 1, 1000, CFGFLAG_SERVER, "Maximum number of complete server info responses that are sent out per second") MACRO_CONFIG_INT(SvVanConnPerSecond, sv_van_conn_per_second, 10, 1, 1000, CFGFLAG_SERVER, "Antispoof specific ratelimit") -MACRO_CONFIG_STR(SvModhelpUrl, sv_modhelp_url, 128, "", CFGFLAG_SERVER|CFGFLAG_NONTEEHISTORIC, "HTTP URL to POST moderator help requests to") MACRO_CONFIG_STR(EcBindaddr, ec_bindaddr, 128, "localhost", CFGFLAG_ECON, "Address to bind the external console to. Anything but 'localhost' is dangerous") MACRO_CONFIG_INT(EcPort, ec_port, 0, 0, 0, CFGFLAG_ECON, "Port to use for the external console") diff --git a/src/engine/shared/json.cpp b/src/engine/shared/json.cpp new file mode 100644 index 000000000..b683cbed2 --- /dev/null +++ b/src/engine/shared/json.cpp @@ -0,0 +1,73 @@ +#include +#include + +static char EscapeJsonChar(char c) +{ + switch(c) + { + case '\"': return '\"'; + case '\\': return '\\'; + case '\b': return 'b'; + case '\n': return 'n'; + case '\r': return 'r'; + case '\t': return 't'; + // Don't escape '\f', who uses that. :) + default: return 0; + } +} + +char *EscapeJson(char *pBuffer, int BufferSize, const char *pString) +{ + dbg_assert(BufferSize > 0, "can't null-terminate the string"); + // Subtract the space for null termination early. + BufferSize--; + + char *pResult = pBuffer; + while(BufferSize && *pString) + { + char c = *pString; + pString++; + char Escaped = EscapeJsonChar(c); + if(Escaped) + { + if(BufferSize < 2) + { + break; + } + *pBuffer++ = '\\'; + *pBuffer++ = Escaped; + BufferSize -= 2; + } + // Assuming ASCII/UTF-8, "if control character". + else if((unsigned char)c < 0x20) + { + // \uXXXX + if(BufferSize < 6) + { + break; + } + str_format(pBuffer, BufferSize, "\\u%04x", c); + pBuffer += 6; + BufferSize -= 6; + } + else + { + *pBuffer++ = c; + BufferSize--; + } + } + *pBuffer = 0; + return pResult; +} + +const char *JsonBool(bool Bool) +{ + if(Bool) + { + return "true"; + } + else + { + return "false"; + } +} diff --git a/src/engine/shared/json.h b/src/engine/shared/json.h new file mode 100644 index 000000000..b50b8a882 --- /dev/null +++ b/src/engine/shared/json.h @@ -0,0 +1,7 @@ +#ifndef ENGINE_SHARED_JSON_H +#define ENGINE_SHARED_JSON_H + +char *EscapeJson(char *pBuffer, int BufferSize, const char *pString); +const char *JsonBool(bool Bool); + +#endif // ENGINE_SHARED_JSON_H diff --git a/src/game/server/ddracechat.cpp b/src/game/server/ddracechat.cpp index 8f0daae12..8ed0aea55 100644 --- a/src/game/server/ddracechat.cpp +++ b/src/game/server/ddracechat.cpp @@ -1399,80 +1399,6 @@ void CGameContext::ConProtectedKill(IConsole::IResult *pResult, void *pUserData) } } -void CGameContext::ConModhelp(IConsole::IResult *pResult, void *pUserData) -{ - CGameContext *pSelf = (CGameContext *) pUserData; - - if(!CheckClientID(pResult->m_ClientID)) - return; - - CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID]; - if(!pPlayer) - return; - - if(pPlayer->m_pPostJson) - { - pSelf->SendChatTarget(pResult->m_ClientID, "Your last request hasn't finished processing yet, please slow down."); - return; - } - - int CurTick = pSelf->Server()->Tick(); - if(pPlayer->m_ModhelpTick != -1) - { - int TickSpeed = pSelf->Server()->TickSpeed(); - int NextModhelpTick = pPlayer->m_ModhelpTick + g_Config.m_SvModhelpDelay * TickSpeed; - if(NextModhelpTick > CurTick) - { - char aBuf[128]; - str_format(aBuf, sizeof(aBuf), "You must wait %d seconds before you can execute this command again.", - (NextModhelpTick - CurTick) / TickSpeed); - pSelf->SendChatTarget(pResult->m_ClientID, aBuf); - return; - } - } - - pPlayer->m_ModhelpTick = CurTick; - - char aBuf[512]; - str_format(aBuf, sizeof(aBuf), "Moderator help is requested by '%s' (ID: %d):", - pSelf->Server()->ClientName(pResult->m_ClientID), - pResult->m_ClientID); - - // Send the request to all authed clients. - for(int i = 0; i < MAX_CLIENTS; i++) - { - if(pSelf->m_apPlayers[i] && pSelf->Server()->ClientAuthed(i)) - { - pSelf->SendChatTarget(i, aBuf); - pSelf->SendChatTarget(i, pResult->GetString(0)); - } - } - if(g_Config.m_SvModhelpUrl[0]) - { - bool ModeratorPresent = false; - for(int i = 0; i < MAX_CLIENTS; i++) - { - if(pSelf->m_apPlayers[i] && pSelf->Server()->ClientAuthed(i)) - { - ModeratorPresent = true; - break; - } - } - - char aJson[512]; - char aPlayerName[64]; - char aMessage[128]; - str_format(aJson, sizeof(aJson), "{\"port\":%d,\"moderator_present\":%s,\"player_id\":%d,\"blacklisted\":%s,\"player_name\":\"%s\",\"message\":\"%s\"}", - g_Config.m_SvPort, - JsonBool(ModeratorPresent), - pResult->m_ClientID, - !pSelf->Server()->DnsblWhite(pResult->m_ClientID) ? "true" : "false", - EscapeJson(aPlayerName, sizeof(aPlayerName), pSelf->Server()->ClientName(pResult->m_ClientID)), - EscapeJson(aMessage, sizeof(aMessage), pResult->GetString(0))); - pSelf->Engine()->AddJob(pPlayer->m_pPostJson = std::make_shared(g_Config.m_SvModhelpUrl, false, aJson)); - } -} - #if defined(CONF_SQL) void CGameContext::ConPoints(IConsole::IResult *pResult, void *pUserData) { diff --git a/src/game/server/ddracechat.h b/src/game/server/ddracechat.h index 7fa96f9a5..3a75650e0 100644 --- a/src/game/server/ddracechat.h +++ b/src/game/server/ddracechat.h @@ -50,8 +50,6 @@ CHAT_COMMAND("rescue", "", CFGFLAG_CHAT|CFGFLAG_SERVER, ConRescue, this, "Telepo CHAT_COMMAND("kill", "", CFGFLAG_CHAT|CFGFLAG_SERVER, ConProtectedKill, this, "Kill yourself") -CHAT_COMMAND("modhelp", "r[message]", CFGFLAG_CHAT|CFGFLAG_SERVER, ConModhelp, this, "Request the help of a moderator with a description of the problem") - #if defined(CONF_SQL) CHAT_COMMAND("times", "?s[player name] ?i[number of times to skip]", CFGFLAG_CHAT|CFGFLAG_SERVER, ConTimes, this, "/times ?s?i shows last 5 times of the server or of a player beginning with name s starting with time i (i = 1 by default)") CHAT_COMMAND("points", "?r[player name]", CFGFLAG_CHAT|CFGFLAG_SERVER, ConPoints, this, "Shows the global points of a player beginning with name r (your rank by default)") diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 962b21407..0ae5eb1a1 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -902,22 +902,6 @@ void CGameContext::OnTick() m_aMutes[i] = m_aMutes[m_NumMutes]; } } - for(int i = 0; i < MAX_CLIENTS; i++) - { - if(m_apPlayers[i] && m_apPlayers[i]->m_pPostJson) - { - switch(m_apPlayers[i]->m_pPostJson->State()) - { - case HTTP_DONE: - m_apPlayers[i]->m_pPostJson = NULL; - break; - case HTTP_ERROR: - dbg_msg("modhelp", "http request failed for cid=%d", i); - m_apPlayers[i]->m_pPostJson = NULL; - break; - } - } - } if(Server()->Tick() % (g_Config.m_SvAnnouncementInterval * Server()->TickSpeed() * 60) == 0) { diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h index 5d47d312a..2acba2c83 100644 --- a/src/game/server/gamecontext.h +++ b/src/game/server/gamecontext.h @@ -357,7 +357,6 @@ private: static void ConUnmute(IConsole::IResult *pResult, void *pUserData); static void ConMutes(IConsole::IResult *pResult, void *pUserData); static void ConModerate(IConsole::IResult *pResult, void *pUserData); - static void ConModhelp(IConsole::IResult *pResult, void *pUserData); static void ConList(IConsole::IResult *pResult, void *pUserData); static void ConSetDDRTeam(IConsole::IResult *pResult, void *pUserData); diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index e48f319d4..d0c69f81a 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -69,7 +69,6 @@ void CPlayer::Reset() m_LastWhisperTo = -1; m_LastSetSpectatorMode = 0; m_TimeoutCode[0] = '\0'; - m_ModhelpTick = -1; m_TuneZone = 0; m_TuneZoneOld = m_TuneZone; diff --git a/src/game/server/player.h b/src/game/server/player.h index 91ae139e6..4465256fb 100644 --- a/src/game/server/player.h +++ b/src/game/server/player.h @@ -6,7 +6,6 @@ // this include should perhaps be removed #include "entities/character.h" #include "gamecontext.h" -#include // player object class CPlayer @@ -175,7 +174,6 @@ public: int m_ChatScore; bool m_Moderating; - int m_ModhelpTick; bool AfkTimer(int new_target_x, int new_target_y); //returns true if kicked void AfkVoteTimer(CNetObj_PlayerInput *NewTarget); @@ -198,7 +196,6 @@ public: #if defined(CONF_SQL) int64 m_LastSQLQuery; #endif - std::shared_ptr m_pPostJson; }; #endif diff --git a/src/game/server/teehistorian.cpp b/src/game/server/teehistorian.cpp index 5ecbb2c68..b5d76e20b 100644 --- a/src/game/server/teehistorian.cpp +++ b/src/game/server/teehistorian.cpp @@ -2,6 +2,7 @@ #include #include +#include #include static const char TEEHISTORIAN_NAME[] = "teehistorian@ddnet.tw"; diff --git a/src/game/server/teehistorian.h b/src/game/server/teehistorian.h index 8f3be6a0f..9c4107f23 100644 --- a/src/game/server/teehistorian.h +++ b/src/game/server/teehistorian.h @@ -3,7 +3,6 @@ #include #include -#include #include #include #include diff --git a/src/game/variables.h b/src/game/variables.h index 26182f6f0..bb7b34d0a 100644 --- a/src/game/variables.h +++ b/src/game/variables.h @@ -158,8 +158,6 @@ MACRO_CONFIG_INT(SvSendVotesPerTick, sv_send_votes_per_tick, 5, 1, 15, CFGFLAG_S MACRO_CONFIG_INT(SvRescue, sv_rescue, 0, 0, 1, CFGFLAG_SERVER, "Allow /rescue command so players can teleport themselves out of freeze") MACRO_CONFIG_INT(SvRescueDelay, sv_rescue_delay, 5, 0, 1000, CFGFLAG_SERVER, "Number of seconds between two rescues") -MACRO_CONFIG_INT(SvModhelpDelay, sv_modhelp_delay, 60, 0, 0, CFGFLAG_SERVER, "Number of seconds to wait before executing /modhelp again") - // debug #ifdef CONF_DEBUG // this one can crash the server if not used correctly MACRO_CONFIG_INT(DbgDummies, dbg_dummies, 0, 0, 15, CFGFLAG_SERVER, "") diff --git a/src/modhelp/server.py b/src/modhelp/server.py deleted file mode 100755 index 88b534fb5..000000000 --- a/src/modhelp/server.py +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env python3 -from flask import Flask, make_response, request -import http -import os -import re -import requests - -SERVER=os.getenv('MODHELP_SERVER') -# Generate one by right-clicking on the server icon in the sidebar, clicking on -# "Server Settings" → "Webhooks" → "Create Webhook". You can then select the -# channel in which the messages should appear. Copy the "Webhook URL" to the -# following config variable: -# DISCORD_WEBHOOK="https://discordapp.com/api/webhooks/.../..." -DISCORD_WEBHOOK=os.getenv('MODHELP_DISCORD_WEBHOOK') -DISCORD_MESSAGE=os.getenv('MODHELP_DISCORD_FORMAT', "<{player_id}:**{player_name}**> {message}") -DISCORD_MESSAGE_PREFIX=os.getenv('MODHELP_DISCORD_PREFIX') - -app = Flask(__name__) - -def sanitize(s): - return re.sub(r"([^\0- 0-9A-Za-z])", r"\\\1", s) - -def no_content(): - return make_response("", http.HTTPStatus.NO_CONTENT) - -def sanitize_string_values(dictionary): - return {k: v if not isinstance(v, str) else sanitize(v) for k, v in dictionary.items()} - -@app.route("/modhelp", methods=['POST']) -def modhelp(): - json = request.get_json() - - if "server" not in json: - if SERVER: - json["server"] = SERVER - - if "server" not in json: - user = "{port}".format(**json) - else: - user = "{server}:{port}".format(**json) - - discord_prefix = DISCORD_MESSAGE_PREFIX + " " if DISCORD_MESSAGE_PREFIX is not None else "" - discord_message = discord_prefix + DISCORD_MESSAGE.format(**sanitize_string_values(json)) - - if DISCORD_WEBHOOK: - try: - requests.post(DISCORD_WEBHOOK, data={"username": user, "content": discord_message}).raise_for_status() - except requests.HTTPError as e: - print(repr(e)) - raise - return no_content() diff --git a/src/test/json.cpp b/src/test/json.cpp index 4dbc6d8a3..203f2c7fc 100644 --- a/src/test/json.cpp +++ b/src/test/json.cpp @@ -1,6 +1,6 @@ #include -#include +#include TEST(Json, Escape) {