diff --git a/SQL/database_changelog.txt b/SQL/database_changelog.txt index 25a52b6806f..7127f8f0fd8 100644 --- a/SQL/database_changelog.txt +++ b/SQL/database_changelog.txt @@ -1,13 +1,27 @@ Any time you make a change to the schema files, remember to increment the database schema version. Generally increment the minor number, major should be reserved for significant changes to the schema. Both values go up to 255. -The latest database version is 5.19 (5.17 for /tg/); The query to update the schema revision table is: +The latest database version is 5.20 (5.18 for /tg/); The query to update the schema revision table is: -INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 19); +INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 20); or -INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 19); +INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 20); In any query remember to add a prefix to the table names if you use one. +----------------------------------------------------- +Version 5.20, 1 November 2021, by Mothblocks +Added `known_alts` table for tracking who not to create suspicious logins for. + +``` +CREATE TABLE `known_alts` ( + `id` INT NOT NULL AUTO_INCREMENT, + `ckey1` VARCHAR(32) NOT NULL, + `ckey2` VARCHAR(32) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `unique_contraints` (`ckey1` , `ckey2`) +); +``` + ----------------------------------------------------- Version 5.19, 23 August 2021, by GoldenAlpharex Added `discord_report` column to the `ban table` @@ -15,8 +29,9 @@ Added `discord_report` column to the `ban table` ``` `discord_reported` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', /* SKYRAT EDIT - Labelling bans for ease of reporting them over Discord. */ ``` + ----------------------------------------------------- -Version 5.17, 8 October 2021, by MrStonedOne + Mothblocks +Version 5.18, 8 October 2021, by MrStonedOne + Mothblocks Changes any table that requrired a NOT NULL round ID to now accept NULL. In the BSQL past, these were handled as 0, but in the move to rust-g this behavior was lost. ``` diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql index 9804bff4e3a..981e527eed9 100644 --- a/SQL/tgstation_schema.sql +++ b/SQL/tgstation_schema.sql @@ -686,6 +686,18 @@ CREATE TABLE `admin_connections` ( UNIQUE INDEX `unique_constraints` (`ckey`, `ip`, `cid`) ) ENGINE=InnoDB; +-- +-- Table structure for table `known_alts` +-- +DROP TABLE IF EXISTS `known_alts`; +CREATE TABLE `known_alts` ( + `id` INT NOT NULL AUTO_INCREMENT, + `ckey1` VARCHAR(32) NOT NULL, + `ckey2` VARCHAR(32) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `unique_contraints` (`ckey1` , `ckey2`) +); + /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; diff --git a/SQL/tgstation_schema_prefixed.sql b/SQL/tgstation_schema_prefixed.sql index 9623b47ca42..32664e73a85 100644 --- a/SQL/tgstation_schema_prefixed.sql +++ b/SQL/tgstation_schema_prefixed.sql @@ -670,6 +670,18 @@ CREATE TABLE `SS13_admin_connections` ( UNIQUE INDEX `unique_constraints` (`ckey`, `ip`, `cid`) ) ENGINE=InnoDB; +-- +-- Table structure for table `known_alts` +-- +DROP TABLE IF EXISTS `SS13_known_alts`; +CREATE TABLE `SS13_known_alts` ( + `id` INT NOT NULL AUTO_INCREMENT, + `ckey1` VARCHAR(32) NOT NULL, + `ckey2` VARCHAR(32) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `unique_contraints` (`ckey1` , `ckey2`) +); + /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index a028f7bbcbf..734840b6078 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -146,3 +146,6 @@ GLOBAL_VAR_INIT(ghost_role_flags, (~0)) /// for asay pings, this is the index in the return list for [/proc/check_admin_pings] that contains the message modified with underlines for the spotted names #define ADMINSAY_PING_UNDERLINE_NAME_INDEX "!underlined_names" + +/// When passed in as the duration for ban_panel, will make the ban default to permanent +#define BAN_PANEL_PERMANENT "permanent" diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 41ab8237205..ff025944e10 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -20,7 +20,7 @@ * * make sure you add an update to the schema_version stable in the db changelog */ -#define DB_MINOR_VERSION 19 +#define DB_MINOR_VERSION 20 //! ## Timing subsystem diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index a440cdfa398..85926bcd451 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -82,6 +82,7 @@ GLOBAL_PROTECT(admin_verbs_admin) /datum/admins/proc/open_borgopanel, /datum/admins/proc/view_all_circuits, /datum/admins/proc/view_all_sdql_spells, + /datum/admins/proc/known_alts_panel, ) GLOBAL_LIST_INIT(admin_verbs_ban, list(/client/proc/unban_panel, /client/proc/ban_panel, /client/proc/stickybanpanel)) GLOBAL_PROTECT(admin_verbs_ban) diff --git a/code/modules/admin/known_alts.dm b/code/modules/admin/known_alts.dm new file mode 100644 index 00000000000..8ea595e1aca --- /dev/null +++ b/code/modules/admin/known_alts.dm @@ -0,0 +1,192 @@ +GLOBAL_DATUM_INIT(known_alts, /datum/known_alts, new) + +/datum/known_alts + var/list/cached_known_alts + COOLDOWN_DECLARE(cache_cooldown) + +/datum/known_alts/Topic(href, list/href_list) + if (!check_rights(R_ADMIN)) + return + + if (!SSdbcore.Connect()) + to_chat(usr, span_warning("Couldn't connect to the database.")) + return + + var/datum/admins/holder = usr.client?.holder + if (isnull(holder)) + return + + if (!holder.CheckAdminHref(href, href_list)) + return + + switch (href_list["action"]) + if ("add") + var/ckey1 = input(usr, "Put in the name of the main ckey") as null|text + if (!ckey1) + return + + var/ckey2 = input(usr, "Put in the name of their alt") as null|text + if (!ckey2) + return + + ckey1 = ckey(ckey1) + ckey2 = ckey(ckey2) + + var/datum/db_query/query_already_exists = SSdbcore.NewQuery({" + SELECT id FROM [format_table_name("known_alts")] + WHERE (ckey1 = :ckey1 AND ckey2 = :ckey2) + OR (ckey1 = :ckey2 AND ckey2 = :ckey1) + "}, list( + "ckey1" = ckey1, + "ckey2" = ckey2, + )) + + query_already_exists.warn_execute() + + if (query_already_exists.last_error) + qdel(query_already_exists) + return + + var/already_exists_row = query_already_exists.NextRow() + qdel(query_already_exists) + + if (already_exists_row) + alert(usr, "Those two are already in the list of known alts!") + return + + var/datum/db_query/query_add_known_alt = SSdbcore.NewQuery({" + INSERT INTO [format_table_name("known_alts")] (ckey1, ckey2) + VALUES (:ckey1, :ckey2) + "}, list( + "ckey1" = ckey1, + "ckey2" = ckey2, + )) + + if (query_add_known_alt.warn_execute()) + var/message = "[key_name(usr)] has added a new known alt connection between [ckey1] and [ckey2]." + message_admins(message) + log_admin_private(message) + + cached_known_alts = null + load_known_alts() + + qdel(query_add_known_alt) + show_panel(usr.client) + + if (!is_banned_from(ckey2, "Server")) + var/ban_choice = alert("[ckey2] is not banned from the server. Do you want to open up the ban panel as well?",,"Yes", "No") + if (ban_choice == "Yes") + holder.ban_panel(ckey2, role = "Server", duration = BAN_PANEL_PERMANENT) + if ("delete") + var/id = text2num(href_list["id"]) + if (!id) + log_admin_private("[key_name(usr)] tried to delete an invalid known alt ID: [href_list["id"]]") + return + + var/datum/db_query/query_known_alt_info = SSdbcore.NewQuery({" + SELECT ckey1, ckey2 FROM [format_table_name("known_alts")] + WHERE id = :id + "}, list( + "id" = id, + )) + + if (!query_known_alt_info.warn_execute()) + qdel(query_known_alt_info) + return + + if (!query_known_alt_info.NextRow()) + alert("Couldn't find the known alt with the ID [id]") + qdel(query_known_alt_info) + return + + var/list/result = query_known_alt_info.item + qdel(query_known_alt_info) + + if (alert("Are you sure you want to delete the alt connection between [result[1]] and [result[2]]?",,"Yes", "No") != "Yes") + return + + var/datum/db_query/query_delete_known_alt = SSdbcore.NewQuery({" + DELETE FROM [format_table_name("known_alts")] + WHERE id = :id + "}, list( + "id" = id, + )) + + if (query_delete_known_alt.warn_execute()) + var/message = "[key_name(usr)] has deleted the known alt connection between [result[1]] and [result[2]]." + message_admins(message) + log_admin_private(message) + + cached_known_alts = null + load_known_alts() + + qdel(query_delete_known_alt) + show_panel(usr.client) + +/// Returns the list of known alts, will return an empty list if the DB could not be connected to. +/// This proc can block. +/datum/known_alts/proc/load_known_alts() + if (!isnull(cached_known_alts) && !COOLDOWN_FINISHED(src, cache_cooldown)) + return cached_known_alts + + if (!SSdbcore.Connect()) + return cached_known_alts || list() + + var/datum/db_query/query_known_alts = SSdbcore.NewQuery("SELECT id, ckey1, ckey2 FROM [format_table_name("known_alts")] ORDER BY id DESC") + query_known_alts.warn_execute() + + if (query_known_alts.last_error) + qdel(query_known_alts) + return cached_known_alts || list() + + cached_known_alts = list() + + while (query_known_alts.NextRow()) + cached_known_alts += list(list( + query_known_alts.item[2], + query_known_alts.item[3], + + // The ID + query_known_alts.item[1], + )) + + COOLDOWN_START(src, cache_cooldown, 10 SECONDS) + qdel(query_known_alts) + + return cached_known_alts + +/datum/known_alts/proc/show_panel(client/client) + if (!check_rights_for(client, R_ADMIN)) + return + + if (!SSdbcore.Connect()) + to_chat(usr, span_warning("Couldn't connect to the database.")) + return + + var/list/known_alts_html = list() + + for (var/known_alt in load_known_alts()) + known_alts_html += "\[-\] Delete [known_alt[1]] is an alt of [known_alt[2]]." + + var/html = {" + + Known Alts + + + +

Any two ckeys in this panel will not show in "banned connection history".

+

Sometimes players switch account, and it's customary to perma-ban the old one.

+ +

All Known Alts:

\[+\] Add
+ + [known_alts_html.Join("
")] + + "} + + client << browse(html, "window=known_alts;size=700x400") + +/datum/admins/proc/known_alts_panel() + set name = "Known Alts Panel" + set category = "Admin" + + GLOB.known_alts.show_panel(usr.client) diff --git a/code/modules/admin/sql_ban_system.dm b/code/modules/admin/sql_ban_system.dm index 6ec34649cfd..2075262d08c 100644 --- a/code/modules/admin/sql_ban_system.dm +++ b/code/modules/admin/sql_ban_system.dm @@ -135,6 +135,9 @@ /datum/admins/proc/ban_panel(player_key, player_ip, player_cid, role, duration = 1440, applies_to_admins, reason, edit_id, page, admin_key, global_ban) // SKYRAT EDIT CHANGE - MULTISERVER + if (duration == BAN_PANEL_PERMANENT) + duration = null + var/panel_height = 620 if(edit_id) panel_height = 240 diff --git a/code/modules/tgui_panel/telemetry.dm b/code/modules/tgui_panel/telemetry.dm index 98ba1f14b8b..7d08fc997a7 100644 --- a/code/modules/tgui_panel/telemetry.dm +++ b/code/modules/tgui_panel/telemetry.dm @@ -60,18 +60,34 @@ message_admins("[key_name(client)] was kicked for sending a huge telemetry payload") qdel(client) return + + var/list/all_known_alts = GLOB.known_alts.load_known_alts() + var/list/our_known_alts = list() + + for (var/known_alt in all_known_alts) + if (known_alt[1] == client?.ckey) + our_known_alts += known_alt[2] + else if (known_alt[2] == client?.ckey) + our_known_alts += known_alt[1] + var/list/found for(var/i in 1 to len) if(QDELETED(client)) // He got cleaned up before we were done return var/list/row = telemetry_connections[i] + // Check for a malformed history object if (!row || row.len < 3 || (!row["ckey"] || !row["address"] || !row["computer_id"])) return + + if (row["ckey"] in our_known_alts) + continue + if (world.IsBanned(row["ckey"], row["address"], row["computer_id"], real_bans_only = TRUE)) found = row break + CHECK_TICK // This fucker has a history of playing on a banned account. if(found) diff --git a/tgstation.dme b/tgstation.dme index 7eed00081a7..f05a1ef4af1 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1709,6 +1709,7 @@ #include "code\modules\admin\holder2.dm" #include "code\modules\admin\ipintel.dm" #include "code\modules\admin\IsBanned.dm" +#include "code\modules\admin\known_alts.dm" #include "code\modules\admin\outfit_editor.dm" #include "code\modules\admin\outfit_manager.dm" #include "code\modules\admin\outfits.dm"