From d8ab6375c0cb6579f736e32399d18ddb6ea3f04e Mon Sep 17 00:00:00 2001 From: oranges Date: Sun, 17 Mar 2019 13:33:48 +1300 Subject: [PATCH] Database backed stickybans. --- SQL/database_changelog.txt | 49 +++- SQL/tgstation_schema.sql | 51 ++++ SQL/tgstation_schema_prefixed.sql | 52 ++++ code/__DEFINES/admin.dm | 3 + code/__DEFINES/subsystems.dm | 3 +- code/controllers/subsystem/dbcore.dm | 21 ++ code/controllers/subsystem/server_maint.dm | 3 + code/controllers/subsystem/stickyban.dm | 199 ++++++++++++- code/game/world.dm | 5 + code/modules/admin/IsBanned.dm | 114 +++++--- code/modules/admin/stickyban.dm | 313 ++++++++++++++++++--- code/modules/goonchat/browserOutput.dm | 2 +- code/world.dm | 1 + 13 files changed, 717 insertions(+), 99 deletions(-) diff --git a/SQL/database_changelog.txt b/SQL/database_changelog.txt index 24ad3f1a659a..fcf347d99d32 100644 --- a/SQL/database_changelog.txt +++ b/SQL/database_changelog.txt @@ -1,15 +1,53 @@ 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 4.7; The query to update the schema revision table is: +The latest database version is 5.1; The query to update the schema revision table is: -INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 0); +INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 1); or -INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 0); +INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 1); In any query remember to add a prefix to the table names if you use one. ---------------------------------------------------- +Version 5.1, 25 Feb 2018, by MrStonedOne +Added four tables to enable storing of stickybans in the database since byond can lose them, and to enable disabling stickybans for a round without depending on a crash free round. Existing stickybans are automagically imported to the tables. + +CREATE TABLE `stickyban` ( + `ckey` VARCHAR(32) NOT NULL, + `reason` VARCHAR(2048) NOT NULL, + `banning_admin` VARCHAR(32) NOT NULL, + `datetime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`ckey`) +) ENGINE=InnoDB; + +CREATE TABLE `stickyban_matched_ckey` ( + `stickyban` VARCHAR(32) NOT NULL, + `matched_ckey` VARCHAR(32) NOT NULL, + `first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `exempt` TINYINT(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`stickyban`, `matched_ckey`) +) ENGINE=InnoDB; + +CREATE TABLE `stickyban_matched_ip` ( + `stickyban` VARCHAR(32) NOT NULL, + `matched_ip` INT UNSIGNED NOT NULL, + `first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`stickyban`, `matched_ip`) +) ENGINE=InnoDB; + +CREATE TABLE `stickyban_matched_cid` ( + `stickyban` VARCHAR(32) NOT NULL, + `matched_cid` VARCHAR(32) NOT NULL, + `first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`stickyban`, `matched_cid`) +) ENGINE=InnoDB; + +---------------------------------------------------- + Version 5.0, 28 October 2018, by Jordie0608 Modified ban table to remove the need for the `bantype` column, a python script is used to migrate data to this new format. @@ -88,8 +126,7 @@ Added table `role_time_log` and triggers `role_timeTlogupdate`, `role_timeTlogin CREATE TABLE `role_time_log` ( `id` BIGINT NOT NULL AUTO_INCREMENT , `ckey` VARCHAR(32) NOT NULL , `job` VARCHAR(128) NOT NULL , `delta` INT NOT NULL , `datetime` TIMESTAMP on update CURRENT_TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , PRIMARY KEY (`id`), INDEX (`ckey`), INDEX (`job`), INDEX (`datetime`)) ENGINE = InnoDB; -DELIMITER -$$ +DELIMITER $$ CREATE TRIGGER `role_timeTlogupdate` AFTER UPDATE ON `role_time` FOR EACH ROW BEGIN INSERT into role_time_log (ckey, job, delta) VALUES (NEW.CKEY, NEW.job, NEW.minutes-OLD.minutes); END $$ @@ -99,7 +136,7 @@ $$ CREATE TRIGGER `role_timeTlogdelete` AFTER DELETE ON `role_time` FOR EACH ROW BEGIN INSERT into role_time_log (ckey, job, delta) VALUES (OLD.ckey, OLD.job, 0-OLD.minutes); END $$ - +DELIMITER ; ---------------------------------------------------- Version 4.2, 17 April 2018, by Jordie0608 diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql index ad91ec1110fd..c7c171ea6909 100644 --- a/SQL/tgstation_schema.sql +++ b/SQL/tgstation_schema.sql @@ -462,6 +462,57 @@ $$ CREATE TRIGGER `role_timeTlogdelete` AFTER DELETE ON `role_time` FOR EACH ROW BEGIN INSERT into role_time_log (ckey, job, delta) VALUES (OLD.ckey, OLD.job, 0-OLD.minutes); END $$ +DELIMITER ; + +-- +-- Table structure for table `stickyban` +-- +DROP TABLE IF EXISTS `stickyban`; +CREATE TABLE `stickyban` ( + `ckey` VARCHAR(32) NOT NULL, + `reason` VARCHAR(2048) NOT NULL, + `banning_admin` VARCHAR(32) NOT NULL, + `datetime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`ckey`) +) ENGINE=InnoDB; + +-- +-- Table structure for table `stickyban_matched_ckey` +-- +DROP TABLE IF EXISTS `stickyban_matched_ckey`; +CREATE TABLE `ss13_stickyban_matched_ckey` ( + `stickyban` VARCHAR(32) NOT NULL, + `matched_ckey` VARCHAR(32) NOT NULL, + `first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `exempt` TINYINT(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`stickyban`, `matched_ckey`) +) ENGINE=InnoDB; + +-- +-- Table structure for table `ss13_stickyban_matched_ip` +-- +DROP TABLE IF EXISTS `ss13_stickyban_matched_ip`; +CREATE TABLE `ss13_stickyban_matched_ip` ( + `stickyban` VARCHAR(32) NOT NULL, + `matched_ip` INT UNSIGNED NOT NULL, + `first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`stickyban`, `matched_ip`) +) ENGINE=InnoDB; + +-- +-- Table structure for table `stickyban_matched_cid` +-- +DROP TABLE IF EXISTS `stickyban_matched_cid`; +CREATE TABLE `stickyban_matched_cid` ( + `stickyban` VARCHAR(32) NOT NULL, + `matched_cid` VARCHAR(32) NOT NULL, + `first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`stickyban`, `matched_cid`) +) ENGINE=InnoDB; + /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; diff --git a/SQL/tgstation_schema_prefixed.sql b/SQL/tgstation_schema_prefixed.sql index e36a7cde9fbb..0c7a1883c914 100644 --- a/SQL/tgstation_schema_prefixed.sql +++ b/SQL/tgstation_schema_prefixed.sql @@ -462,6 +462,58 @@ $$ CREATE TRIGGER `SS13_role_timeTlogdelete` AFTER DELETE ON `SS13_role_time` FOR EACH ROW BEGIN INSERT into SS13_role_time_log (ckey, job, delta) VALUES (OLD.ckey, OLD.job, 0-OLD.minutes); END $$ +DELIMITER ; + +-- +-- Table structure for table `SS13_stickyban` +-- +DROP TABLE IF EXISTS `SS13_stickyban`; +CREATE TABLE `SS13_stickyban` ( + `ckey` VARCHAR(32) NOT NULL, + `reason` VARCHAR(2048) NOT NULL, + `banning_admin` VARCHAR(32) NOT NULL, + `datetime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`ckey`) +) ENGINE=InnoDB; + +-- +-- Table structure for table `SS13_stickyban_matched_ckey` +-- +DROP TABLE IF EXISTS `SS13_stickyban_matched_ckey`; +CREATE TABLE `SS13_stickyban_matched_ckey` ( + `stickyban` VARCHAR(32) NOT NULL, + `matched_ckey` VARCHAR(32) NOT NULL, + `first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `exempt` TINYINT(1) NOT NULL DEFAULT '0', + PRIMARY KEY (`stickyban`, `matched_ckey`) +) ENGINE=InnoDB; + +-- +-- Table structure for table `SS13_stickyban_matched_ip` +-- +DROP TABLE IF EXISTS `SS13_stickyban_matched_ip`; +CREATE TABLE `SS13_stickyban_matched_ip` ( + `stickyban` VARCHAR(32) NOT NULL, + `matched_ip` INT UNSIGNED NOT NULL, + `first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`stickyban`, `matched_ip`) +) ENGINE=InnoDB; + +-- +-- Table structure for table `SS13_stickyban_matched_cid` +-- +DROP TABLE IF EXISTS `SS13_stickyban_matched_cid`; +CREATE TABLE `SS13_stickyban_matched_cid` ( + `stickyban` VARCHAR(32) NOT NULL, + `matched_cid` VARCHAR(32) NOT NULL, + `first_matched` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + `last_matched` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`stickyban`, `matched_cid`) +) ENGINE=InnoDB; + + /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm index 2e7761d9ebc2..4a274f9afe0e 100644 --- a/code/__DEFINES/admin.dm +++ b/code/__DEFINES/admin.dm @@ -81,3 +81,6 @@ #define SPAM_TRIGGER_WARNING 5 //Number of identical messages required before the spam-prevention will warn you to stfu #define SPAM_TRIGGER_AUTOMUTE 10 //Number of identical messages required before the spam-prevention will automute you + +#define STICKYBAN_DB_CACHE_TIME 10 SECONDS +#define STICKYBAN_ROGUE_CHECK_TIME 5 \ No newline at end of file diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 0fcab54f0f81..3fba67e2b26b 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -1,7 +1,8 @@ //Update this whenever the db schema changes //make sure you add an update to the schema_version stable in the db changelog #define DB_MAJOR_VERSION 5 -#define DB_MINOR_VERSION 0 +#define DB_MINOR_VERSION 1 + //Timing subsystem //Don't run if there is an identical unique timer active diff --git a/code/controllers/subsystem/dbcore.dm b/code/controllers/subsystem/dbcore.dm index efd06a9d376b..ccbe8dc61caf 100644 --- a/code/controllers/subsystem/dbcore.dm +++ b/code/controllers/subsystem/dbcore.dm @@ -177,6 +177,27 @@ SUBSYSTEM_DEF(dbcore) return FALSE return new /datum/DBQuery(sql_query, connection) +/datum/controller/subsystem/dbcore/proc/QuerySelect(list/querys, warn = FALSE, qdel = FALSE) + if (!islist(querys)) + if (!istype(querys, /datum/DBQuery)) + CRASH("Invalid query passed to QuerySelect: [querys]") + querys = list(querys) + + for (var/thing in querys) + var/datum/DBQuery/query = thing + if (warn) + INVOKE_ASYNC(query, /datum/DBQuery.proc/warn_execute) + else + INVOKE_ASYNC(query, /datum/DBQuery.proc/Execute) + + for (var/thing in querys) + var/datum/DBQuery/query = thing + UNTIL(!query.in_progress) + if (qdel) + qdel(query) + + + /* Takes a list of rows (each row being an associated list of column => value) and inserts them via a single mass query. Rows missing columns present in other rows will resolve to SQL NULL diff --git a/code/controllers/subsystem/server_maint.dm b/code/controllers/subsystem/server_maint.dm index 8f88e6202f53..a452a319c9c2 100644 --- a/code/controllers/subsystem/server_maint.dm +++ b/code/controllers/subsystem/server_maint.dm @@ -9,6 +9,9 @@ SUBSYSTEM_DEF(server_maint) runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT var/list/currentrun +/datum/controller/subsystem/server_maint/PreInit() + world.hub_password = "" //quickly! before the hubbies see us. + /datum/controller/subsystem/server_maint/Initialize(timeofday) if (CONFIG_GET(flag/hub)) world.update_hub_visibility(TRUE) diff --git a/code/controllers/subsystem/stickyban.dm b/code/controllers/subsystem/stickyban.dm index 189efa99fedb..5568be58c7bd 100644 --- a/code/controllers/subsystem/stickyban.dm +++ b/code/controllers/subsystem/stickyban.dm @@ -1,34 +1,207 @@ SUBSYSTEM_DEF(stickyban) - name = "Sticky Ban" + name = "PRISM" init_order = INIT_ORDER_STICKY_BAN flags = SS_NO_FIRE var/list/cache = list() + var/list/dbcache = list() + var/list/confirmed_exempt = list() + var/dbcacheexpire = 0 + /datum/controller/subsystem/stickyban/Initialize(timeofday) - var/list/bannedkeys = world.GetConfig("ban") + var/list/bannedkeys = sticky_banned_ckeys() //sanitize the sticky ban list + + //delete db bans that no longer exist in the database and add new legacy bans to the database + if (SSdbcore.Connect() || length(SSstickyban.dbcache)) + for (var/oldban in (world.GetConfig("ban") - bannedkeys)) + var/ckey = ckey(oldban) + if (ckey != oldban && (ckey in bannedkeys)) + continue + + var/list/ban = params2list(world.GetConfig("ban", oldban)) + if (ban && !ban["fromdb"]) + if (!import_raw_stickyban_to_db(ckey, ban)) + log_world("Could not import stickyban on [oldban] into the database. Ignoring") + continue + dbcacheexpire = 0 + bannedkeys += ckey + world.SetConfig("ban", oldban, null) + + for (var/bannedkey in bannedkeys) var/ckey = ckey(bannedkey) - var/list/ban = stickyban2list(world.GetConfig("ban", bannedkey)) + var/list/ban = get_stickyban_from_ckey(bannedkey) - //byond stores sticky bans by key, that can end up confusing things - //i also remove it here so that if any stickybans cause a runtime, they just stop existing - world.SetConfig("ban", bannedkey, null) + //byond stores sticky bans by key, that's lame + if (ckey != bannedkey) + world.SetConfig("ban", bannedkey, null) if (!ban["ckey"]) ban["ckey"] = ckey - //storing these can break things and isn't needed for sticky ban tracking - ban -= "IP" - ban -= "computer_id" - ban["matches_this_round"] = list() ban["existing_user_matches_this_round"] = list() ban["admin_matches_this_round"] = list() + ban["pending_matches_this_round"] = list() + cache[ckey] = ban - - for (var/bannedckey in cache) - world.SetConfig("ban", bannedckey, list2stickyban(cache[bannedckey])) + world.SetConfig("ban", ckey, list2stickyban(ban)) return ..() + +/datum/controller/subsystem/stickyban/proc/Populatedbcache() + var/newdbcache = list() //so if we runtime or the db connection dies we don't kill the existing cache + + var/datum/DBQuery/query_stickybans = SSdbcore.NewQuery("SELECT ckey, reason, banning_admin, datetime FROM [format_table_name("stickyban")] ORDER BY ckey") + var/datum/DBQuery/query_ckey_matches = SSdbcore.NewQuery("SELECT stickyban, matched_ckey, first_matched, last_matched, exempt FROM [format_table_name("stickyban_matched_ckey")] ORDER BY first_matched") + var/datum/DBQuery/query_cid_matches = SSdbcore.NewQuery("SELECT stickyban, matched_cid, first_matched, last_matched FROM [format_table_name("stickyban_matched_cid")] ORDER BY first_matched") + var/datum/DBQuery/query_ip_matches = SSdbcore.NewQuery("SELECT stickyban, INET_NTOA(matched_ip), first_matched, last_matched FROM [format_table_name("stickyban_matched_ip")] ORDER BY first_matched") + + SSdbcore.QuerySelect(list(query_stickybans, query_ckey_matches, query_cid_matches, query_ip_matches)) + + if (query_stickybans.last_error) + qdel(query_stickybans) + qdel(query_ckey_matches) + qdel(query_cid_matches) + qdel(query_ip_matches) + return + + while (query_stickybans.NextRow()) + var/list/ban = list() + + ban["ckey"] = query_stickybans.item[1] + ban["message"] = query_stickybans.item[2] + ban["reason"] = "(InGameBan)([query_stickybans.item[3]])" + ban["admin"] = query_stickybans.item[3] + ban["datetime"] = query_stickybans.item[4] + ban["type"] = list("sticky") + + newdbcache["[query_stickybans.item[1]]"] = ban + + + if (!query_ckey_matches.last_error) + while (query_ckey_matches.NextRow()) + var/list/match = list() + + match["stickyban"] = query_ckey_matches.item[1] + match["matched_ckey"] = query_ckey_matches.item[2] + match["first_matched"] = query_ckey_matches.item[3] + match["last_matched"] = query_ckey_matches.item[4] + match["exempt"] = text2num(query_ckey_matches.item[5]) + + var/ban = newdbcache[query_ckey_matches.item[1]] + if (!ban) + continue + var/keys = ban[text2num(query_ckey_matches.item[5]) ? "whitelist" : "keys"] + if (!keys) + keys = ban[text2num(query_ckey_matches.item[5]) ? "whitelist" : "keys"] = list() + keys[query_ckey_matches.item[2]] = match + + if (!query_cid_matches.last_error) + while (query_cid_matches.NextRow()) + var/list/match = list() + + match["stickyban"] = query_cid_matches.item[1] + match["matched_cid"] = query_cid_matches.item[2] + match["first_matched"] = query_cid_matches.item[3] + match["last_matched"] = query_cid_matches.item[4] + + var/ban = newdbcache[query_cid_matches.item[1]] + if (!ban) + continue + var/computer_ids = ban["computer_id"] + if (!computer_ids) + computer_ids = ban["computer_id"] = list() + computer_ids[query_cid_matches.item[2]] = match + + + if (!query_ip_matches.last_error) + while (query_ip_matches.NextRow()) + var/list/match = list() + + match["stickyban"] = query_ip_matches.item[1] + match["matched_ip"] = query_ip_matches.item[2] + match["first_matched"] = query_ip_matches.item[3] + match["last_matched"] = query_ip_matches.item[4] + + var/ban = newdbcache[query_ip_matches.item[1]] + if (!ban) + continue + var/IPs = ban["IP"] + if (!IPs) + IPs = ban["IP"] = list() + IPs[query_ip_matches.item[2]] = match + + dbcache = newdbcache + dbcacheexpire = world.time+STICKYBAN_DB_CACHE_TIME + + qdel(query_stickybans) + qdel(query_ckey_matches) + qdel(query_cid_matches) + qdel(query_ip_matches) + + +/datum/controller/subsystem/stickyban/proc/import_raw_stickyban_to_db(ckey, list/ban) + . = FALSE + if (!ban["admin"]) + ban["admin"] = "LEGACY" + if (!ban["message"]) + ban["message"] = "Evasion" + + var/datum/DBQuery/query_create_stickyban = SSdbcore.NewQuery("INSERT IGNORE INTO [format_table_name("stickyban")] (ckey, reason, banning_admin) VALUES ('[sanitizeSQL(ckey)]', '[sanitizeSQL(ban["message"])]', '[sanitizeSQL(ban["admin"])]')") + if (!query_create_stickyban.warn_execute()) + qdel(query_create_stickyban) + return + qdel(query_create_stickyban) + + var/list/sqlckeys = list() + var/list/sqlcids = list() + var/list/sqlips = list() + + if (ban["keys"]) + var/list/keys = splittext(ban["keys"], ",") + for (var/key in keys) + var/list/sqlckey = list() + sqlckey["stickyban"] = "'[sanitizeSQL(ckey)]'" + sqlckey["matched_ckey"] = "'[sanitizeSQL(ckey(key))]'" + sqlckey["exempt"] = FALSE + sqlckeys[++sqlckeys.len] = sqlckey + + if (ban["whitelist"]) + var/list/keys = splittext(ban["whitelist"], ",") + for (var/key in keys) + var/list/sqlckey = list() + sqlckey["stickyban"] = "'[sanitizeSQL(ckey)]'" + sqlckey["matched_ckey"] = "'[sanitizeSQL(ckey(key))]'" + sqlckey["exempt"] = TRUE + sqlckeys[++sqlckeys.len] = sqlckey + + if (ban["computer_id"]) + var/list/cids = splittext(ban["computer_id"], ",") + for (var/cid in cids) + var/list/sqlcid = list() + sqlcid["stickyban"] = "'[sanitizeSQL(ckey)]'" + sqlcid["matched_cid"] = "'[sanitizeSQL(cid)]'" + sqlcids[++sqlcids.len] = sqlcid + + if (ban["IP"]) + var/list/ips = splittext(ban["IP"], ",") + for (var/ip in ips) + var/list/sqlip = list() + sqlip["stickyban"] = "'[sanitizeSQL(ckey)]'" + sqlip["matched_ip"] = "'[sanitizeSQL(ip)]'" + sqlips[++sqlips.len] = sqlip + + if (length(sqlckeys)) + SSdbcore.MassInsert(format_table_name("stickyban_matched_ckey"), sqlckeys, FALSE, TRUE) + + if (length(sqlcids)) + SSdbcore.MassInsert(format_table_name("stickyban_matched_cid"), sqlcids, FALSE, TRUE) + + if (length(sqlips)) + SSdbcore.MassInsert(format_table_name("stickyban_matched_ip"), sqlips, FALSE, TRUE) + + + return TRUE diff --git a/code/game/world.dm b/code/game/world.dm index b02ac5636349..d4eaa8314c8e 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -20,6 +20,8 @@ GLOBAL_VAR(restart_counter) config.Load(params[OVERRIDE_CONFIG_DIRECTORY_PARAMETER]) + load_admins() + //SetupLogs depends on the RoundID, so lets check //DB schema and set RoundID if we can SSdbcore.CheckSchemaVersion() @@ -30,9 +32,12 @@ GLOBAL_VAR(restart_counter) world.log = file("[GLOB.log_directory]/dd.log") #endif +<<<<<<< HEAD load_yogs_stuff() // yogs - Donators refresh_admin_files() //yogs - DB support load_admins() +======= +>>>>>>> c961d93003... Merge pull request #42899 from MrStonedOne/sqlstickybans LoadVerbs(/datum/verbs/menu) if(CONFIG_GET(flag/usewhitelist)) load_whitelist() diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index b4b9f7b4415e..f19eb7372186 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -2,32 +2,37 @@ //How many new ckey matches before we revert the stickyban to it's roundstart state //These are exclusive, so once it goes over one of these numbers, it reverts the ban -#define STICKYBAN_MAX_MATCHES 20 -#define STICKYBAN_MAX_EXISTING_USER_MATCHES 5 //ie, users who were connected before the ban triggered -#define STICKYBAN_MAX_ADMIN_MATCHES 2 +#define STICKYBAN_MAX_MATCHES 15 +#define STICKYBAN_MAX_EXISTING_USER_MATCHES 3 //ie, users who were connected before the ban triggered +#define STICKYBAN_MAX_ADMIN_MATCHES 1 -/world/IsBanned(key,address,computer_id,type,real_bans_only=FALSE) - if (!key || !address || !computer_id) +/world/IsBanned(key, address, computer_id, type, real_bans_only=FALSE) + debug_world_log("isbanned(): '[args.Join("', '")]'") + if (!key || (!real_bans_only && (!address || !computer_id))) if(real_bans_only) return FALSE log_access("Failed Login (invalid data): [key] [address]-[computer_id]") return list("reason"="invalid login data", "desc"="Error: Could not check ban status, Please try again. Error message: Your computer provided invalid or blank information to the server on connection (byond username, IP, and Computer ID.) Provided information for reference: Username:'[key]' IP:'[address]' Computer ID:'[computer_id]'. (If you continue to get this error, please restart byond or contact byond support.)") - if (text2num(computer_id) == 2147483647) //this cid causes stickybans to go haywire - log_access("Failed Login (invalid cid): [key] [address]-[computer_id]") - return list("reason"="invalid login data", "desc"="Error: Could not check ban status, Please try again. Error message: Your computer provided an invalid Computer ID.)") - var/admin = 0 + var/admin = FALSE var/ckey = ckey(key) + + //IsBanned can get re-called on a user in certain situations, this prevents that leading to repeated messages to admins. + var/static/list/checkedckeys = list() + //magic voodo to check for a key in a list while also adding that key to the list without having to do two associated lookups + var/message = !checkedckeys[ckey]++ + if(GLOB.admin_datums[ckey] || GLOB.deadmins[ckey]) - admin = 1 + admin = TRUE //Whitelist if(CONFIG_GET(flag/usewhitelist)) if(!check_whitelist(ckey)) if (admin) log_admin("The admin [key] has been allowed to bypass the whitelist") - message_admins("The admin [key] has been allowed to bypass the whitelist") - addclientmessage(ckey,"You have been allowed to bypass the whitelist") + if (message) + message_admins("The admin [key] has been allowed to bypass the whitelist") + addclientmessage(ckey,"You have been allowed to bypass the whitelist") else log_access("Failed Login: [key] - Not on whitelist") return list("reason"="whitelist", "desc" = "\nReason: You are not on the white list for this server") @@ -46,11 +51,13 @@ if(!real_bans_only && extreme_popcap && living_player_count() >= extreme_popcap && !admin) log_access("Failed Login: [key] - Population cap reached") return list("reason"="popcap", "desc"= "\nReason: [CONFIG_GET(string/extreme_popcap_message)]") + if(CONFIG_GET(flag/sql_enabled)) if(!SSdbcore.Connect()) var/msg = "Ban database connection failure. Key [ckey] not checked" log_world(msg) - message_admins(msg) + if (message) + message_admins(msg) else var/list/ban_details = is_banned_from_with_details(ckey, address, computer_id, "Server") for(var/i in ban_details) @@ -58,12 +65,14 @@ if(text2num(i["applies_to_admins"])) var/msg = "Admin [key] is admin banned, and has been disallowed access." log_admin(msg) - message_admins(msg) + if (message) + message_admins(msg) else var/msg = "Admin [key] has been allowed to bypass a matching non-admin ban on [i["key"]] [i["ip"]]-[i["computerid"]]." log_admin(msg) - message_admins(msg) - addclientmessage(ckey,"Admin [key] has been allowed to bypass a matching non-admin ban on [i["key"]] [i["ip"]]-[i["computerid"]].") + if (message) + message_admins(msg) + addclientmessage(ckey,"Admin [key] has been allowed to bypass a matching non-admin ban on [i["key"]] [i["ip"]]-[i["computerid"]].") continue var/expires = "This is a permanent ban." if(i["expiration_time"]) @@ -74,18 +83,24 @@ [expires] If you wish to appeal this ban please use the keyword 'assistantgreytide' to register an account on the forums."} //yogs log_access("Failed Login: [key] [computer_id] [address] - Banned (#[i["id"]])") return list("reason"="Banned","desc"="[desc]") + var/list/ban = ..() //default pager ban stuff + if (ban) + if (!admin) + . = ban + if (real_bans_only) + return var/bannedckey = "ERROR" if (ban["ckey"]) bannedckey = ban["ckey"] var/newmatch = FALSE var/client/C = GLOB.directory[ckey] - var/cachedban = SSstickyban.cache[bannedckey] - + var/list/cachedban = SSstickyban.cache[bannedckey] //rogue ban in the process of being reverted. - if (cachedban && cachedban["reverting"]) + if (cachedban && (cachedban["reverting"] || cachedban["timeout"])) + world.SetConfig("ban", bannedckey, null) return null if (cachedban && ckey != bannedckey) @@ -98,51 +113,80 @@ if (newmatch && cachedban) var/list/newmatches = cachedban["matches_this_round"] + var/list/pendingmatches = cachedban["matches_this_round"] var/list/newmatches_connected = cachedban["existing_user_matches_this_round"] var/list/newmatches_admin = cachedban["admin_matches_this_round"] - newmatches[ckey] = ckey if (C) newmatches_connected[ckey] = ckey + newmatches_connected = cachedban["existing_user_matches_this_round"] + pendingmatches[ckey] = ckey + sleep(STICKYBAN_ROGUE_CHECK_TIME) + pendingmatches -= ckey if (admin) newmatches_admin[ckey] = ckey + if (cachedban["reverting"] || cachedban["timeout"]) + return null + + newmatches[ckey] = ckey + + if (\ - newmatches.len > STICKYBAN_MAX_MATCHES || \ + newmatches.len+pendingmatches.len > STICKYBAN_MAX_MATCHES || \ newmatches_connected.len > STICKYBAN_MAX_EXISTING_USER_MATCHES || \ newmatches_admin.len > STICKYBAN_MAX_ADMIN_MATCHES \ - ) - if (cachedban["reverting"]) - return null - cachedban["reverting"] = TRUE + ) + + var/action + if (ban["fromdb"]) + cachedban["timeout"] = TRUE + action = "putting it on timeout for the remainder of the round" + else + cachedban["reverting"] = TRUE + action = "reverting to its roundstart state" world.SetConfig("ban", bannedckey, null) - log_game("Stickyban on [bannedckey] detected as rogue, reverting to its roundstart state") - message_admins("Stickyban on [bannedckey] detected as rogue, reverting to its roundstart state") + //we always report this + log_game("Stickyban on [bannedckey] detected as rogue, [action]") + message_admins("Stickyban on [bannedckey] detected as rogue, [action]") //do not convert to timer. spawn (5) world.SetConfig("ban", bannedckey, null) sleep(1) world.SetConfig("ban", bannedckey, null) - cachedban["matches_this_round"] = list() - cachedban["existing_user_matches_this_round"] = list() - cachedban["admin_matches_this_round"] = list() - cachedban -= "reverting" - world.SetConfig("ban", bannedckey, list2stickyban(cachedban)) + if (!ban["fromdb"]) + cachedban = cachedban.Copy() //so old references to the list still see the ban as reverting + cachedban["matches_this_round"] = list() + cachedban["existing_user_matches_this_round"] = list() + cachedban["admin_matches_this_round"] = list() + cachedban -= "reverting" + SSstickyban.cache[bannedckey] = cachedban + world.SetConfig("ban", bannedckey, list2stickyban(cachedban)) return null + if (ban["fromdb"]) + if(SSdbcore.Connect()) + INVOKE_ASYNC(SSdbcore, /datum/controller/subsystem/dbcore/proc.QuerySelect, list( + SSdbcore.NewQuery("INSERT INTO [format_table_name("stickyban_matched_ckey")] (matched_ckey, stickyban) VALUES ('[sanitizeSQL(ckey)]', '[sanitizeSQL(bannedckey)]') ON DUPLICATE KEY UPDATE last_matched = now()"), + SSdbcore.NewQuery("INSERT INTO [format_table_name("stickyban_matched_ip")] (matched_ip, stickyban) VALUES ( INET_ATON('[sanitizeSQL(address)]'), '[sanitizeSQL(bannedckey)]') ON DUPLICATE KEY UPDATE last_matched = now()"), + SSdbcore.NewQuery("INSERT INTO [format_table_name("stickyban_matched_cid")] (matched_cid, stickyban) VALUES ('[sanitizeSQL(computer_id)]', '[sanitizeSQL(bannedckey)]') ON DUPLICATE KEY UPDATE last_matched = now()") + ), FALSE, TRUE) + + //byond will not trigger isbanned() for "global" host bans, //ie, ones where the "apply to this game only" checkbox is not checked (defaults to not checked) //So it's safe to let admins walk thru host/sticky bans here if (admin) log_admin("The admin [key] has been allowed to bypass a matching host/sticky ban on [bannedckey]") - message_admins("The admin [key] has been allowed to bypass a matching host/sticky ban on [bannedckey]") - addclientmessage(ckey,"You have been allowed to bypass a matching host/sticky ban on [bannedckey]") + if (message) + message_admins("The admin [key] has been allowed to bypass a matching host/sticky ban on [bannedckey]") + addclientmessage(ckey,"You have been allowed to bypass a matching host/sticky ban on [bannedckey]") return null if (C) //user is already connected!. - to_chat(C, "You are about to get disconnected for matching a sticky ban after you connected. If this turns out to be the ban evasion detection system going haywire, we will automatically detect this and revert the matches. if you feel that this is the case, please wait EXACTLY 6 seconds then reconnect using file -> reconnect to see if the match was reversed.") + to_chat(C, "You are about to get disconnected for matching a sticky ban after you connected. If this turns out to be the ban evasion detection system going haywire, we will automatically detect this and revert the matches. if you feel that this is the case, please wait EXACTLY 6 seconds then reconnect using file -> reconnect to see if the match was automatically reversed.") var/desc = "\nReason:(StickyBan) You, or another user of this computer or connection ([bannedckey]) is banned from playing here. The ban reason is:\n[ban["message"]]\nThis ban was applied by [ban["admin"]]\nThis is a BanEvasion Detection System ban, if you think this ban is a mistake, please wait EXACTLY 6 seconds, then try again before filing an appeal. If you wish to appeal this ban please use the keyword 'assistantgreytide' to register an account on the forums.\n" //yogs . = list("reason" = "Stickyban", "desc" = desc) diff --git a/code/modules/admin/stickyban.dm b/code/modules/admin/stickyban.dm index df6a9b89ad46..b5ae1022a97f 100644 --- a/code/modules/admin/stickyban.dm +++ b/code/modules/admin/stickyban.dm @@ -7,7 +7,7 @@ if ("add") var/list/ban = list() var/ckey - ban["admin"] = usr.key + ban["admin"] = usr.ckey ban["type"] = list("sticky") ban["reason"] = "(InGameBan)([usr.key])" //this will be displayed in dd only @@ -22,6 +22,7 @@ if (get_stickyban_from_ckey(ckey)) to_chat(usr, "Error: Can not add a stickyban: User already has a current sticky ban") + return if (data["reason"]) ban["message"] = data["reason"] @@ -31,7 +32,19 @@ return ban["message"] = "[reason]" + if(SSdbcore.Connect()) + var/datum/DBQuery/query_create_stickyban = SSdbcore.NewQuery("INSERT INTO [format_table_name("stickyban")] (ckey, reason, banning_admin) VALUES ('[sanitizeSQL(ckey)]', '[sanitizeSQL(ban["message"])]', '[sanitizeSQL(usr.ckey)]')") + if (query_create_stickyban.warn_execute()) + ban["fromdb"] = TRUE + qdel(query_create_stickyban) + world.SetConfig("ban",ckey,list2stickyban(ban)) + ban = stickyban2list(list2stickyban(ban)) + ban["matches_this_round"] = list() + ban["existing_user_matches_this_round"] = list() + ban["admin_matches_this_round"] = list() + ban["pending_matches_this_round"] = list() + SSstickyban.cache[ckey] = ban log_admin_private("[key_name(usr)] has stickybanned [ckey].\nReason: [ban["message"]]") message_admins("[key_name_admin(usr)] has stickybanned [ckey].\nReason: [ban["message"]]") @@ -51,6 +64,16 @@ to_chat(usr, "Error: The ban disappeared.") return world.SetConfig("ban",ckey, null) + SSstickyban.cache -= ckey + + if (SSdbcore.Connect()) + SSdbcore.QuerySelect(list( + SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban")] WHERE ckey = '[sanitizeSQL(ckey)]'"), + SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = '[sanitizeSQL(ckey)]'"), + SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_cid")] WHERE stickyban = '[sanitizeSQL(ckey)]'"), + SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ip")] WHERE stickyban = '[sanitizeSQL(ckey)]'") + ), warn = TRUE, qdel = TRUE) + log_admin_private("[key_name(usr)] removed [ckey]'s stickyban") message_admins("[key_name_admin(usr)] removed [ckey]'s stickyban") @@ -67,18 +90,12 @@ to_chat(usr, "Error: No sticky ban for [ckey] found!") return - var/found = 0 - //we have to do it this way because byond keeps the case in its sticky ban matches WHY!!! - for (var/key in ban["keys"]) - if (ckey(key) == alt) - found = 1 - break - - if (!found) + var/key = LAZYACCESS(ban["keys"], alt) + if (!key) to_chat(usr, "Error: [alt] is not linked to [ckey]'s sticky ban!") return - if (alert("Are you sure you want to disassociate [alt] from [ckey]'s sticky ban? \nNote: Nothing stops byond from re-linking them","Are you sure","Yes","No") == "No") + if (alert("Are you sure you want to disassociate [alt] from [ckey]'s sticky ban? \nNote: Nothing stops byond from re-linking them, Use \[E] to exempt them","Are you sure","Yes","No") == "No") return //we have to do this again incase something changes @@ -87,19 +104,22 @@ to_chat(usr, "Error: The ban disappeared.") return - found = 0 - for (var/key in ban["keys"]) - if (ckey(key) == alt) - ban["keys"] -= key - found = 1 - break + key = LAZYACCESS(ban["keys"], alt) - if (!found) + if (!key) to_chat(usr, "Error: [alt] link to [ckey]'s sticky ban disappeared.") return + LAZYREMOVE(ban["keys"], alt) world.SetConfig("ban",ckey,list2stickyban(ban)) + SSstickyban.cache[ckey] = ban + + if (SSdbcore.Connect()) + var/datum/DBQuery/query_remove_stickyban_alt = SSdbcore.NewQuery("DELETE FROM [format_table_name("stickyban_matched_ckey")] WHERE stickyban = '[sanitizeSQL(ckey)]' AND matched_ckey = '[sanitizeSQL(alt)]'") + query_remove_stickyban_alt.warn_execute() + qdel(query_remove_stickyban_alt) + log_admin_private("[key_name(usr)] has disassociated [alt] from [ckey]'s sticky ban") message_admins("[key_name_admin(usr)] has disassociated [alt] from [ckey]'s sticky ban") @@ -124,14 +144,171 @@ world.SetConfig("ban",ckey,list2stickyban(ban)) + SSstickyban.cache[ckey] = ban + + if (SSdbcore.Connect()) + var/datum/DBQuery/query_edit_stickyban = SSdbcore.NewQuery("UPDATE [format_table_name("stickyban")] SET reason = '[sanitizeSQL(reason)]' WHERE ckey = '[sanitizeSQL(ckey)]'") + query_edit_stickyban.warn_execute() + qdel(query_edit_stickyban) + log_admin_private("[key_name(usr)] has edited [ckey]'s sticky ban reason from [oldreason] to [reason]") message_admins("[key_name_admin(usr)] has edited [ckey]'s sticky ban reason from [oldreason] to [reason]") + if ("exempt") + if (!data["ckey"]) + return + var/ckey = data["ckey"] + if (!data["alt"]) + return + var/alt = ckey(data["alt"]) + var/ban = get_stickyban_from_ckey(ckey) + if (!ban) + to_chat(usr, "Error: No sticky ban for [ckey] found!") + return + + var/key = LAZYACCESS(ban["keys"], alt) + if (!key) + to_chat(usr, "Error: [alt] is not linked to [ckey]'s sticky ban!") + return + + if (alert("Are you sure you want to exempt [alt] from [ckey]'s sticky ban?","Are you sure","Yes","No") == "No") + return + + //we have to do this again incase something changes + ban = get_stickyban_from_ckey(ckey) + if (!ban) + to_chat(usr, "Error: The ban disappeared.") + return + + key = LAZYACCESS(ban["keys"], alt) + + if (!key) + to_chat(usr, "Error: [alt]'s link to [ckey]'s sticky ban disappeared.") + return + LAZYREMOVE(ban["keys"], alt) + key["exempt"] = TRUE + LAZYSET(ban["whitelist"], alt, key) + + world.SetConfig("ban",ckey,list2stickyban(ban)) + + SSstickyban.cache[ckey] = ban + + if (SSdbcore.Connect()) + var/datum/DBQuery/query_exempt_stickyban_alt = SSdbcore.NewQuery("UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 1 WHERE stickyban = '[sanitizeSQL(ckey)]' AND matched_ckey = '[sanitizeSQL(alt)]'") + query_exempt_stickyban_alt.warn_execute() + qdel(query_exempt_stickyban_alt) + + log_admin_private("[key_name(usr)] has exempted [alt] from [ckey]'s sticky ban") + message_admins("[key_name_admin(usr)] has exempted [alt] from [ckey]'s sticky ban") + + if ("unexempt") + if (!data["ckey"]) + return + var/ckey = data["ckey"] + if (!data["alt"]) + return + var/alt = ckey(data["alt"]) + var/ban = get_stickyban_from_ckey(ckey) + if (!ban) + to_chat(usr, "Error: No sticky ban for [ckey] found!") + return + + var/key = LAZYACCESS(ban["whitelist"], alt) + if (!key) + to_chat(usr, "Error: [alt] is not exempt from [ckey]'s sticky ban!") + return + + if (alert("Are you sure you want to unexempt [alt] from [ckey]'s sticky ban?","Are you sure","Yes","No") == "No") + return + + //we have to do this again incase something changes + ban = get_stickyban_from_ckey(ckey) + if (!ban) + to_chat(usr, "Error: The ban disappeared.") + return + + key = LAZYACCESS(ban["whitelist"], alt) + if (!key) + to_chat(usr, "Error: [alt]'s exemption from [ckey]'s sticky ban disappeared.") + return + + LAZYREMOVE(ban["whitelist"], alt) + key["exempt"] = FALSE + LAZYSET(ban["keys"], alt, key) + + world.SetConfig("ban",ckey,list2stickyban(ban)) + + SSstickyban.cache[ckey] = ban + + if (SSdbcore.Connect()) + var/datum/DBQuery/query_unexempt_stickyban_alt = SSdbcore.NewQuery("UPDATE [format_table_name("stickyban_matched_ckey")] SET exempt = 0 WHERE stickyban = '[sanitizeSQL(ckey)]' AND matched_ckey = '[sanitizeSQL(alt)]'") + query_unexempt_stickyban_alt.warn_execute() + qdel(query_unexempt_stickyban_alt) + + log_admin_private("[key_name(usr)] has unexempted [alt] from [ckey]'s sticky ban") + message_admins("[key_name_admin(usr)] has unexempted [alt] from [ckey]'s sticky ban") + + if ("timeout") + if (!data["ckey"]) + return + if (!SSdbcore.Connect()) + to_chat(usr, "No database connection!") + return + + var/ckey = data["ckey"] + + if (alert("Are you sure you want to put [ckey]'s stickyban on timeout until next round (or removed)?","Are you sure","Yes","No") == "No") + return + var/ban = get_stickyban_from_ckey(ckey) + if (!ban) + to_chat(usr, "Error: No sticky ban for [ckey] found!") + return + + ban["timeout"] = TRUE + + world.SetConfig("ban", ckey, null) + + var/cachedban = SSstickyban.cache[ckey] + if (cachedban) + cachedban["timeout"] = TRUE + + log_admin_private("[key_name(usr)] has put [ckey]'s sticky ban on timeout.") + message_admins("[key_name_admin(usr)] has put [ckey]'s sticky ban on timeout.") + + if ("untimeout") + if (!data["ckey"]) + return + if (!SSdbcore.Connect()) + to_chat(usr, "No database connection!") + return + var/ckey = data["ckey"] + + if (alert("Are you sure you want to lift the timeout on [ckey]'s stickyban?","Are you sure","Yes","No") == "No") + return + + var/ban = get_stickyban_from_ckey(ckey) + var/cachedban = SSstickyban.cache[ckey] + if (cachedban) + cachedban["timeout"] = FALSE + if (!ban) + if (!cachedban) + to_chat(usr, "Error: No sticky ban for [ckey] found!") + return + ban = cachedban + + ban["timeout"] = FALSE + + world.SetConfig("ban",ckey,list2stickyban(ban)) + + log_admin_private("[key_name(usr)] has taken [ckey]'s sticky ban off of timeout.") + message_admins("[key_name_admin(usr)] has taken [ckey]'s sticky ban off of timeout.") + + if ("revert") if (!data["ckey"]) return var/ckey = data["ckey"] - if (alert("Are you sure you want to revert the sticky ban on [ckey] to its state at round start?","Are you sure","Yes","No") == "No") + if (alert("Are you sure you want to revert the sticky ban on [ckey] to its state at round start (or last edit)?","Are you sure","Yes","No") == "No") return var/ban = get_stickyban_from_ckey(ckey) if (!ban) @@ -150,14 +327,22 @@ world.SetConfig("ban",ckey,list2stickyban(cached_ban)) -/datum/admins/proc/stickyban_gethtml(ckey, ban) - . = {" +/datum/admins/proc/stickyban_gethtml(ckey) + var/ban = get_stickyban_from_ckey(ckey) + if (!ban) + return + var/timeout + if (SSdbcore.Connect()) + timeout = "\[[(ban["timeout"] ? "untimeout" : "timeout" )]\]" + else + timeout = "\[revert\]" + . = list({" \[-\] - \[revert\] + [timeout] [ckey]
" [ban["message"]] \[Edit\]
- "} + "}) if (ban["admin"]) . += "[ban["admin"]]
" else @@ -166,19 +351,24 @@ for (var/key in ban["keys"]) if (ckey(key) == ckey) continue - . += "
  • \[-\][key]
  • " + . += "
  • \[-\][key]\[E\]
  • " + + for (var/key in ban["whitelist"]) + if (ckey(key) == ckey) + continue + . += "
  • \[-\][key]\[UE\]
  • " + . += "\n" /datum/admins/proc/stickyban_show() if(!check_rights(R_BAN)) return - var/list/bans = sortList(world.GetConfig("ban")) - var/banhtml = "" + var/list/bans = sticky_banned_ckeys() + var/list/banhtml = list() for(var/key in bans) var/ckey = ckey(key) - var/ban = stickyban2list(world.GetConfig("ban",key)) banhtml += "

    \n" - banhtml += stickyban_gethtml(ckey,ban) + banhtml += stickyban_gethtml(ckey) var/html = {" @@ -186,22 +376,49 @@

    All Sticky Bans:

    \[+\]
    - [banhtml] + [banhtml.Join("")] "} usr << browse(html,"window=stickybans;size=700x400") +/proc/sticky_banned_ckeys() + if (SSdbcore.Connect() || length(SSstickyban.dbcache)) + if (SSstickyban.dbcacheexpire < world.time) + SSstickyban.Populatedbcache() + if (SSstickyban.dbcacheexpire) + return SSstickyban.dbcache.Copy() + + return sortList(world.GetConfig("ban")) + + /proc/get_stickyban_from_ckey(var/ckey) + . = list() if (!ckey) return null - ckey = ckey(ckey) - . = null - for (var/key in world.GetConfig("ban")) - if (ckey(key) == ckey) - . = stickyban2list(world.GetConfig("ban",key)) - break + if (SSdbcore.Connect() || length(SSstickyban.dbcache)) + if (SSstickyban.dbcacheexpire < world.time) + SSstickyban.Populatedbcache() + if (SSstickyban.dbcacheexpire) + . = SSstickyban.dbcache[ckey] + //reset the cache incase its a newer ban (but only if we didn't update the cache recently) + if (!. && SSstickyban.dbcacheexpire != world.time+STICKYBAN_DB_CACHE_TIME) + SSstickyban.dbcacheexpire = 1 + SSstickyban.Populatedbcache() + . = SSstickyban.dbcache[ckey] + if (.) + var/list/cachedban = SSstickyban.cache["[ckey]"] + if (cachedban) + .["timeout"] = cachedban["timeout"] -/proc/stickyban2list(var/ban) + .["fromdb"] = TRUE + return + + . = stickyban2list(world.GetConfig("ban", ckey)) || stickyban2list(world.GetConfig("ban", ckey(ckey))) || list() + + if (!length(.)) + return null + +/proc/stickyban2list(ban, strictdb = TRUE) if (!ban) return null . = params2list(ban) @@ -212,30 +429,40 @@ var/ckey = ckey(key) ckeys[ckey] = ckey //to make searching faster. .["keys"] = ckeys + if (.["whitelist"]) + var/keys = splittext(.["whitelist"], ",") + var/ckeys = list() + for (var/key in keys) + var/ckey = ckey(key) + ckeys[ckey] = ckey //to make searching faster. + .["whitelist"] = ckeys .["type"] = splittext(.["type"], ",") .["IP"] = splittext(.["IP"], ",") .["computer_id"] = splittext(.["computer_id"], ",") + . -= "fromdb" -/proc/list2stickyban(var/list/ban) +/proc/list2stickyban(list/ban) if (!ban || !islist(ban)) return null . = ban.Copy() if (.["keys"]) .["keys"] = jointext(.["keys"], ",") + if (.["IP"]) + .["IP"] = jointext(.["IP"], ",") + if (.["computer_id"]) + .["computer_id"] = jointext(.["computer_id"], ",") + if (.["whitelist"]) + .["whitelist"] = jointext(.["whitelist"], ",") if (.["type"]) .["type"] = jointext(.["type"], ",") - //internal tracking only, shouldn't be stored + . -= "reverting" + . -= "matches_this_round" . -= "existing_user_matches_this_round" . -= "admin_matches_this_round" - . -= "matches_this_round" - . -= "reverting" + . -= "pending_matches_this_round" - //storing these can sometimes cause sticky bans to start matching everybody - // and isn't even needed for sticky ban matching, as the hub tracks these separately - . -= "IP" - . -= "computer_id" . = list2params(.) diff --git a/code/modules/goonchat/browserOutput.dm b/code/modules/goonchat/browserOutput.dm index 4cb918dbbd97..fe9e05f56462 100644 --- a/code/modules/goonchat/browserOutput.dm +++ b/code/modules/goonchat/browserOutput.dm @@ -174,7 +174,7 @@ GLOBAL_DATUM_INIT(iconCache, /savefile, new("tmp/iconCache.sav")) //Cache of ico var/list/row = src.connectionHistory[i] if (!row || row.len < 3 || (!row["ckey"] || !row["compid"] || !row["ip"])) //Passed malformed history object return - if (world.IsBanned(row["ckey"], row["compid"], row["ip"], real_bans_only=TRUE)) + if (world.IsBanned(row["ckey"], row["ip"], row["compid"], real_bans_only=TRUE)) found = row break diff --git a/code/world.dm b/code/world.dm index 344ca9be79ee..65d1e87680e2 100644 --- a/code/world.dm +++ b/code/world.dm @@ -7,6 +7,7 @@ area = /area/space view = "15x15" hub = "Exadv1.spacestation13" + hub_password = "kMZy3U5jJHSiBQjr" name = "/tg/ Station 13" fps = 20 #ifdef FIND_REF_NO_CHECK_TICK