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 = {" +
+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.
+ +