diff --git a/code/game/world.dm b/code/game/world.dm index 958ef849..9c1f4780 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -1,4 +1,6 @@ #define RESTART_COUNTER_PATH "data/round_counter.txt" +#define TOPIC_LENGTH_LIMIT 8192 //The reason why this is so large is to allow TGS topic calls to function without issue. +#define TOPIC_COOLDOWN 1 //90% sure there isnt anything that does multiple topic calls in a single decisecond. GLOBAL_VAR(restart_counter) @@ -140,6 +142,25 @@ GLOBAL_VAR(restart_counter) log_runtime(GLOB.revdata.get_log_message()) /world/Topic(T, addr, master, key) + var/static/list/bannedsourceaddrs = list() + var/static/list/lasttimeaddr = list() + + if(addr in bannedsourceaddrs) + return + + if(length(T) >= TOPIC_LENGTH_LIMIT) + log_topic("Oversized topic, banning address. from:[addr]") + bannedsourceaddrs |= addr + return + + if(addr in lasttimeaddr && world.time < (lasttimeaddr["[addr]"] + TOPIC_COOLDOWN)) + log_topic("Too many topic calls from address in [TOPIC_COOLDOWN] ds, banning address. from:[addr]") + bannedsourceaddrs |= addr + return + + lasttimeaddr["[addr]"] = world.time + + TGS_TOPIC //redirect to server tools if necessary var/static/list/topic_handlers = TopicHandlers() diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 3f4e5e15..7fe6b41b 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -5,9 +5,17 @@ For the main html chat area //Precaching a bunch of shit GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of icons for the browser output +//Should match the value set in the browser js +#define MAX_COOKIE_LENGTH 5 + + //On client, created on login /datum/chatOutput var/client/owner //client ref + // How many times client data has been checked + var/total_checks = 0 + // When to next clear the client data checks counter + var/next_time_to_clear = 0 var/loaded = FALSE // Has the client loaded the browser output area? var/list/messageQueue //If they haven't loaded chat, this is where messages will go until they do var/cookieSent = FALSE // Has the client sent a cookie for analysis @@ -148,6 +156,19 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico //Called by client, sent data to investigate (cookie history so far) /datum/chatOutput/proc/analyzeClientData(cookie = "") + //Spam check + if(world.time > next_time_to_clear) + next_time_to_clear = world.time + (3 SECONDS) + total_checks = 0 + + total_checks += 1 + + if(total_checks > SPAM_TRIGGER_AUTOMUTE) + message_admins("[key_name(owner)] kicked for goonchat topic spam") + qdel(owner) + return + + if(!cookie) return @@ -156,13 +177,24 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico if (connData && islist(connData) && connData.len > 0 && connData["connData"]) connectionHistory = connData["connData"] //lol fuck var/list/found = new() + + if(connectionHistory.len > MAX_COOKIE_LENGTH) + message_admins("[key_name(src.owner)] was kicked for an invalid ban cookie)") + qdel(owner) + return + + for(var/i in connectionHistory.len to 1 step -1) + if(QDELETED(owner)) + //he got cleaned up before we were done + return var/list/row = src.connectionHistory[i] if (!row || row.len < 3 || (!row["ckey"] || !row["compid"] || !row["ip"])) //Passed malformed history object return if (world.IsBanned(row["ckey"], row["ip"], row["compid"], real_bans_only=TRUE)) found = row break + CHECK_TICK //Uh oh this fucker has a history of playing on a banned account!! if (found.len > 0) @@ -253,3 +285,6 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico /datum/chatOutput/proc/swaptodarkmode() owner.force_dark_theme() + + +#undef MAX_COOKIE_LENGTH diff --git a/code/modules/goonchat/browserassets/js/browserOutput.js b/code/modules/goonchat/browserassets/js/browserOutput.js index 93a498fd..4375926c 100644 --- a/code/modules/goonchat/browserassets/js/browserOutput.js +++ b/code/modules/goonchat/browserassets/js/browserOutput.js @@ -30,7 +30,7 @@ var opts = { 'scrollSnapTolerance': 10, //If within x pixels of bottom 'clickTolerance': 10, //Keep focus if outside x pixels of mousedown position on mouseup 'imageRetryDelay': 50, //how long between attempts to reload images (in ms) - 'imageRetryLimit': 50, //how many attempts should we make? + 'imageRetryLimit': 50, //how many attempts should we make? 'popups': 0, //Amount of popups opened ever 'wasd': false, //Is the user in wasd mode? 'priorChatHeight': 0, //Thing for height-resizing detection @@ -159,7 +159,7 @@ function byondDecode(message) { // The replace for + is because FOR SOME REASON, BYOND replaces spaces with a + instead of %20, and a plus with %2b. // Marvelous. message = message.replace(/\+/g, "%20"); - try { + try { // This is a workaround for the above not always working when BYOND's shitty url encoding breaks. (byond bug id:2399401) if (decodeURIComponent) { message = decodeURIComponent(message); @@ -420,8 +420,8 @@ function handleClientData(ckey, ip, compid) { return; //Record already exists } } - - if (opts.clientData.length >= opts.clientDataLimit) { + //Lets make sure we obey our limit (can connect from server with higher limit) + while (opts.clientData.length >= opts.clientDataLimit) { opts.clientData.shift(); } } else { diff --git a/tgstation.dme b/tgstation.dme index 41677a1b..59160062 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -2880,7 +2880,6 @@ #include "modular_citadel\code\_onclick\hud\stamina.dm" #include "modular_citadel\code\controllers\configuration\entries\general.dm" #include "modular_citadel\code\controllers\subsystem\job.dm" -//#include "modular_citadel\code\controllers\subsystem\shuttle.dm" #include "modular_citadel\code\datums\components\material_container.dm" #include "modular_citadel\code\datums\components\phantomthief.dm" #include "modular_citadel\code\datums\components\souldeath.dm"