Refactors stack traces, tiny bit of cleanup (#18773)

This commit is contained in:
AffectedArc07
2022-08-14 02:11:40 +01:00
committed by GitHub
parent 5d819ac1a9
commit 34ed47ae74
50 changed files with 228 additions and 175 deletions
+107 -42
View File
@@ -47,14 +47,10 @@
hsrc = locate(href_list["src"])
if(hsrc)
var/hsrc_info = datum_info_line(hsrc) || "[hsrc]"
log_runtime(EXCEPTION("Got \\ref-based src in topic from [src] for [hsrc_info], should be UID: [href]"))
stack_trace("Got \\ref-based src in topic from [src] for [hsrc_info], should be UID: [href]")
#if defined(TOPIC_DEBUGGING)
to_chat(world, "[src]'s Topic: [href] destined for [hsrc].")
#endif
if(href_list["asset_cache_confirm_arrival"])
// to_chat(src, "ASSET JOB [href_list["asset_cache_confirm_arrival"]] ARRIVED.")
var/job = text2num(href_list["asset_cache_confirm_arrival"])
completed_asset_jobs += job
return
@@ -64,17 +60,19 @@
// Rate limiting
var/mtl = 100 // 100 topics per minute
if (!holder) // Admins are allowed to spam click, deal with it.
if(!holder) // Admins are allowed to spam click, deal with it.
var/minute = round(world.time, 600)
if (!topiclimiter)
if(!topiclimiter)
topiclimiter = new(LIMITER_SIZE)
if (minute != topiclimiter[CURRENT_MINUTE])
if(minute != topiclimiter[CURRENT_MINUTE])
topiclimiter[CURRENT_MINUTE] = minute
topiclimiter[MINUTE_COUNT] = 0
topiclimiter[MINUTE_COUNT] += 1
if (topiclimiter[MINUTE_COUNT] > mtl)
if(topiclimiter[MINUTE_COUNT] > mtl)
var/msg = "Your previous action was ignored because you've done too many in a minute."
if (minute != topiclimiter[ADMINSWARNED_AT]) //only one admin message per-minute. (if they spam the admins can just boot/ban them)
if(minute != topiclimiter[ADMINSWARNED_AT]) //only one admin message per-minute. (if they spam the admins can just boot/ban them)
topiclimiter[ADMINSWARNED_AT] = minute
msg += " Administrators have been informed."
log_game("[key_name(src)] Has hit the per-minute topic limit of [mtl] topic calls in a given game minute")
@@ -83,22 +81,24 @@
return
var/stl = 10 // 10 topics a second
if (!holder) // Admins are allowed to spam click, deal with it.
if(!holder) // Admins are allowed to spam click, deal with it.
var/second = round(world.time, 10)
if (!topiclimiter)
if(!topiclimiter)
topiclimiter = new(LIMITER_SIZE)
if (second != topiclimiter[CURRENT_SECOND])
if(second != topiclimiter[CURRENT_SECOND])
topiclimiter[CURRENT_SECOND] = second
topiclimiter[SECOND_COUNT] = 0
topiclimiter[SECOND_COUNT] += 1
if (topiclimiter[SECOND_COUNT] > stl)
if(topiclimiter[SECOND_COUNT] > stl)
to_chat(src, "<span class='danger'>Your previous action was ignored because you've done too many in a second</span>")
return
//search the href for script injection
if( findtext(href,"<script",1,0) )
if(findtext(href, "<script", 1, 0))
log_world("Attempted use of scripts within a topic call, by [src]")
log_runtime(EXCEPTION("Attempted use of scripts within a topic call, by [src]"), src)
stack_trace("Attempted use of scripts within a topic call, by [src]")
message_admins("Attempted use of scripts within a topic call, by [src]")
return
@@ -119,8 +119,6 @@
cmd_admin_discord_pm()
return
//Logs all hrefs
if(GLOB.configuration.logging.href_logging)
log_href("[src] (usr:[usr]\[[COORD(usr)]\]) : [hsrc ? "[hsrc] " : ""][href]")
@@ -135,9 +133,11 @@
ssd_warning_acknowledged = TRUE
to_chat(src, "<span class='notice'>SSD warning acknowledged.</span>")
return
if(href_list["link_forum_account"])
link_forum_account()
return // prevents a recursive loop where the ..() 5 lines after this makes the proc endlessly re-call itself
if(href_list["withdraw_consent"])
var/choice = alert(usr, "Are you SURE you want to withdraw your consent to the Terms of Service?\nYou will be instantaneously removed from the server and will have to re-accept the Terms of Service.", "Warning", "Yes", "No")
if(choice == "Yes")
@@ -145,6 +145,7 @@
var/datum/db_query/query = SSdbcore.NewQuery("REPLACE INTO privacy (ckey, datetime, consent) VALUES (:ckey, Now(), 0)", list(
"ckey" = ckey
))
if(!query.warn_execute())
to_chat(usr, "Well, this is embarassing. We tried to save your ToS withdrawal but the DB failed. Please contact the server host")
return
@@ -153,6 +154,7 @@
message_admins("[key_name_admin(usr)] was disconnected due to withdrawing their ToS consent.")
to_chat(usr, "<span class='boldannounce'>Your ToS consent has been withdrawn. You have been kicked from the server</span>")
qdel(src)
return
if(href_list["__keydown"])
var/keycode = href_list["__keydown"]
@@ -178,12 +180,6 @@
var/fakekey = holder?.fakekey
return fakekey ? fakekey : key
/client/proc/is_content_unlocked()
if(!prefs.unlock_content)
to_chat(src, "Become a BYOND member to access member-perks and features, as well as support the engine that makes this game possible. <a href='http://www.byond.com/membership'>Click here to find out more</a>.")
return 0
return 1
//Like for /atoms, but clients are their own snowflake FUCK
/client/proc/setDir(newdir)
dir = newdir
@@ -195,25 +191,28 @@
to_chat(src, "<span class='danger'>You are sending messages to quickly. Please wait [wait_time] [wait_time == 1 ? "second" : "seconds"] before sending another message.</span>")
return 1
last_message_time = world.time
if(GLOB.configuration.general.enable_auto_mute && !check_rights(R_ADMIN, 0) && last_message == message)
last_message_count++
if(last_message_count >= SPAM_TRIGGER_AUTOMUTE)
to_chat(src, "<span class='danger'>You have exceeded the spam filter limit for identical messages. An auto-mute was applied.</span>")
cmd_admin_mute(mob, mute_type, 1)
return 1
return TRUE
if(last_message_count >= SPAM_TRIGGER_WARNING)
to_chat(src, "<span class='danger'>You are nearing the spam filter limit for identical messages.</span>")
return 0
return FALSE
else
last_message = message
last_message_count = 0
return 0
return FALSE
//This stops files larger than UPLOAD_LIMIT being sent from client to server via input(), client.Import() etc.
/client/AllowUpload(filename, filelength)
if(filelength > UPLOAD_LIMIT)
to_chat(src, "<font color='red'>Error: AllowUpload(): File Upload too large. Upload Limit: [UPLOAD_LIMIT/1024]KiB.</font>")
return 0
return FALSE
/* //Don't need this at the moment. But it's here if it's needed later.
//Helps prevent multiple files being uploaded at once. Or right after eachother.
var/time_to_wait = fileaccess_timer - world.time
@@ -221,7 +220,7 @@
to_chat(src, "<font color='red'>Error: AllowUpload(): Spam prevention. Please wait [round(time_to_wait/10)] seconds.</font>")
return 0
fileaccess_timer = world.time + FTPDELAY */
return 1
return TRUE
///////////
@@ -234,14 +233,18 @@
if(connection != "seeker") //Invalid connection type.
return null
if(byond_version < MIN_CLIENT_VERSION) // Too out of date to play at all. Unfortunately, we can't send them a message here.
version_blocked = TRUE
if(byond_build < GLOB.configuration.general.minimum_client_build)
version_blocked = TRUE
var/show_update_prompt = FALSE
if(byond_version < SUGGESTED_CLIENT_VERSION) // Update is suggested, but not required.
show_update_prompt = TRUE
else if(byond_version == SUGGESTED_CLIENT_VERSION && byond_build < SUGGESTED_CLIENT_BUILD)
show_update_prompt = TRUE
@@ -282,6 +285,7 @@
CLP.process_result(login_queries[CLP.type], src)
QDEL_LIST_ASSOC_VAL(login_queries) // Clear out the used queries
else
// Set vars here that need to be set if the DB is offline
@@ -304,6 +308,7 @@
// Log alts
if(length(related_accounts_ip))
log_admin("[key_name(src)] Alts by IP: [jointext(related_accounts_ip, " ")]")
if(length(related_accounts_cid))
log_admin("[key_name(src)] Alts by CID: [jointext(related_accounts_cid, " ")]")
@@ -329,6 +334,7 @@
deadmin()
verbs += /client/proc/readmin
GLOB.deadmins += ckey
else
on_holder_add()
add_admin_verbs()
@@ -361,6 +367,7 @@
if(prefs.toggles & PREFTOGGLE_UI_DARKMODE) // activates dark mode if its flagged. -AA07
activate_darkmode()
else
// activate_darkmode() calls the CL update button proc, so we dont want it double called
SSchangelog.UpdatePlayerChangelogButton(src)
@@ -430,17 +437,21 @@
announce_leave() // Do not put this below
SSdebugview.stop_processing(src)
SSchangelog.startup_clients_open -= src
if(holder)
holder.owner = null
GLOB.admins -= src
GLOB.directory -= ckey
GLOB.clients -= src
SSinstancing.update_playercache() // Clear us out
QDEL_NULL(chatOutput)
QDEL_NULL(pai_save)
if(movingmob)
movingmob.client_mobs_in_contents -= mob
UNSETEMPTY(movingmob.client_mobs_in_contents)
SSambience.ambience_listening_clients -= src
SSinput.processing -= src
Master.UpdateTickRate()
@@ -563,6 +574,7 @@
qdel(query_update)
// After the regular update
INVOKE_ASYNC(src, /client/.proc/get_byond_account_date, FALSE) // Async to avoid other procs in the client chain being delayed by a web request
else
//New player!! Need to insert all the stuff
var/datum/db_query/query_insert = SSdbcore.NewQuery("INSERT INTO player (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, :ckey, Now(), Now(), :ip, :cid, :rank)", list(
@@ -623,24 +635,29 @@
/client/proc/check_forum_link()
if(!GLOB.configuration.url.forum_link_url || !prefs || prefs.fuid)
return
if(GLOB.configuration.jobs.enable_exp_tracking)
var/living_hours = get_exp_type_num(EXP_TYPE_LIVING) / 60
if(living_hours < 20)
return
to_chat(src, "<B>You have no verified forum account. <a href='?src=[UID()];link_forum_account=true'>VERIFY FORUM ACCOUNT</a></B>")
/client/proc/create_oauth_token()
var/datum/db_query/query_find_token = SSdbcore.NewQuery("SELECT token FROM oauth_tokens WHERE ckey=:ckey limit 1", list(
"ckey" = ckey
))
// These queries have log_error=FALSE to avoid auth tokens being in plaintext logs
if(!query_find_token.warn_execute(log_error=FALSE))
qdel(query_find_token)
return
if(query_find_token.NextRow())
var/tkn = query_find_token.item[1]
qdel(query_find_token)
return tkn
qdel(query_find_token)
var/tokenstr = md5("[rand(0,9999)][world.time][rand(0,9999)][ckey][rand(0,9999)][address][rand(0,9999)][computer_id][rand(0,9999)]")
@@ -649,40 +666,49 @@
"ckey" = ckey,
"tokenstr" = tokenstr,
))
// These queries have log_error=FALSE to avoid auth tokens being in plaintext logs
if(!query_insert_token.warn_execute(log_error=FALSE))
if(!query_insert_token.warn_execute(log_error = FALSE))
qdel(query_insert_token)
return
qdel(query_insert_token)
return tokenstr
/client/proc/link_forum_account(fromban)
if(!GLOB.configuration.url.forum_link_url)
return
if(IsGuestKey(key))
to_chat(src, "Guest keys cannot be linked.")
return
if(prefs && prefs.fuid)
if(!fromban)
to_chat(src, "Your forum account is already set.")
return
var/datum/db_query/query_find_link = SSdbcore.NewQuery("SELECT fuid FROM player WHERE ckey=:ckey LIMIT 1", list(
"ckey" = ckey
))
if(!query_find_link.warn_execute())
qdel(query_find_link)
return
if(query_find_link.NextRow())
if(query_find_link.item[1])
if(!fromban)
to_chat(src, "Your forum account is already set. ([query_find_link.item[1]])")
qdel(query_find_link)
return
qdel(query_find_link)
var/tokenid = create_oauth_token()
if(!tokenid)
to_chat(src, "link_forum_account: unable to create token")
return
var/url = "[GLOB.configuration.url.forum_link_url][tokenid]"
if(fromban)
url += "&fwd=appeal"
@@ -690,6 +716,7 @@
to_chat(src, "<span class='boldannounce'>If you are screenshotting this screen for your ban appeal, please blur/draw over the token in the above link.</span>")
else
to_chat(src, {"Now opening a window to verify your information with the forums. If the window does not load, please go to: <a href="[url]">[url]</a>"})
src << link(url)
return
@@ -701,11 +728,14 @@
/client/proc/check_randomizer(topic)
set waitfor = FALSE // Yes I know this is already called from an async proc but someone may change that without thinking properly
. = FALSE
if(connection != "seeker") //Invalid connection type.
return null
topic = params2list(topic)
if(!GLOB.configuration.general.enabled_cid_randomiser_buster)
return
// Stash o' ckeys
var/static/cidcheck = list()
var/static/tokens = list()
@@ -719,6 +749,7 @@
var/datum/db_query/query_cidcheck = SSdbcore.NewQuery("SELECT computerid FROM player WHERE ckey=:ckey", list(
"ckey" = ckey
))
if(!query_cidcheck.warn_execute())
qdel(query_cidcheck)
return
@@ -726,6 +757,7 @@
var/lastcid = computer_id
if(query_cidcheck.NextRow())
lastcid = query_cidcheck.item[1]
qdel(query_cidcheck)
if(computer_id != lastcid)
@@ -741,9 +773,10 @@
to_chat(src, "<pre class=\"system system\">you're a huge nerd. wakka wakka doodle doop nobody's ever gonna see this, the chat system shouldn't be online by this point</pre>")
qdel(src)
return TRUE
else
if (!topic || !topic["token"] || !tokens[ckey] || topic["token"] != tokens[ckey])
if (!cidcheck_spoofckeys[ckey])
if(!topic || !topic["token"] || !tokens[ckey] || topic["token"] != tokens[ckey])
if(!cidcheck_spoofckeys[ckey])
message_admins("<span class='adminnotice'>[key_name(src)] appears to have attempted to spoof a cid randomizer check.</span>")
cidcheck_spoofckeys[ckey] = TRUE
cidcheck[ckey] = computer_id
@@ -752,6 +785,7 @@
sleep(10) //browse is queued, we don't want them to disconnect before getting the browse() command.
qdel(src)
return TRUE
// We DO have their cached CID handy - compare it, now
if(oldcid != computer_id)
// Change detected, they are randomizing
@@ -770,6 +804,7 @@
qdel(src)
return TRUE
else
// don't shoot, I'm innocent
if(cidcheck_failedckeys[ckey])
@@ -777,7 +812,8 @@
message_admins("<span class='adminnotice'>[key_name_admin(src)] has been allowed to connect after showing they removed their cid randomizer</span>")
SSdiscord.send2discord_simple_noadmins("**\[Info]** [key_name(src)] has been allowed to connect after showing they removed their cid randomizer.")
cidcheck_failedckeys -= ckey
if (cidcheck_spoofckeys[ckey])
if(cidcheck_spoofckeys[ckey])
message_admins("<span class='adminnotice'>[key_name_admin(src)] has been allowed to connect after appearing to have attempted to spoof a cid randomizer check because it <i>appears</i> they aren't spoofing one this time</span>")
cidcheck_spoofckeys -= ckey
cidcheck -= ckey
@@ -790,33 +826,42 @@
"ckey" = ckey,
"adminckey" = adminckey
))
if(!query_get_notes.warn_execute())
qdel(query_get_notes)
return
if(query_get_notes.NextRow())
qdel(query_get_notes)
return
qdel(query_get_notes)
// Only add a note if their most recent note isn't from the randomizer blocker, either
var/datum/db_query/query_get_note = SSdbcore.NewQuery("SELECT adminckey FROM notes WHERE ckey=:ckey ORDER BY timestamp DESC LIMIT 1", list(
"ckey" = ckey
))
if(!query_get_note.warn_execute())
qdel(query_get_note)
return
if(query_get_note.NextRow())
if(query_get_note.item[1] == adminckey)
qdel(query_get_note)
return
qdel(query_get_note)
add_note(ckey, "Detected as using a cid randomizer.", null, adminckey, logged = 0)
add_note(ckey, "Detected as using a cid randomizer.", null, adminckey, logged = FALSE)
/client/proc/cid_check_reconnect()
var/token = md5("[rand(0,9999)][world.time][rand(0,9999)][ckey][rand(0,9999)][address][rand(0,9999)][computer_id][rand(0,9999)]")
. = token
log_adminwarn("Failed Login: [key] [computer_id] [address] - CID randomizer check")
var/url = winget(src, null, "url")
//special javascript to make them reconnect under a new window.
src << browse("<a id='link' href='byond://[url]?token=[token]'>\
byond://[url]?token=[token]\
@@ -826,12 +871,12 @@
window.location=\"byond://winset?command=.quit\"\
</script>",
"border=0;titlebar=0;size=1x1")
to_chat(src, "<a href='byond://[url]?token=[token]'>You will be automatically taken to the game, if not, click here to be taken manually</a>. Except you can't, since the chat window doesn't exist yet.")
//checks if a client is afk
//3000 frames = 5 minutes
/client/proc/is_afk(duration=3000)
if(inactivity > duration) return inactivity
/client/proc/is_afk(duration = 5 MINUTES)
if(inactivity > duration)
return inactivity
return 0
//Send resources to the client.
@@ -839,13 +884,16 @@
// Change the way they should download resources.
if(length(GLOB.configuration.url.rsc_urls))
preload_rsc = pick(GLOB.configuration.url.rsc_urls)
else
preload_rsc = 1 // If config.resource_urls is not set, preload like normal.
// Most assets are now handled through global_cache.dm
getFiles(
'html/search.js', // Used in various non-TGUI HTML windows for search functionality
'html/panels.css' // Used for styling certain panels, such as in the new player panel
)
spawn (10) //removing this spawn causes all clients to not get verbs.
//Precache the client with all other assets slowly, so as to not block other browse() calls
getFilesSlow(src, SSassets.preload, register_asset = FALSE)
@@ -855,8 +903,10 @@
for(var/L in GLOB.all_languages)
var/datum/language/lang = GLOB.all_languages[L]
var/message = "[lang.name] : [lang.type]"
if(lang.flags & RESTRICTED)
message += " (RESTRICTED)"
to_chat(world, "[message]")
/client/proc/colour_transition(list/colour_to = null, time = 10) //Call this with no parameters to reset to default.
@@ -950,10 +1000,13 @@
/client/proc/send_ssd_warning(mob/M)
if(!GLOB.configuration.general.ssd_warning)
return FALSE
if(ssd_warning_acknowledged)
return FALSE
if(M && M.player_logged < SSD_WARNING_TIMER)
if(M?.player_logged < SSD_WARNING_TIMER)
return FALSE
to_chat(src, "Are you taking this person to cryo or giving them medical treatment? If you are, <a href='byond://?src=[UID()];ssdwarning=accepted'>confirm that</a> and proceed. Interacting with SSD players in other ways is against server rules unless you've ahelped first for permission.")
return TRUE
@@ -1009,13 +1062,16 @@
var/list/lines = splittext(http["CONTENT"], "\n")
var/list/initial_data = list()
var/current_index = ""
for(var/L in lines)
if(L == "")
continue
if(!findtext(L, "\t"))
current_index = L
initial_data[current_index] = list()
continue
initial_data[current_index] += replacetext(replacetext(L, "\t", ""), "\"", "")
var/list/parsed_data = list()
@@ -1032,12 +1088,15 @@
// Main return is here
return parsed_data
catch
log_debug("Error parsing byond.com data for [ckey]. Please inform maintainers.")
return null
else
log_debug("Error retrieving data from byond.com for [ckey]. Invalid status code (Expected: 200 | Got: [status]).")
return null
else
log_debug("Failed to retrieve data from byond.com for [ckey]. Connection failed.")
return null
@@ -1056,6 +1115,7 @@
var/datum/db_query/query_date = SSdbcore.NewQuery("SELECT byond_date, DATEDIFF(Now(), byond_date) FROM player WHERE ckey=:ckey", list(
"ckey" = ckey
))
if(!query_date.warn_execute())
qdel(query_date)
return
@@ -1083,21 +1143,25 @@
"date" = byondacc_date,
"ckey" = ckey
))
if(!query_update.warn_execute())
qdel(query_update)
return
qdel(query_update)
// Now retrieve the age again because BYOND doesnt have native methods for this
var/datum/db_query/query_age = SSdbcore.NewQuery("SELECT DATEDIFF(Now(), byond_date) FROM player WHERE ckey=:ckey", list(
"ckey" = ckey
))
if(!query_age.warn_execute())
qdel(query_age)
return
while(query_age.NextRow())
byondacc_age = max(text2num(query_age.item[1]), 0) // Ensure account isnt negative days old
qdel(query_age)
// Notify admins on new clients connecting, if the byond account age is less than a config value
@@ -1111,7 +1175,9 @@
if(prefs.sound & SOUND_AMBIENCE)
if(SSambience.ambience_listening_clients[src] > world.time)
return // If already properly set we don't want to reset the timer.
SSambience.ambience_listening_clients[src] = world.time + 10 SECONDS //Just wait 10 seconds before the next one aight mate? cheers.
else
SSambience.ambience_listening_clients -= src
@@ -1124,12 +1190,11 @@
var/output = GLOB.join_tos
output += "<hr><p>By withdrawing your consent, you acknowledge that you will be instantaneously kicked from the server and will have to re-accept the Terms of Service. If you do not wish to withdraw your consent at this moment, feel free to close this window.</p>"
output += "<p><a href='byond://?src=[UID()];withdraw_consent=1'>Withdraw consent</a></p>"
src << browse(output,"window=privacy_consent;size=600x500")
var/datum/browser/popup = new(src, "privacy_consent", "<div align='center'>Privacy Consent</div>", 500, 400)
popup.set_content(output)
popup.open(FALSE)
return
#undef LIMITER_SIZE
#undef CURRENT_SECOND
@@ -54,7 +54,7 @@
// Might as well scrub out any malformed be_special list entries while we're here
for(var/role in be_special)
if(!(role in GLOB.special_roles))
log_runtime(EXCEPTION("[C.key] had a malformed role entry: '[role]'. Removing!"), src)
stack_trace("[C.key] had a malformed role entry: '[role]'. Removing!")
be_special -= role
// We're saving volume_mixer here as well, so no point in keeping the timer running