diff --git a/code/__DEFINES/_globals.dm b/code/__DEFINES/_globals.dm index 6448fab451a3..4da30c08aace 100644 --- a/code/__DEFINES/_globals.dm +++ b/code/__DEFINES/_globals.dm @@ -9,6 +9,21 @@ /// Creates an empty global initializer, do not use #define GLOBAL_UNMANAGED(X) /datum/controller/global_vars/proc/InitGlobal##X() { return; } +#define GLOBAL_MANAGED_MULTIPLE(X)\ +/datum/controller/global_vars/proc/InitGlobal##X(){\ + ##X = CollectGlobal##X();\ +}\ +/datum/controller/global_vars/proc/CollectGlobal##X(){\ + CAN_BE_REDEFINED(TRUE);\ + return list();\ +} + +#define GLOBAL_MULTIPLE_UPDATE(X, NewValue)\ +/datum/controller/global_vars/CollectGlobal##X(){\ + . = ..();\ + . += ##NewValue;\ +} + /// Creates name keyed subtype instance list #define GLOBAL_SUBTYPE_INDEXED(X, TypePath, Index)\ /datum/controller/global_vars/proc/InitGlobal##X(){\ @@ -69,6 +84,8 @@ /// Create a global const var, do not use #define GLOBAL_VAR_CONST(X, InitValue) GLOBAL_RAW(/const/##X) = InitValue; GLOBAL_UNMANAGED(X) +#define GLOBAL_MULTIPLE(X) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED_MULTIPLE(X) + /// Create a list global with an initializer expression #define GLOBAL_LIST_INIT(X, InitValue) GLOBAL_RAW(/list/##X); GLOBAL_MANAGED(X, InitValue) diff --git a/code/__DEFINES/_protect.dm b/code/__DEFINES/_protect.dm index 5dbbd2d51386..f6fa1c12c8b0 100644 --- a/code/__DEFINES/_protect.dm +++ b/code/__DEFINES/_protect.dm @@ -1,4 +1,13 @@ +GLOBAL_MULTIPLE(protected_sentry_procs) +#define SET_PROTECTED_PROC(proc) GLOBAL_MULTIPLE_UPDATE(protected_sentry_procs, proc) + +GLOBAL_MULTIPLE(protected_sentry_datums) +#define SET_PROTECTED_DATUM(datum) GLOBAL_MULTIPLE_UPDATE(protected_sentry_datums, datum) + +GLOBAL_LIST_EMPTY(protected_config_entries) + #define GENERAL_PROTECT_DATUM(Path)\ +SET_PROTECTED_DATUM(Path)\ ##Path/can_vv_get(var_name){\ return FALSE;\ }\ diff --git a/code/__DEFINES/client.dm b/code/__DEFINES/client.dm index b335951aec0f..3ef997774bbf 100644 --- a/code/__DEFINES/client.dm +++ b/code/__DEFINES/client.dm @@ -8,6 +8,6 @@ /// This gathers all the client *procs* that we are pretending are verbs - but only particularly want /// authorized users to be able to use /client/proc/collect_client_verbs() as /list - CAN_BE_REDEFINED(TRUE); + CAN_BE_REDEFINED(TRUE) return list() diff --git a/code/__DEFINES/configuration.dm b/code/__DEFINES/configuration.dm index f0d64efb6dd7..749ec7b9380a 100644 --- a/code/__DEFINES/configuration.dm +++ b/code/__DEFINES/configuration.dm @@ -8,6 +8,8 @@ //flags #define CONFIG_ENTRY_LOCKED (1<<0) //can't edit #define CONFIG_ENTRY_HIDDEN (1<<1) //can't see value +#define CONFIG_ENTRY_SENSITIVE (1<<2) //scrubbed from public logging, if a list assumes value is sensitive +#define CONFIG_ENTRY_SENSITIVE_KEY (1<<3) //scrubbed from public logging, if a list assumes key is sensitive #define ON_CONFIG_LOAD(type) \ ##type/New() { \ diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 6c57aa62f2af..152b6d974afb 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -4,6 +4,9 @@ GLOBAL_PROTECT(admins) GLOBAL_LIST_EMPTY(directory) //all ckeys with associated client +GLOBAL_LIST_EMPTY(all_player_keys) +GLOBAL_LIST_EMPTY(all_player_cids) + GLOBAL_LIST_EMPTY(player_list) //all mobs **with clients attached**. GLOBAL_LIST_EMPTY(living_player_list) // all /mob/living with clients diff --git a/code/controllers/configuration/config_entry.dm b/code/controllers/configuration/config_entry.dm index 49dae4c2ff38..1fc830e84c1d 100644 --- a/code/controllers/configuration/config_entry.dm +++ b/code/controllers/configuration/config_entry.dm @@ -6,6 +6,8 @@ #define KEY_MODE_TYPE 1 #define KEY_MODE_TEXT_UNALTERED 2 +SET_PROTECTED_DATUM(/datum/config_entry) + /datum/config_entry var/name //read-only, this is determined by the last portion of the derived entry type var/config_entry_value diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm index b74275d2cee2..be0dd7c8d53b 100644 --- a/code/controllers/configuration/configuration.dm +++ b/code/controllers/configuration/configuration.dm @@ -1,3 +1,5 @@ +SET_PROTECTED_DATUM(/datum/controller/configuration) + /datum/controller/configuration name = "Configuration" @@ -162,6 +164,9 @@ _entries[esname] = E _entries_by_type[I] = E + if(E.protection & (CONFIG_ENTRY_SENSITIVE|CONFIG_ENTRY_SENSITIVE_KEY)) + GLOB.protected_config_entries += E + /datum/controller/configuration/proc/RemoveEntry(datum/config_entry/CE) entries -= CE.name diff --git a/code/controllers/configuration/entries/achievements.dm b/code/controllers/configuration/entries/achievements.dm index ca537860691f..036b6e4d1d21 100644 --- a/code/controllers/configuration/entries/achievements.dm +++ b/code/controllers/configuration/entries/achievements.dm @@ -1,10 +1,10 @@ /// The base URL for the achievements API endpoint /datum/config_entry/string/achievements_api_url - protection = CONFIG_ENTRY_HIDDEN + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_SENSITIVE /// The API key for authenticating with the achievements service /datum/config_entry/string/achievements_api_key - protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED|CONFIG_ENTRY_SENSITIVE /// Additional parameter passed to the backend service /datum/config_entry/string/achievements_instance diff --git a/code/controllers/configuration/entries/dbconfig.dm b/code/controllers/configuration/entries/dbconfig.dm index be4799988f3b..1cf195732a95 100644 --- a/code/controllers/configuration/entries/dbconfig.dm +++ b/code/controllers/configuration/entries/dbconfig.dm @@ -15,7 +15,7 @@ protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED /datum/config_entry/string/db_password - protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED|CONFIG_ENTRY_SENSITIVE /datum/config_entry/flag/db_debug_mode protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index 1fde1a7cef87..d8b00e50c51f 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -240,7 +240,7 @@ Administrative related. protection = CONFIG_ENTRY_LOCKED /datum/config_entry/string/tgs3_commandline_path - protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN + protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN | CONFIG_ENTRY_SENSITIVE config_entry_value = "C:\\Program Files (x86)\\TG Station Server\\TGCommandLine.exe" /datum/config_entry/number/minute_topic_limit @@ -375,14 +375,14 @@ or your package manager The default value assumes youtube-dl is in your system PATH */ /datum/config_entry/string/invoke_youtubedl - protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN + protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN | CONFIG_ENTRY_SENSITIVE /datum/config_entry/string/cobalt_base_api - protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN + protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN | CONFIG_ENTRY_SENSITIVE /datum/config_entry/string/cobalt_api_key - protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN + protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN | CONFIG_ENTRY_SENSITIVE /datum/config_entry/number/error_cooldown // The "cooldown" time for each occurrence of a unique error config_entry_value = 600 @@ -589,7 +589,7 @@ This maintains a list of ip addresses that are able to bypass topic filtering. /datum/config_entry/keyed_list/topic_tokens key_mode = KEY_MODE_TEXT value_mode = VALUE_MODE_TEXT - protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED|CONFIG_ENTRY_SENSITIVE_KEY /datum/config_entry/keyed_list/topic_tokens/ValidateListEntry(key_name, key_value) return key_value != "topic_token" && ..() @@ -627,7 +627,7 @@ This maintains a list of ip addresses that are able to bypass topic filtering. /datum/config_entry/string/redis_connection config_entry_value = "redis://127.0.0.1/" - protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED|CONFIG_ENTRY_SENSITIVE /datum/config_entry/string/instance_name config_entry_value = "game" @@ -724,9 +724,10 @@ This maintains a list of ip addresses that are able to bypass topic filtering. protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN /datum/config_entry/string/sentry_endpoint + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED|CONFIG_ENTRY_SENSITIVE /datum/config_entry/string/sentry_dsn - protection = CONFIG_ENTRY_HIDDEN + protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED|CONFIG_ENTRY_SENSITIVE /datum/config_entry/str_list/ignored_cids protection = CONFIG_ENTRY_LOCKED diff --git a/code/controllers/mc/globals.dm b/code/controllers/mc/globals.dm index 59b96c017d10..4b05f8d527ae 100644 --- a/code/controllers/mc/globals.dm +++ b/code/controllers/mc/globals.dm @@ -43,7 +43,7 @@ GLOBAL_REAL(GLOB, /datum/controller/global_vars) gvars_datum_protected_varlist = list(NAMEOF(src, gvars_datum_protected_varlist) = TRUE) var/list/global_procs = typesof(/datum/controller/global_vars/proc) var/expected_len = length(vars) - length(gvars_datum_in_built_vars) - if(length(global_procs) != expected_len) + if(length(global_procs) < expected_len) warning("Unable to detect all global initialization procs! Expected [expected_len] got [length(global_procs)]!") if(length(global_procs)) var/list/expected_global_procs = vars - gvars_datum_in_built_vars diff --git a/code/controllers/subsystem/cmtv.dm b/code/controllers/subsystem/cmtv.dm index 03104a886720..b84f064d2760 100644 --- a/code/controllers/subsystem/cmtv.dm +++ b/code/controllers/subsystem/cmtv.dm @@ -655,7 +655,7 @@ SUBSYSTEM_DEF(cmtv) protection = CONFIG_ENTRY_LOCKED /datum/config_entry/string/cmtv_api_key - protection = CONFIG_ENTRY_HIDDEN | CONFIG_ENTRY_LOCKED + protection = CONFIG_ENTRY_HIDDEN | CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_SENSITIVE /atom/movable/screen/cmtv plane = ESCAPE_MENU_PLANE diff --git a/code/controllers/subsystem/sentry.dm b/code/controllers/subsystem/sentry.dm index cd54ec39996a..5679f554aa80 100644 --- a/code/controllers/subsystem/sentry.dm +++ b/code/controllers/subsystem/sentry.dm @@ -19,6 +19,8 @@ SUBSYSTEM_DEF(sentry) can_fire = FALSE return SS_INIT_NO_NEED + return SS_INIT_SUCCESS + /datum/controller/subsystem/sentry/fire(resumed) var/static/list/headers = list( "Content-Type" = "application/x-sentry-envelope", @@ -37,6 +39,8 @@ SUBSYSTEM_DEF(sentry) if(!endpoint) endpoint = ENDPOINT_CONFIG + var/static/regex/ip_regex = regex(@"(((?!25?[6-9])[12]\d|[1-9])?\d\.?\b){4}", "g") + for(var/datum/error_envelope/error as anything in envelopes) var/event_id = get_uuid() @@ -46,12 +50,12 @@ SUBSYSTEM_DEF(sentry) for(var/datum/static_callee/called as anything in error.stacktrace) var/list/parsed_args = list( - "src" = called._src, - "usr" = called._usr, + "src" = isnull(called._src) ? "null" : called._src, + "usr" = isnull(called._usr) ? "null" : called._usr, ) var/index = 1 for(var/arg in called._args) - parsed_args["argument #[index]"] = arg + parsed_args["argument #[index]"] = isnull(arg) ? "null" : arg index++ var/pre_context, context, post_context @@ -72,16 +76,29 @@ SUBSYSTEM_DEF(sentry) var/procpath/proc_path = called.proc - stacktrace += list(list( + var/censor_args = FALSE + if(proc_path.type in GLOB.protected_sentry_procs) + censor_args = TRUE + + for(var/protected in GLOB.protected_sentry_datums) + if(findtext("[proc_path.type]", "[protected]")) + censor_args = TRUE + break + + var/to_add = list( "filename" = called.file, "function" = proc_path.type, "lineno" = called.line, - "vars" = parsed_args, "pre_context" = pre_context, "context_line" = context, "post_context" = post_context, "source_link" = "https://github.com/cmss13-devs/cmss13/blob/[git_revision]/[called.file]#L[called.line]" - )) + ) + + if(!censor_args) + to_add["vars"] = parsed_args + + stacktrace += list(to_add) var/list/event_parts = list( "event_id" = event_id, @@ -92,17 +109,41 @@ SUBSYSTEM_DEF(sentry) "round_id" = GLOB.round_id, ), "exception" = list( - "type" = error.error, - "value" = "Runtime Error", - "stacktrace" = list("frames" = stacktrace), + "values" = list(list( + "type" = error.error, + "value" = "Runtime Error", + "stacktrace" = list("frames" = stacktrace), + )) ), ) var/event = json_encode(event_parts) + + event = ip_regex.Replace(event, "ip address") + for(var/replacement in GLOB.all_player_keys) + event = replacetext(event, replacement, "player key") + event = replacetext(event, ckey(replacement), "player ckey") + + for(var/replacement in GLOB.all_player_cids) + event = replacetext(event, replacement, "player computer id") + + for(var/datum/config_entry/protected_entry in GLOB.protected_config_entries) + if(islist(protected_entry.config_entry_value)) + for(var/key, value in protected_entry.config_entry_value) + if(protected_entry.protection & CONFIG_ENTRY_SENSITIVE_KEY || isnull(value)) + event = replacetext(event, key, "config entry key [protected_entry.type]") + else + event = replacetext(event, value, "config entry value [protected_entry.type]") + else + if(length(protected_entry.config_entry_value)) + event = replacetext(event, protected_entry.config_entry_value, "config entry [protected_entry.type]") + var/event_header = "{\"type\":\"event\",\"length\":[length(event)]}" var/assembled = "[header]\n[event_header]\n[event]\n" - rustg_http_request_fire_and_forget(RUSTG_HTTP_METHOD_POST, endpoint, assembled, headers, null) + var/request = rustg_http_request_blocking(RUSTG_HTTP_METHOD_POST, endpoint, assembled, headers, null) + log_debug("SENTRY: REQUEST [request]") + log_debug("SENTRY: EVENT: [assembled]") envelopes.Cut() diff --git a/code/modules/admin/admin_ranks.dm b/code/modules/admin/admin_ranks.dm index ed59ea2fad01..34a0fc66c604 100644 --- a/code/modules/admin/admin_ranks.dm +++ b/code/modules/admin/admin_ranks.dm @@ -166,7 +166,7 @@ GLOBAL_LIST_EMPTY(admin_ranks) //list of all ranks with associated rights protection = CONFIG_ENTRY_LOCKED /datum/config_entry/string/cmdb_api_key - protection = CONFIG_ENTRY_HIDDEN | CONFIG_ENTRY_LOCKED + protection = CONFIG_ENTRY_HIDDEN | CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_SENSITIVE /** * Using the API backed admins/admin_ranks requires a response from the endpoint following this schema: diff --git a/code/modules/admin/tabs/admin_tab.dm b/code/modules/admin/tabs/admin_tab.dm index 16af60f48d5e..7b6a74449abb 100644 --- a/code/modules/admin/tabs/admin_tab.dm +++ b/code/modules/admin/tabs/admin_tab.dm @@ -258,6 +258,7 @@ cmd_admin_say(msg) +SET_PROTECTED_PROC(/client/proc/cmd_admin_say) /client/proc/cmd_admin_say(msg as text) set name = "Asay" //Gave this shit a shorter name so you only have to time out "asay" rather than "admin say" to use it --NeoFite set category = "Admin" @@ -386,6 +387,7 @@ var/msg = input(src, null, "asay \"text\"") as text|null cmd_admin_say(msg) +SET_PROTECTED_PROC(/client/proc/cmd_mentor_say) /client/proc/cmd_mentor_say(msg as text) set name = "MentorSay" set category = "Admin.Mentor" diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm index 935e1a5a2a68..1ad555c40590 100644 --- a/code/modules/admin/verbs/adminhelp.dm +++ b/code/modules/admin/verbs/adminhelp.dm @@ -163,6 +163,8 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) #define WEBHOOK_URGENT 1 #define WEBHOOK_NON_URGENT 2 +SET_PROTECTED_DATUM(/datum/admin_help) + /** * # Adminhelp Ticket */ @@ -804,6 +806,8 @@ GLOBAL_DATUM_INIT(ahelp_tickets, /datum/admin_help_tickets, new) GLOBAL_DATUM_INIT(admin_help_ui_handler, /datum/admin_help_ui_handler, new) +SET_PROTECTED_DATUM(/datum/admin_help_ui_handler) + /datum/admin_help_ui_handler var/list/ahelp_cooldowns = list() diff --git a/code/modules/admin/verbs/adminpm.dm b/code/modules/admin/verbs/adminpm.dm index 2d3513510c5d..5d05c9fce24d 100644 --- a/code/modules/admin/verbs/adminpm.dm +++ b/code/modules/admin/verbs/adminpm.dm @@ -97,6 +97,7 @@ return cmd_admin_pm(whom, msg) +SET_PROTECTED_PROC(/client/proc/cmd_admin_pm) //takes input from cmd_admin_pm_context, cmd_admin_pm_panel or /client/Topic and sends them a PM. //Fetching a message if needed. src is the sender and C is the target client /client/proc/cmd_admin_pm(whom, msg) diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 68b997128ef4..4e0a810d15f7 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -553,6 +553,9 @@ GLOBAL_LIST_INIT(whitelisted_client_procs, list( SEND_GLOBAL_SIGNAL(COMSIG_GLOB_CLIENT_LOGGED_IN, src) SEND_SIGNAL(src, COMSIG_CLIENT_LOGGED_IN) + GLOB.all_player_keys |= key + GLOB.all_player_cids |= computer_id + if(CONFIG_GET(flag/ooc_country_flags)) spawn if(src) ip2country(address, src)