diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 96335a3c1acf..47aa0e732c76 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -146,8 +146,9 @@ #define SS_INIT_DATABASE -27 #define SS_INIT_ENTITYMANAGER -28 #define SS_INIT_PLAYTIME -29 -#define SS_INIT_PREDSHIPS -30 -#define SS_INIT_OBJECTIVES -31 +#define SS_INIT_STICKY -30 +#define SS_INIT_PREDSHIPS -31 +#define SS_INIT_OBJECTIVES -32 #define SS_INIT_MINIMAP -34 #define SS_INIT_STATPANELS -98 #define SS_INIT_CHAT -100 //Should be last to ensure chat remains smooth during init. diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm index eb1b0540fb54..83929ecf8803 100644 --- a/code/controllers/configuration/entries/general.dm +++ b/code/controllers/configuration/entries/general.dm @@ -531,6 +531,8 @@ This maintains a list of ip addresses that are able to bypass topic filtering. /datum/config_entry/string/round_results_webhook_url +/datum/config_entry/string/important_log_channel + /// InfluxDB v2 Host to connect to for sending statistics (over HTTP API) /datum/config_entry/string/influxdb_host /// InfluxDB v2 Bucket to send staistics to diff --git a/code/controllers/subsystem/stickyban.dm b/code/controllers/subsystem/stickyban.dm new file mode 100644 index 000000000000..48e934addc1a --- /dev/null +++ b/code/controllers/subsystem/stickyban.dm @@ -0,0 +1,284 @@ +SUBSYSTEM_DEF(stickyban) + name = "Sticky Ban" + init_order = SS_INIT_STICKY + flags = SS_NO_FIRE + +/datum/controller/subsystem/stickyban/Initialize() + var/list/all_bans = world.GetConfig("ban") + + for(var/existing_ban in all_bans) + var/list/ban_data = params2list(world.GetConfig("ban", existing_ban)) + INVOKE_ASYNC(src, PROC_REF(import_sticky), existing_ban, ban_data) + + return SS_INIT_SUCCESS + +/** + * Returns a list of [/datum/view_record/stickyban]s, or null, if no stickybans are found. All arguments are optional, but you should pass at least one if you want any results. + */ +/datum/controller/subsystem/stickyban/proc/check_for_sticky_ban(ckey, address, computer_id) + var/list/stickyban_ids = list() + + for(var/datum/view_record/stickyban_matched_ckey/matched_ckey as anything in get_impacted_ckey_records(ckey)) + stickyban_ids += matched_ckey.linked_stickyban + + for(var/datum/view_record/stickyban_matched_cid/matched_cid as anything in get_impacted_cid_records(computer_id)) + stickyban_ids += matched_cid.linked_stickyban + + for(var/datum/view_record/stickyban_matched_ip/matched_ip as anything in get_impacted_ip_records(address)) + stickyban_ids += matched_ip.linked_stickyban + + if(!length(stickyban_ids)) + return FALSE + + var/list/datum/view_record/stickyban/stickies = DB_VIEW(/datum/view_record/stickyban, + DB_AND( + DB_COMP("id", DB_IN, stickyban_ids), + DB_COMP("active", DB_EQUALS, TRUE) + ) + ) + + for(var/datum/view_record/stickyban/current_sticky in stickies) + if(length(get_whitelisted_ckey_records(current_sticky.id, ckey))) + stickies -= current_sticky + + if(!length(stickies)) + return FALSE + + return stickies + +/** + * Associates an existing stickyban with a new match, either of a ckey, address, or computer_id. Or all three. + * + * Arguments: + * - existing_ban_id, int, required + * - ckey, string, optional + * - address, string, optional + * - computer_id, string, optional + */ +/datum/controller/subsystem/stickyban/proc/match_sticky(existing_ban_id, ckey, address, computer_id) + if(!existing_ban_id) + return + + if(ckey) + add_matched_ckey(existing_ban_id, ckey) + + if(address) + add_matched_ip(existing_ban_id, address) + + if(computer_id) + add_matched_cid(existing_ban_id, computer_id) + +/** + * Adds a new tracked stickyban, and returns a [/datum/entity/stickyban] if it was successful. Blocking, sleeps. + */ +/datum/controller/subsystem/stickyban/proc/add_stickyban(identifier, reason, message, datum/entity/player/banning_admin, override_date) + var/datum/entity/stickyban/new_sticky = DB_ENTITY(/datum/entity/stickyban) + new_sticky.identifier = identifier + new_sticky.reason = reason + new_sticky.message = message + + if(banning_admin) + new_sticky.adminid = banning_admin.id + + new_sticky.date = override_date ? override_date : "[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]" + new_sticky.save() + new_sticky.sync() + + return new_sticky + +/// Adds a ckey match to the specified sticky ban. +/datum/controller/subsystem/stickyban/proc/add_matched_ckey(existing_ban_id, key) + key = ckey(key) + + if(length(DB_VIEW(/datum/view_record/stickyban_matched_ckey, + DB_AND( + DB_COMP("linked_stickyban", DB_EQUALS, existing_ban_id), + DB_COMP("ckey", DB_EQUALS, key) + ) + ))) + return + + var/datum/entity/stickyban_matched_ckey/matched_ckey = DB_ENTITY(/datum/entity/stickyban_matched_ckey) + + matched_ckey.ckey = key + matched_ckey.linked_stickyban = existing_ban_id + + matched_ckey.save() + +/// Adds an IP match to the specified stickyban. +/datum/controller/subsystem/stickyban/proc/add_matched_ip(existing_ban_id, ip) + if(length(DB_VIEW(/datum/view_record/stickyban_matched_ip, + DB_AND( + DB_COMP("linked_stickyban", DB_EQUALS, existing_ban_id), + DB_COMP("ip", DB_EQUALS, ip) + ) + ))) + return + + var/datum/entity/stickyban_matched_ip/matched_ip = DB_ENTITY(/datum/entity/stickyban_matched_ip) + + matched_ip.ip = ip + matched_ip.linked_stickyban = existing_ban_id + + matched_ip.save() + +/// Adds a CID match to the specified stickyban. +/datum/controller/subsystem/stickyban/proc/add_matched_cid(existing_ban_id, cid) + if(length(DB_VIEW(/datum/view_record/stickyban_matched_cid, + DB_AND( + DB_COMP("linked_stickyban", DB_EQUALS, existing_ban_id), + DB_COMP("cid", DB_EQUALS, cid) + ) + ))) + return + + + var/datum/entity/stickyban_matched_cid/matched_cid = DB_ENTITY(/datum/entity/stickyban_matched_cid) + + matched_cid.cid = cid + matched_cid.linked_stickyban = existing_ban_id + + matched_cid.save() + +/// Whitelists a specific CKEY to the specified stickyban, which will allow connection, even with matching CIDs and IPs. +/datum/controller/subsystem/stickyban/proc/whitelist_ckey(existing_ban_id, key) + key = ckey(key) + + if(!key) + return + + var/id_to_select + + var/list/datum/view_record/stickyban_matched_ckey/existing_matches = DB_VIEW(/datum/view_record/stickyban_matched_ckey, + DB_AND( + DB_COMP("linked_stickyban", DB_EQUALS, existing_ban_id), + DB_COMP("ckey", DB_EQUALS, key) + ) + ) + + if(length(existing_matches)) + var/datum/view_record/stickyban_matched_ckey/match = existing_matches[1] + id_to_select = match.id + + var/datum/entity/stickyban_matched_ckey/whitelisted_ckey = DB_ENTITY(/datum/entity/stickyban_matched_ckey, id_to_select) + + whitelisted_ckey.ckey = key + whitelisted_ckey.linked_stickyban = existing_ban_id + whitelisted_ckey.whitelisted = TRUE + + whitelisted_ckey.save() + +/** + * Returns a [/list] of [/datum/view_record/stickyban_matched_ckey] where the ckey provided has not been + * whitelisted from the stickyban, and would be prevented from joining - provided that the stickyban itself + * remains active. + */ +/datum/controller/subsystem/stickyban/proc/get_impacted_ckey_records(key) + key = ckey(key) + + return DB_VIEW(/datum/view_record/stickyban_matched_ckey, + DB_AND( + DB_COMP("ckey", DB_EQUALS, key), + DB_COMP("whitelisted", DB_EQUALS, FALSE) + ) + ) + +/** + * Returns a [/list] of [/datum/view_record/stickyban_matched_ckey] which have been manually whitelisted by an admin and matches the provided existing_ban_id and key. + */ +/datum/controller/subsystem/stickyban/proc/get_whitelisted_ckey_records(existing_ban_id, key) + key = ckey(key) + + return DB_VIEW(/datum/view_record/stickyban_matched_ckey, + DB_AND( + DB_COMP("linked_stickyban", DB_EQUALS, existing_ban_id), + DB_COMP("ckey", DB_EQUALS, key), + DB_COMP("whitelisted", DB_EQUALS, TRUE), + ) + ) + +/** + * Returns a [/list] of [/datum/view_record/stickyban_matched_cid] where the impacted CID matches the CID provided. + * Connections matching this CID will be blocked - provided the linked stickyban is active. + */ +/datum/controller/subsystem/stickyban/proc/get_impacted_cid_records(cid) + return DB_VIEW(/datum/view_record/stickyban_matched_cid, + DB_COMP("cid", DB_EQUALS, cid) + ) + +/** + * Returns a [/list] of [/datum/view_record/stickyban_matched_ip] where the impacted IP matches the IP provided. + * Connections matchin this IP will be blocked - provided the linked stickyban is active. + */ +/datum/controller/subsystem/stickyban/proc/get_impacted_ip_records(ip) + return DB_VIEW(/datum/view_record/stickyban_matched_ip, + DB_COMP("ip", DB_EQUALS, ip) + ) + +/// Legacy import from pager bans to database bans. +/datum/controller/subsystem/stickyban/proc/import_sticky(identifier, list/ban_data) + WAIT_DB_READY + + if(ban_data["type"] != "sticky") + handle_old_perma(identifier, ban_data) + return + + if(!ban_data["message"]) + ban_data["message"] = "Evasion" + + add_stickyban(identifier, ban_data["reason"], ban_data["message"], override_date = "LEGACY") + +/** + * We abuse the on_insert from ndatabase here to ensure we have the synced ID of the new stickyban when applying a *lot* of associated bans. If we don't have a matching pager ban with the new sticky's identifier, we stop. + */ +/datum/entity_meta/stickyban/on_insert(datum/entity/stickyban/new_sticky) + var/list/ban_data = params2list(world.GetConfig("ban", new_sticky.identifier)) + + if(!length(ban_data)) + return + + var/list/whitelisted = list() + if(ban_data["whitelist"]) + whitelisted = splittext(ban_data["whitelist"], ",") + for(var/key in whitelisted) + SSstickyban.whitelist_ckey(new_sticky.id, key) + + if(ban_data["keys"]) + var/list/keys = splittext(ban_data["keys"], ",") + keys -= whitelisted + for(var/key in keys) + SSstickyban.add_matched_ckey(new_sticky.id, key) + + if(ban_data["computer_id"]) + var/list/cids = splittext(ban_data["computer_id"], ",") + for(var/cid in cids) + SSstickyban.add_matched_cid(new_sticky.id, cid) + + if(ban_data["IP"]) + var/list/ips = splittext(ban_data["IP"], ",") + for(var/ip in ips) + SSstickyban.add_matched_ip(new_sticky.id, ip) + + world.SetConfig("ban", new_sticky.identifier, null) + +/// Imports permabans from the old ban.txt, and does *not* ban people that have been whitelisted. +/datum/controller/subsystem/stickyban/proc/handle_old_perma(identifier, list/ban_data) + var/list/keys_to_ban = list() + + keys_to_ban += splittext(ban_data["keys"], ",") + + for(var/x in 1 to length(keys_to_ban)) + keys_to_ban[x] = ckey(keys_to_ban[x]) + + var/list/keys = splittext(ban_data["whitelist"], ",") + for(var/key in keys) + keys_to_ban -= ckey(key) + + for(var/key in keys_to_ban) + var/datum/entity/player/player_entity = get_player_from_key(key) + if(!player_entity) + continue + + INVOKE_ASYNC(player_entity, TYPE_PROC_REF(/datum/entity/player, add_perma_ban), ban_data["message"]) + + world.SetConfig("ban", identifier, null) diff --git a/code/datums/entities/player.dm b/code/datums/entities/player.dm index 2973a174858f..f0b601652fe0 100644 --- a/code/datums/entities/player.dm +++ b/code/datums/entities/player.dm @@ -305,6 +305,36 @@ BSQL_PROTECT_DATUM(/datum/entity/player) return TRUE +/// Permanently bans this user, with the provided reason. The banner ([/datum/entity/player]) argument is optional, as this can be done without admin intervention. +/datum/entity/player/proc/add_perma_ban(reason, internal_reason, datum/entity/player/banner) + if(is_permabanned) + return FALSE + + is_permabanned = TRUE + permaban_date = "[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]" + permaban_reason = reason + + if(banner) + permaban_admin_id = banner.id + message_admins("[key_name_admin(banner.owning_client)] has permanently banned [ckey] for '[reason]'.") + var/datum/tgs_chat_embed/field/reason_embed + if(internal_reason) + reason_embed = new("Permaban Reason", internal_reason) + important_message_external("[banner.owning_client] has permanently banned [ckey] for '[reason]'.", "Permaban Placed", reason_embed ? list(reason_embed) : null) + + add_note("Permanently banned | [reason]", FALSE, NOTE_ADMIN, TRUE) + if(internal_reason) + add_note("Internal reason: [internal_reason]", TRUE, NOTE_ADMIN) + + if(owning_client) + to_chat_forced(owning_client, SPAN_LARGE("You have been permanently banned by [banner.ckey].\nReason: [reason].")) + to_chat_forced(owning_client, SPAN_LARGE("This is a permanent ban. It will not be removed.")) + QDEL_NULL(owning_client) + + save() + + return TRUE + /datum/entity/player/proc/auto_unban() if(!is_time_banned) return @@ -447,54 +477,45 @@ BSQL_PROTECT_DATUM(/datum/entity/player) record_login_triplet(player.ckey, address, computer_id) player_data.sync() -/datum/entity/player/proc/check_ban(computer_id, address) +/datum/entity/player/proc/check_ban(computer_id, address, is_telemetry) . = list() - var/list/linked_bans = check_for_sticky_ban(address, computer_id) - if(islist(linked_bans)) - var/datum/view_record/stickyban_list_view/SLW = LAZYACCESS(linked_bans, 1) - if(SLW) - var/reason = "" - - if(SLW.address == address) - reason += "IP Address Matches; " - if(SLW.computer_id == computer_id) - reason += "CID Matches; " - if(SLW.ckey == ckey) - reason += "Ckey Matches; " - - var/source_id = SLW.linked_stickyban - var/source_reason = SLW.linked_reason - var/source_ckey = SLW.linked_ckey - if(!source_id) - source_id = "[SLW.entry_id]" - source_reason = SLW.reason - source_ckey = SLW.ckey - - log_access("Failed Login: [ckey] [last_known_cid] [last_known_ip] - Stickybanned (Linked to [source_ckey]; Reason: [source_reason])") - message_admins("Failed Login: [ckey] (IP: [last_known_ip], CID: [last_known_cid]) - Stickybanned (Linked to ckey [source_ckey]; Reason: [source_reason])") - - DB_FILTER(/datum/entity/player_sticky_ban, - DB_AND( - DB_COMP("ckey", DB_EQUALS, ckey), - DB_COMP("address", DB_EQUALS, address), - DB_COMP("computer_id", DB_EQUALS, computer_id) - ), CALLBACK(src, PROC_REF(process_stickyban), address, computer_id, source_id, reason, null)) - - .["desc"] = "\nReason: Stickybanned\nExpires: PERMANENT" - .["reason"] = "ckey/id" - return . + var/list/datum/view_record/stickyban/all_stickies = SSstickyban.check_for_sticky_ban(ckey, address, computer_id) + + if(length(all_stickies)) + var/datum/view_record/stickyban/sticky = all_stickies[1] + + if(!is_telemetry) + log_access("Failed Login: [ckey] [last_known_cid] [last_known_ip] - Stickybanned (Reason: [sticky.reason])") + message_admins("Failed Login: [ckey] (IP: [last_known_ip], CID: [last_known_cid]) - Stickybanned (Reason: [sticky.reason])") + + var/appeal + if(CONFIG_GET(string/banappeals)) + appeal = "\nFor more information on your ban, or to appeal, head to [CONFIG_GET(string/banappeals)]" + + .["desc"] = "\nReason: Stickybanned - [sticky.message] Identifier: [sticky.identifier]\n[appeal]" + .["reason"] = "ckey/id" + + if(!is_telemetry) + SSstickyban.match_sticky(sticky.id, ckey, address, computer_id) + return + if(!is_time_banned && !is_permabanned) return null + var/appeal if(CONFIG_GET(string/banappeals)) appeal = "\nFor more information on your ban, or to appeal, head to [CONFIG_GET(string/banappeals)]" if(is_permabanned) - permaban_admin.sync() - log_access("Failed Login: [ckey] [last_known_cid] [last_known_ip] - Banned [permaban_reason]") - message_admins("Failed Login: [ckey] id:[last_known_cid] ip:[last_known_ip] - Banned [permaban_reason]") - .["desc"] = "\nReason: [permaban_reason]\nExpires: PERMANENT\nBy: [permaban_admin.ckey][appeal]" + var/banner = "Host" + if(permaban_admin_id) + var/datum/view_record/players/banning_admin = locate() in DB_VIEW(/datum/view_record/players, DB_COMP("id", DB_EQUALS, permaban_admin_id)) + banner = banning_admin.ckey + if(!is_telemetry) + log_access("Failed Login: [ckey] [last_known_cid] [last_known_ip] - Banned [permaban_reason]") + message_admins("Failed Login: [ckey] id:[last_known_cid] ip:[last_known_ip] - Banned [permaban_reason]") + .["desc"] = "\nReason: [permaban_reason]\nExpires: PERMANENT\nBy: [banner][appeal]" .["reason"] = "ckey/id" return . if(is_time_banned) @@ -509,8 +530,9 @@ BSQL_PROTECT_DATUM(/datum/entity/player) timeleftstring = "[round(time_left / 60, 0.1)] Hours" else timeleftstring = "[time_left] Minutes" - log_access("Failed Login: [ckey] [last_known_cid] [last_known_ip] - Banned [time_ban_reason]") - message_admins("Failed Login: [ckey] id:[last_known_cid] ip:[last_known_ip] - Banned [time_ban_reason]") + if(!is_telemetry) + log_access("Failed Login: [ckey] [last_known_cid] [last_known_ip] - Banned [time_ban_reason]") + message_admins("Failed Login: [ckey] id:[last_known_cid] ip:[last_known_ip] - Banned [time_ban_reason]") .["desc"] = "\nReason: [time_ban_reason]\nExpires: [timeleftstring]\nBy: [time_ban_admin.ckey][appeal]" .["reason"] = "ckey/id" return . @@ -681,7 +703,6 @@ BSQL_PROTECT_DATUM(/datum/entity/player) parent_entity = /datum/entity/player child_entity = /datum/entity/player child_field = "permaban_admin_id" - parent_name = "permabanning_admin" /datum/view_record/players diff --git a/code/datums/entities/player_sticky_ban.dm b/code/datums/entities/player_sticky_ban.dm index d79befddb04e..752334e8e001 100644 --- a/code/datums/entities/player_sticky_ban.dm +++ b/code/datums/entities/player_sticky_ban.dm @@ -1,94 +1,133 @@ -/datum/entity/player_sticky_ban - var/player_id - var/admin_id +BSQL_PROTECT_DATUM(/datum/entity/stickyban) + +/datum/entity/stickyban + var/identifier var/reason + var/message var/date - var/ckey - var/address - var/computer_id - - var/linked_stickyban - -BSQL_PROTECT_DATUM(/datum/entity/player_sticky_ban) + var/active = TRUE + var/adminid -/datum/entity_meta/player_sticky_ban - entity_type = /datum/entity/player_sticky_ban - table_name = "player_sticky_bans" +/datum/entity_meta/stickyban + entity_type = /datum/entity/stickyban + table_name = "stickyban" field_types = list( - "player_id"=DB_FIELDTYPE_BIGINT, - "admin_id"=DB_FIELDTYPE_BIGINT, - "reason"=DB_FIELDTYPE_STRING_MAX, - "date"=DB_FIELDTYPE_STRING_LARGE, - "address"=DB_FIELDTYPE_STRING_LARGE, - "ckey" = DB_FIELDTYPE_STRING_LARGE, - "computer_id"=DB_FIELDTYPE_STRING_LARGE, - "linked_stickyban"=DB_FIELDTYPE_BIGINT, + "identifier" = DB_FIELDTYPE_STRING_LARGE, + "reason" = DB_FIELDTYPE_STRING_LARGE, + "message" = DB_FIELDTYPE_STRING_LARGE, + "date" = DB_FIELDTYPE_STRING_LARGE, + "active" = DB_FIELDTYPE_INT, + "adminid" = DB_FIELDTYPE_BIGINT, ) +/datum/view_record/stickyban + var/id + var/identifier + var/reason + var/message + var/date + var/active + var/admin -/datum/entity_link/linked_sticky_bans - parent_entity = /datum/entity/player_sticky_ban - child_entity = /datum/entity/player_sticky_ban - child_field = "linked_stickyban" - - parent_name = "linked_ban" - child_name = "linked_bans" - -/datum/entity_link/player_to_player_sticky_bans - parent_entity = /datum/entity/player - child_entity = /datum/entity/player_sticky_ban - child_field = "player_id" - - parent_name = "player" - child_name = "stickybans" +/datum/entity_view_meta/stickyban + root_record_type = /datum/entity/stickyban + destination_entity = /datum/view_record/stickyban + fields = list( + "id", + "identifier", + "reason", + "message", + "date", + "active", + "admin" = DB_CASE(DB_COMP("adminid", DB_ISNOT), "stickybanning_admin.ckey", DB_CONST("AdminBot")) + ) -/datum/entity_link/admin_to_player_sticky_bans +/datum/entity_link/stickyban_to_banning_admin parent_entity = /datum/entity/player - child_entity = /datum/entity/player_sticky_ban - child_field = "admin_id" + child_entity = /datum/entity/stickyban + child_field = "adminid" + parent_name = "stickybanning_admin" - parent_name = "admin" +/datum/entity/stickyban_matched_ckey + var/ckey + var/linked_stickyban + var/whitelisted = FALSE -/datum/view_record/stickyban_list_view - var/entry_id - var/player_id - var/admin_id +/datum/entity_meta/stickyban_matched_ckey + entity_type = /datum/entity/stickyban_matched_ckey + table_name = "stickyban_matched_ckey" + field_types = list( + "ckey" = DB_FIELDTYPE_STRING_LARGE, + "linked_stickyban" = DB_FIELDTYPE_BIGINT, + "whitelisted" = DB_FIELDTYPE_INT, + ) - var/reason - var/date - var/address - var/computer_id +/datum/view_record/stickyban_matched_ckey + var/id var/ckey + var/linked_stickyban var/whitelisted +/datum/entity_view_meta/stickyban_matched_ckey + root_record_type = /datum/entity/stickyban_matched_ckey + destination_entity = /datum/view_record/stickyban_matched_ckey + fields = list( + "id", + "ckey", + "linked_stickyban", + "whitelisted", + ) + + +/datum/entity/stickyban_matched_cid + var/cid var/linked_stickyban - var/linked_ckey - var/linked_reason - var/admin_ckey - var/linked_admin_ckey +/datum/entity_meta/stickyban_matched_cid + entity_type = /datum/entity/stickyban_matched_cid + table_name = "stickyban_matched_cid" + field_types = list( + "cid" = DB_FIELDTYPE_STRING_LARGE, + "linked_stickyban" = DB_FIELDTYPE_BIGINT, + ) +/datum/view_record/stickyban_matched_cid + var/id + var/cid + var/linked_stickyban -/datum/entity_view_meta/stickyban_list_view - root_record_type = /datum/entity/player_sticky_ban - destination_entity = /datum/view_record/stickyban_list_view +/datum/entity_view_meta/stickyban_matched_cid + root_record_type = /datum/entity/stickyban_matched_cid + destination_entity = /datum/view_record/stickyban_matched_cid fields = list( - "entry_id" = "id", - "player_id", - "admin_id", + "id", + "cid", + "linked_stickyban", + ) - "reason", - "date", - "address", - "computer_id", - "ckey" = "player.ckey", - "whitelisted" = "player.stickyban_whitelisted", - "linked_stickyban", - "linked_ckey" = "linked_ban.player.ckey", - "linked_reason" = "linked_ban.reason", +/datum/entity/stickyban_matched_ip + var/ip + var/linked_stickyban - "admin_ckey" = "admin.ckey", - "linked_admin_ckey" = "linked_ban.admin.ckey" +/datum/entity_meta/stickyban_matched_ip + entity_type = /datum/entity/stickyban_matched_ip + table_name = "stickyban_matched_ip" + field_types = list( + "ip" = DB_FIELDTYPE_STRING_LARGE, + "linked_stickyban" = DB_FIELDTYPE_BIGINT, + ) + +/datum/view_record/stickyban_matched_ip + var/id + var/ip + var/linked_stickyban + +/datum/entity_view_meta/stickyban_matched_ip + root_record_type = /datum/entity/stickyban_matched_ip + destination_entity = /datum/view_record/stickyban_matched_ip + fields = list( + "id", + "ip", + "linked_stickyban", ) - order_by = list("entry_id" = DB_ORDER_BY_DESC) diff --git a/code/defines/procs/admin.dm b/code/defines/procs/admin.dm index 1e4f02e95cc0..d48c02127ea9 100644 --- a/code/defines/procs/admin.dm +++ b/code/defines/procs/admin.dm @@ -1,3 +1,15 @@ -/proc/log_and_message_admins(message as text) - log_admin("[key_name(usr)] [message]") - message_admins("[key_name(usr)] [message]") +/proc/important_message_external(message, title, list/datum/tgs_chat_embed/field/fields) + if(CONFIG_GET(string/important_log_channel)) + var/datum/tgs_message_content/to_send = new("") + + var/datum/tgs_chat_embed/structure/embed = new() + embed.title = title ? title : "Important Log" + embed.description = message + embed.timestamp = time2text(world.timeofday, "YYYY-MM-DD hh:mm:ss") + embed.colour = "#ED2939" + if(length(fields)) + embed.fields = fields + + to_send.embed = embed + + send2chat(to_send, CONFIG_GET(string/important_log_channel)) diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index 4a7307b247a5..85a1028c2296 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -1,6 +1,6 @@ #ifndef OVERRIDE_BAN_SYSTEM //Blocks an attempt to connect before even creating our client datum thing. -/world/IsBanned(key,address,computer_id, type, real_bans_only=FALSE) +/world/IsBanned(key,address,computer_id, type, real_bans_only=FALSE, is_telemetry = FALSE) var/ckey = ckey(key) // This is added siliently. Thanks to MSO for this fix. You will see it when/if we go OS @@ -28,11 +28,7 @@ var/datum/entity/player/P = get_player_from_key(ckey) - . = P.check_ban(computer_id, address) - if(.) - return . - - return ..() //default pager ban stuff + . = P.check_ban(computer_id, address, is_telemetry) #endif diff --git a/code/modules/admin/NewBan.dm b/code/modules/admin/NewBan.dm index 7dca354129ff..f4394738fb2d 100644 --- a/code/modules/admin/NewBan.dm +++ b/code/modules/admin/NewBan.dm @@ -180,15 +180,44 @@ GLOBAL_DATUM(Banlist, /savefile) expiry = "Removal Pending" else expiry = "Permaban" - var/unban_link = "(U)" + var/unban_link + if(ban.is_permabanned) + unban_link = "(UP)" + else + unban_link = "(UT)" - dat += "[unban_link] Key: [ban.ckey]ComputerID: [ban.last_known_cid]IP: [ban.last_known_ip] [expiry](By: [ban.admin])(Reason: [ban.reason])" + dat += "[unban_link] Key: [ban.ckey]ComputerID: [ban.last_known_cid]IP: [ban.last_known_ip] [expiry](By: [ban.admin ? ban.admin : "AdminBot"])(Reason: [ban.reason])" dat += "" - var/dat_header = "
Bans: (U) = Unban" + var/dat_header = "
Bans: (UP) = Unban Perma (UT) = Unban Timed" dat_header += " - Ban Listing
[dat]" show_browser(usr, dat_header, "Unban Panel", "unbanp", "size=875x400") +/datum/admins/proc/stickypanel() + var/add_sticky = "Add Sticky Ban" + var/find_sticky = "Find Sticky Ban" + + var/data = "
Sticky Bans: [add_sticky] [find_sticky]
" + + var/list/datum/view_record/stickyban/stickies = DB_VIEW(/datum/view_record/stickyban, + DB_COMP("active", DB_EQUALS, TRUE) + ) + + for(var/datum/view_record/stickyban/current_sticky in stickies) + var/whitelist_link = "(WHITELIST)" + var/remove_sticky_link = "(REMOVE)" + var/add_to_sticky_link = "(ADD)" + + var/impacted_ckey_link = "CKEYs" + var/impacted_ip_link = "IPs" + var/impacted_cid_link = "CIDs" + + data += "" + + data += "
[whitelist_link][remove_sticky_link][add_to_sticky_link]Identifier: [current_sticky.identifier]Reason: [current_sticky.reason]Message: [current_sticky.message] Admin: [current_sticky.admin] View: [impacted_ckey_link][impacted_ip_link][impacted_cid_link]
" + + show_browser(owner, data, "Stickyban Panel", "sticky", "size=875x400") + //////////////////////////////////// DEBUG //////////////////////////////////// /proc/CreateBans() @@ -251,3 +280,48 @@ GLOBAL_DATUM(Banlist, /savefile) if(P.is_time_banned && alert(usr, "Ban already exists. Proceed?", "Confirmation", "Yes", "No") != "Yes") return P.add_timed_ban(reason, mins) + +/client/proc/cmd_admin_do_stickyban(identifier, reason, message, list/impacted_ckeys, list/impacted_cids, list/impacted_ips) + if(!identifier) + identifier = tgui_input_text(src, "Name of the primary CKEY you are adding a stickyban to.", "BuildABan") + if(!identifier) + return + + if(!message) + message = tgui_input_text(src, "What message should be given to the impacted users?", "BuildABan", encode = FALSE) + if(!message) + return + + if(!reason) + reason = tgui_input_text(src, "What's the reason for the ban? This is shown internally, and not displayed in public notes and ban messages. Include as much detail as necessary.", "BuildABan", multiline = TRUE, encode = FALSE) + if(!reason) + return + + if(!length(impacted_ckeys)) + impacted_ckeys = splittext(tgui_input_text(src, "Which CKEYs should be impacted by this ban? Include the primary ckey, separated by semicolons.", "BuildABan", "player1;player2;player3"), ";") + + if(!length(impacted_cids)) + impacted_cids = splittext(tgui_input_text(src, "Which CIDs should be impacted by this ban? Separate with semicolons.", "BuildABan", "12345678;87654321"), ";") + + if(!length(impacted_ips)) + impacted_ips = splittext(tgui_input_text(src, "Which IPs should be impacted by this ban? Separate with semicolons.", "BuildABan", "1.1.1.1;8.8.8.8"), ";") + + var/datum/entity/stickyban/new_sticky = SSstickyban.add_stickyban(identifier, reason, message, player_data) + + if(!new_sticky) + to_chat(src, SPAN_ADMIN("Failed to apply stickyban.")) + return + + for(var/ckey in impacted_ckeys) + SSstickyban.add_matched_ckey(new_sticky.id, ckey) + + for(var/cid in impacted_cids) + SSstickyban.add_matched_cid(new_sticky.id, cid) + + for(var/ip in impacted_ips) + SSstickyban.add_matched_ip(new_sticky.id, ip) + + log_admin("STICKYBAN: Identifier: [identifier] Reason: [reason] Message: [message] CKEYs: [english_list(impacted_ckeys)] IPs: [english_list(impacted_ips)] CIDs: [english_list(impacted_cids)]") + message_admins("[key_name_admin(src)] has added a new stickyban with the identifier '[identifier]'.") + var/datum/tgs_chat_embed/field/reason_embed = new("Stickyban Reason", reason) + important_message_external("[src] has added a new stickyban with the identifier '[identifier]'.", "Stickyban Placed", list(reason_embed)) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index a022a1888274..e5fd014e5706 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -97,8 +97,9 @@ GLOBAL_LIST_INIT(admin_verbs_admin, list( )) GLOBAL_LIST_INIT(admin_verbs_ban, list( - /client/proc/unban_panel - // /client/proc/jobbans // Disabled temporarily due to 15-30 second lag spikes. Don't forget the comma in the line above when uncommenting this! + /client/proc/unban_panel, + /client/proc/stickyban_panel, + // /client/proc/jobbans // Disabled temporarily due to 15-30 second lag spikes. )) GLOBAL_LIST_INIT(admin_verbs_sounds, list( diff --git a/code/modules/admin/player_panel/actions/punish.dm b/code/modules/admin/player_panel/actions/punish.dm index 576de30ae7ff..eb80632d8afe 100644 --- a/code/modules/admin/player_panel/actions/punish.dm +++ b/code/modules/admin/player_panel/actions/punish.dm @@ -45,6 +45,58 @@ return TRUE +/datum/player_action/permanent_ban + action_tag = "permanent_ban" + name = "Permanent Ban" + permissions_required = R_BAN + +/datum/player_action/permanent_ban/act(client/user, mob/target, list/params) + var/reason = tgui_input_text(user, "What message should be given to the permabanned user?", "Permanent Ban", encode = FALSE) + if(!reason) + return + + var/internal_reason = tgui_input_text(user, "What's the reason for the ban? This is shown internally, and not displayed in public notes and ban messages. Include as much detail as necessary.", "Permanent Ban", multiline = TRUE, encode = FALSE) + if(!internal_reason) + return + + var/datum/entity/player/target_entity = target.client?.player_data + if(!target_entity) + target_entity = get_player_from_key(target.ckey || target.persistent_ckey) + + if(!target_entity) + return + + if(!target_entity.add_perma_ban(reason, internal_reason, user.player_data)) + to_chat(user, SPAN_ADMIN("The user is already permabanned! If necessary, you can remove the permaban, and place a new one.")) + +/datum/player_action/sticky_ban + action_tag = "sticky_ban" + name = "Sticky Ban" + permissions_required = R_BAN + +/datum/player_action/sticky_ban/act(client/user, mob/target, list/params) + var/datum/entity/player/player = get_player_from_key(target.ckey || target.persistent_ckey) + if(!player) + return + + var/persistent_ip = target.client?.address || player.last_known_ip + var/persistent_cid = target.client?.computer_id || player.last_known_cid + + var/message = tgui_input_text(user, "What message should be given to the impacted users?", "BuildABan", encode = FALSE) + if(!message) + return + + var/reason = tgui_input_text(user, "What's the reason for the ban? This is shown internally, and not displayed in public notes and ban messages. Include as much detail as necessary.", "BuildABan", multiline = TRUE, encode = FALSE) + if(!reason) + return + + user.cmd_admin_do_stickyban(target.ckey, reason, message, impacted_ckeys = list(target.ckey), impacted_cids = list(persistent_cid), impacted_ips = list(persistent_ip)) + player.add_note("Stickybanned | [message]", FALSE, NOTE_ADMIN, TRUE) + player.add_note("Internal reason: [reason]", TRUE, NOTE_ADMIN) + + if(target.client) + qdel(target.client) + /datum/player_action/mute action_tag = "mob_mute" name = "Mute" diff --git a/code/modules/admin/stickyban.dm b/code/modules/admin/stickyban.dm deleted file mode 100644 index 69793a599596..000000000000 --- a/code/modules/admin/stickyban.dm +++ /dev/null @@ -1,66 +0,0 @@ -// BLOCKING PROC, RUN ASYNC - -/proc/stickyban_internal(ckey, address, cid, reason, linked_stickyban, datum/entity/player/banning_admin) - - if(!ckey || !address || !cid) - CRASH("Incorrect data passed to stickyban_internal ([ckey], [address], [cid])") - - var/datum/entity/player/P = get_player_from_key(ckey) - - if(!P) - message_admins("Tried stickybanning ckey \"[ckey]\", player entity was unable to be found. Please try again later.") - return - - var/datum/entity/player_sticky_ban/PSB = DB_ENTITY(/datum/entity/player_sticky_ban) - PSB.player_id = P.id - if(reason) - PSB.reason = reason - PSB.address = address - PSB.computer_id = cid - PSB.ckey = P.ckey - PSB.date = "[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]" - - if(linked_stickyban) - PSB.linked_stickyban = linked_stickyban - - if(!reason) - reason = "No reason given." - - if(banning_admin) - PSB.admin_id = banning_admin.id - if(banning_admin.owning_client) - message_admins("[banning_admin.owning_client.ckey] has stickybanned [ckey].") - - message_admins("[ckey] (IP: [address], CID: [cid]) has been stickybanned for: \"[reason]\".") - - if(P.owning_client) - to_chat_forced(P.owning_client, SPAN_WARNING("You have been sticky banned by [banning_admin? banning_admin.ckey : "Host"].\nReason: [sanitize(reason)].")) - to_chat_forced(P.owning_client, SPAN_WARNING("This is a permanent ban")) - QDEL_NULL(P.owning_client) - - PSB.save() - -/datum/entity/player/proc/process_stickyban(address, computer_id, source_id, reason, datum/entity/player/banning_admin, list/PSB) - if(length(PSB) > 0) // sticky ban with identical data already exists, no need for another copy - if(banning_admin) - to_chat(banning_admin, SPAN_WARNING("Failed to add stickyban to [ckey]. Reason: Stickyban already exists.")) - return - - stickyban_internal(ckey, address, computer_id, reason, source_id, banning_admin) - - -/datum/entity/player/proc/check_for_sticky_ban(address, computer_id) - var/list/datum/view_record/stickyban_list_view/SBLW = DB_VIEW(/datum/view_record/stickyban_list_view, - DB_OR( - DB_COMP("ckey", DB_EQUALS, ckey), - DB_COMP("address", DB_EQUALS, address), - DB_COMP("computer_id", DB_EQUALS, computer_id) - )) - - if(length(SBLW) == 0) - return - - if(stickyban_whitelisted) - return - - return SBLW diff --git a/code/modules/admin/tabs/admin_tab.dm b/code/modules/admin/tabs/admin_tab.dm index 8dce41ac8235..356762b5edd7 100644 --- a/code/modules/admin/tabs/admin_tab.dm +++ b/code/modules/admin/tabs/admin_tab.dm @@ -53,6 +53,12 @@ admin_holder.unbanpanel() return +/client/proc/stickyban_panel() + set name = "Stickyban Panel" + set category = "Admin.Panels" + + admin_holder?.stickypanel() + /client/proc/player_panel_new() set name = "Player Panel" set category = "Admin.Panels" diff --git a/code/modules/admin/topic/topic.dm b/code/modules/admin/topic/topic.dm index 825f7c3cdbf4..ecef2627ed3c 100644 --- a/code/modules/admin/topic/topic.dm +++ b/code/modules/admin/topic/topic.dm @@ -229,6 +229,200 @@ alert(usr, "This ban has already been lifted / does not exist.", "Error", "Ok") unbanpanel() + else if(href_list["unban_perma"]) + var/datum/entity/player/unban_player = get_player_from_key(href_list["unban_perma"]) + if(!(tgui_alert(owner, "Do you want to unban [unban_player.ckey]? They are currently permabanned for: [unban_player.permaban_reason], since [unban_player.permaban_date].", "Unban Player", list("Yes", "No")) == "Yes")) + return + + if(!unban_player.is_permabanned) + to_chat(owner, "The player is not currently permabanned.") + + unban_player.is_permabanned = FALSE + unban_player.permaban_admin_id = null + unban_player.permaban_date = null + unban_player.permaban_reason = null + + unban_player.save() + + message_admins("[key_name_admin(owner)] has removed the permanent ban on [unban_player.ckey].") + important_message_external("[owner] has removed the permanent ban on [unban_player.ckey].", "Permaban Removed") + + else if(href_list["sticky"]) + if(href_list["view_all_ckeys"]) + var/list/datum/view_record/stickyban_matched_ckey/all_ckeys = DB_VIEW(/datum/view_record/stickyban_matched_ckey, + DB_COMP("linked_stickyban", DB_EQUALS, href_list["sticky"]) + ) + + var/list/keys = list() + var/list/whitelisted = list() + for(var/datum/view_record/stickyban_matched_ckey/match as anything in all_ckeys) + if(match.whitelisted) + whitelisted += match.ckey + else + keys += match.ckey + + show_browser(owner, "Impacted: [english_list(keys)]

Whitelisted: [english_list(whitelisted)]", "Stickyban Keys", "stickykeys") + return + + if(href_list["view_all_cids"]) + var/list/datum/view_record/stickyban_matched_cid/all_cids = DB_VIEW(/datum/view_record/stickyban_matched_cid, + DB_COMP("linked_stickyban", DB_EQUALS, href_list["sticky"]) + ) + + var/list/cids = list() + for(var/datum/view_record/stickyban_matched_cid/match as anything in all_cids) + cids += match.cid + + show_browser(owner, english_list(cids), "Stickyban CIDs", "stickycids") + return + + if(href_list["view_all_ips"]) + var/list/datum/view_record/stickyban_matched_ip/all_ips = DB_VIEW(/datum/view_record/stickyban_matched_ip, + DB_COMP("linked_stickyban", DB_EQUALS, href_list["sticky"]) + ) + + var/list/ips = list() + for(var/datum/view_record/stickyban_matched_ip/match as anything in all_ips) + ips += match.ip + + show_browser(owner, english_list(ips), "Stickyban IPs", "stickycips") + return + + if(href_list["find_sticky"]) + var/ckey = ckey(tgui_input_text(owner, "Which CKEY should we attempt to find stickybans for?", "FindABan")) + if(!ckey) + return + + var/list/datum/view_record/stickyban/stickies = SSstickyban.check_for_sticky_ban(ckey) + if(!stickies) + to_chat(owner, SPAN_ADMIN("Could not locate any stickbans impacting [ckey].")) + return + + var/list/impacting_stickies = list() + + for(var/datum/view_record/stickyban/sticky as anything in stickies) + impacting_stickies += sticky.identifier + + to_chat(owner, SPAN_ADMIN("Found the following stickybans for [ckey]: [english_list(impacting_stickies)]")) + + if(!check_rights_for(owner, R_BAN)) + return + + if(href_list["new_sticky"]) + owner.cmd_admin_do_stickyban() + return + + var/datum/entity/stickyban/sticky = DB_ENTITY(/datum/entity/stickyban, href_list["sticky"]) + if(!sticky) + return + + sticky.sync() + + if(href_list["whitelist_ckey"]) + var/ckey_to_whitelist = ckey(tgui_input_text(owner, "What CKEY should be whitelisted? Editing stickyban: [sticky.identifier]")) + if(!ckey_to_whitelist) + return + + SSstickyban.whitelist_ckey(sticky.id, ckey_to_whitelist) + message_admins("[key_name_admin(owner)] has whitelisted [ckey_to_whitelist] against stickyban '[sticky.identifier]'.") + important_message_external("[owner] has whitelisted [ckey_to_whitelist] against stickyban '[sticky.identifier]'.", "CKEY Whitelisted") + + if(href_list["add"]) + var/option = tgui_input_list(owner, "What do you want to add?", "AddABan", list("CID", "CKEY", "IP")) + if(!option) + return + + var/to_add = tgui_input_text(owner, "Provide the [option] to add to the stickyban.", "AddABan") + if(!to_add) + return + + switch(option) + if("CID") + SSstickyban.add_matched_cid(sticky.id, to_add) + if("CKEY") + SSstickyban.add_matched_ckey(sticky.id, to_add) + if("IP") + SSstickyban.add_matched_ip(sticky.id, to_add) + + message_admins("[key_name_admin(owner)] has added a [option] ([to_add]) to stickyban '[sticky.identifier]'.") + important_message_external("[owner] has added a [option] ([to_add]) to stickyban '[sticky.identifier]'.", "[option] Added to Stickyban") + + if(href_list["remove"]) + var/option = tgui_input_list(owner, "What do you want to remove?", "DelABan", list("Entire Stickyban", "CID", "CKEY", "IP")) + switch(option) + if("Entire Stickyban") + if(!(tgui_alert(owner, "Are you sure you want to remove this stickyban? Identifier: [sticky.identifier] Reason: [sticky.reason]", "Confirm", list("Yes", "No")) == "Yes")) + return + + sticky.active = FALSE + sticky.save() + + message_admins("[key_name_admin(owner)] has deactivated stickyban '[sticky.identifier]'.") + important_message_external("[owner] has deactivated stickyban '[sticky.identifier]'.", "Stickyban Deactivated") + + if("CID") + var/list/datum/view_record/stickyban_matched_cid/all_cids = DB_VIEW(/datum/view_record/stickyban_matched_cid, + DB_COMP("linked_stickyban", DB_EQUALS, sticky.id) + ) + + var/list/cid_to_record_id = list() + for(var/datum/view_record/stickyban_matched_cid/match in all_cids) + cid_to_record_id["[match.cid]"] = match.id + + var/picked = tgui_input_list(owner, "Which CID to remove?", "DelABan", cid_to_record_id) + if(!picked) + return + + var/selected = cid_to_record_id[picked] + + var/datum/entity/stickyban_matched_cid/sticky_cid = DB_ENTITY(/datum/entity/stickyban_matched_cid, selected) + sticky_cid.delete() + + message_admins("[key_name_admin(owner)] has removed a CID ([picked]) from stickyban '[sticky.identifier]'.") + important_message_external("[owner] has removed a CID ([picked]) from stickyban '[sticky.identifier]'.", "CID Removed from Stickyban") + + if("CKEY") + var/list/datum/view_record/stickyban_matched_ckey/all_ckeys = DB_VIEW(/datum/view_record/stickyban_matched_ckey, + DB_COMP("linked_stickyban", DB_EQUALS, sticky.id) + ) + + var/list/ckey_to_record_id = list() + for(var/datum/view_record/stickyban_matched_ckey/match in all_ckeys) + ckey_to_record_id["[match.ckey]"] = match.id + + var/picked = tgui_input_list(owner, "Which CKEY to remove?", "DelABan", ckey_to_record_id) + if(!picked) + return + + var/selected = ckey_to_record_id[picked] + + var/datum/entity/stickyban_matched_ckey/sticky_ckey = DB_ENTITY(/datum/entity/stickyban_matched_ckey, selected) + sticky_ckey.delete() + + message_admins("[key_name_admin(owner)] has removed a CKEY ([picked]) from stickyban '[sticky.identifier]'.") + important_message_external("[owner] has removed a CKEY ([picked]) from stickyban '[sticky.identifier]'.", "CKEY Removed from Stickyban") + + if("IP") + var/list/datum/view_record/stickyban_matched_ip/all_ips = DB_VIEW(/datum/view_record/stickyban_matched_ip, + DB_COMP("linked_stickyban", DB_EQUALS, sticky.id) + ) + + var/list/ip_to_record_id = list() + for(var/datum/view_record/stickyban_matched_ip/match in all_ips) + ip_to_record_id["[match.ip]"] = match.id + + var/picked = tgui_input_list(owner, "Which IP to remove?", "DelABan", ip_to_record_id) + if(!picked) + return + + var/selected = ip_to_record_id[picked] + + var/datum/entity/stickyban_matched_ip/sticky_ip = DB_ENTITY(/datum/entity/stickyban_matched_ip, selected) + sticky_ip.delete() + + message_admins("[key_name_admin(owner)] has removed an IP ([picked]) from stickyban [sticky.identifier].") + important_message_external("[owner] has removed an IP ([picked]) from stickyban '[sticky.identifier].", "IP Removed from Stickyban") + else if(href_list["warn"]) usr.client.warn(href_list["warn"]) diff --git a/code/modules/admin/verbs/autoreplace.dm b/code/modules/admin/verbs/autoreplace.dm index b2fe04cfb4a3..a896c751f5ed 100644 --- a/code/modules/admin/verbs/autoreplace.dm +++ b/code/modules/admin/verbs/autoreplace.dm @@ -32,7 +32,7 @@ GLOBAL_LIST_INIT_TYPED(admin_runtime_decorators, /datum/decorator/manual/admin_r GLOB.admin_runtime_decorators.Add(SSdecorator.add_decorator(/datum/decorator/manual/admin_runtime, types, subtypes, field, value)) - log_and_message_admins("[src] activated new decorator id: [GLOB.admin_runtime_decorators.len] set for [hint_text] `[types]` for field `[field]` set value `[value]`") + message_admins("[src] activated new decorator id: [GLOB.admin_runtime_decorators.len] set for [hint_text] `[types]` for field `[field]` set value `[value]`") /client/proc/deactivate_autoreplacer() set category = "Admin.Events" @@ -49,7 +49,7 @@ GLOBAL_LIST_INIT_TYPED(admin_runtime_decorators, /datum/decorator/manual/admin_r GLOB.admin_runtime_decorators[num_value].enabled = FALSE - log_and_message_admins("[src] deactivated decorator id: [num_value]") + message_admins("[src] deactivated decorator id: [num_value]") /client/proc/rerun_decorators() set category = "Admin.Events" @@ -65,4 +65,4 @@ GLOBAL_LIST_INIT_TYPED(admin_runtime_decorators, /datum/decorator/manual/admin_r SSdecorator.force_update() - log_and_message_admins("[src] rerun all decorators.") + message_admins("[src] rerun all decorators.") diff --git a/code/modules/clans/client.dm b/code/modules/clans/client.dm index c4948b2a6923..3450b7553c51 100644 --- a/code/modules/clans/client.dm +++ b/code/modules/clans/client.dm @@ -234,7 +234,7 @@ return - log_and_message_admins("[key_name_admin(src)] has set the name of [target_clan.name] to [input].") + message_admins("[key_name_admin(src)] has set the name of [target_clan.name] to [input].") to_chat(src, SPAN_NOTICE("Set the name of [target_clan.name] to [input].")) target_clan.name = trim(input) @@ -247,7 +247,7 @@ if(!input || input == target_clan.description) return - log_and_message_admins("[key_name_admin(src)] has set the description of [target_clan.name].") + message_admins("[key_name_admin(src)] has set the description of [target_clan.name].") to_chat(src, SPAN_NOTICE("Set the description of [target_clan.name].")) target_clan.description = trim(input) @@ -261,7 +261,7 @@ return target_clan.color = color - log_and_message_admins("[key_name_admin(src)] has set the color of [target_clan.name] to [color].") + message_admins("[key_name_admin(src)] has set the color of [target_clan.name] to [color].") to_chat(src, SPAN_NOTICE("Set the name of [target_clan.name] to [color].")) if(CLAN_ACTION_CLAN_SETHONOR) if(!has_clan_permission(CLAN_PERMISSION_ADMIN_MANAGER)) @@ -272,7 +272,7 @@ if((!input && input != 0) || input == target_clan.honor) return - log_and_message_admins("[key_name_admin(src)] has set the honor of clan [target_clan.name] from [target_clan.honor] to [input].") + message_admins("[key_name_admin(src)] has set the honor of clan [target_clan.name] from [target_clan.honor] to [input].") to_chat(src, SPAN_NOTICE("Set the honor of [target_clan.name] from [target_clan.honor] to [input].")) target_clan.honor = input @@ -286,7 +286,7 @@ to_chat(src, "You have decided not to delete [target_clan.name].") return - log_and_message_admins("[key_name_admin(src)] has deleted the clan [target_clan.name].") + message_admins("[key_name_admin(src)] has deleted the clan [target_clan.name].") to_chat(src, SPAN_NOTICE("You have deleted [target_clan.name].")) var/list/datum/view_record/clan_playerbase_view/CPV = DB_VIEW(/datum/view_record/clan_playerbase_view, DB_COMP("clan_id", DB_EQUALS, target_clan.id)) @@ -339,7 +339,7 @@ return var/target_clan = target.clan_id - log_and_message_admins("[key_name_admin(src)] has purged [player_name]'s clan profile.") + message_admins("[key_name_admin(src)] has purged [player_name]'s clan profile.") to_chat(src, SPAN_NOTICE("You have purged [player_name]'s clan profile.")) target.delete() @@ -379,20 +379,20 @@ target.clan_id = null target.clan_rank = GLOB.clan_ranks_ordered[CLAN_RANK_YOUNG] to_chat(src, SPAN_NOTICE("Removed [player_name] from their clan.")) - log_and_message_admins("[key_name_admin(src)] has removed [player_name] from their current clan.") + message_admins("[key_name_admin(src)] has removed [player_name] from their current clan.") else if(input == "Remove from Ancient") target.clan_rank = GLOB.clan_ranks_ordered[CLAN_RANK_YOUNG] target.permissions = GLOB.clan_ranks[CLAN_RANK_YOUNG].permissions to_chat(src, SPAN_NOTICE("Removed [player_name] from ancient.")) - log_and_message_admins("[key_name_admin(src)] has removed [player_name] from ancient.") + message_admins("[key_name_admin(src)] has removed [player_name] from ancient.") else if(input == "Make Ancient" && is_clan_manager) target.clan_rank = GLOB.clan_ranks_ordered[CLAN_RANK_ADMIN] target.permissions = CLAN_PERMISSION_ADMIN_ANCIENT to_chat(src, SPAN_NOTICE("Made [player_name] an ancient.")) - log_and_message_admins("[key_name_admin(src)] has made [player_name] an ancient.") + message_admins("[key_name_admin(src)] has made [player_name] an ancient.") else to_chat(src, SPAN_NOTICE("Moved [player_name] to [input].")) - log_and_message_admins("[key_name_admin(src)] has moved [player_name] to clan [input].") + message_admins("[key_name_admin(src)] has moved [player_name] to clan [input].") target.clan_id = clans[input] @@ -455,7 +455,7 @@ target.clan_rank = GLOB.clan_ranks_ordered[chosen_rank.name] target.permissions = chosen_rank.permissions - log_and_message_admins("[key_name_admin(src)] has set the rank of [player_name] to [chosen_rank.name] for their clan.") + message_admins("[key_name_admin(src)] has set the rank of [player_name] to [chosen_rank.name] for their clan.") to_chat(src, SPAN_NOTICE("Set [player_name]'s rank to [chosen_rank.name]")) target.save() diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm index 2e5c6a9112a3..d89e8572caff 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Queen.dm @@ -595,7 +595,7 @@ xeno_announcement(input, hivenumber, "The words of the [name] reverberate in our head...") - log_and_message_admins("[key_name_admin(src)] has created a Word of the Queen report:") + message_admins("[key_name_admin(src)] has created a Word of the Queen report:") log_admin("[key_name_admin(src)] Word of the Queen: [input]") return TRUE diff --git a/code/modules/tgui_panel/telemetry.dm b/code/modules/tgui_panel/telemetry.dm index eb5c7d96a4d9..4ef1f06bfac0 100644 --- a/code/modules/tgui_panel/telemetry.dm +++ b/code/modules/tgui_panel/telemetry.dm @@ -86,7 +86,7 @@ // Check for a malformed history object if (!row || row.len < 3 || (!row["ckey"] || !row["address"] || !row["computer_id"])) - return + continue /* TODO - Reintroduce this when we get a proper round ID tracking, and we want to log it to database @@ -103,7 +103,7 @@ continue */ - if (world.IsBanned(row["ckey"], row["address"], row["computer_id"], real_bans_only = TRUE)) + if (world.IsBanned(row["ckey"], row["address"], row["computer_id"], real_bans_only = TRUE, is_telemetry = TRUE)) found = row break diff --git a/colonialmarines.dme b/colonialmarines.dme index 380d22202ec8..42e46e15ef3c 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -298,6 +298,7 @@ #include "code\controllers\subsystem\sound_loops.dm" #include "code\controllers\subsystem\soundscape.dm" #include "code\controllers\subsystem\statpanel.dm" +#include "code\controllers\subsystem\stickyban.dm" #include "code\controllers\subsystem\techtree.dm" #include "code\controllers\subsystem\tgui.dm" #include "code\controllers\subsystem\ticker.dm" @@ -1399,7 +1400,6 @@ #include "code\modules\admin\NewBan.dm" #include "code\modules\admin\player_notes.dm" #include "code\modules\admin\server_verbs.dm" -#include "code\modules\admin\stickyban.dm" #include "code\modules\admin\STUI.dm" #include "code\modules\admin\tag.dm" #include "code\modules\admin\medal_panel\medals_panel.dm" diff --git a/tgui/packages/tgui/interfaces/PlayerPanel.jsx b/tgui/packages/tgui/interfaces/PlayerPanel.jsx index 85f73b581c67..88b30aa51802 100644 --- a/tgui/packages/tgui/interfaces/PlayerPanel.jsx +++ b/tgui/packages/tgui/interfaces/PlayerPanel.jsx @@ -236,7 +236,6 @@ const GeneralActions = (props) => { /> { />