diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index 0379517190f..e0f33226e8c 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -266,6 +266,8 @@ CREATE TABLE `player` ( `exp` mediumtext, `clientfps` smallint(4) DEFAULT '0', `atklog` smallint(4) DEFAULT '0', + `fuid` BIGINT(20) NULL DEFAULT NULL, + `fupdate` SMALLINT(4) NULL DEFAULT 0, PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB AUTO_INCREMENT=32446 DEFAULT CHARSET=latin1; @@ -523,15 +525,27 @@ CREATE TABLE `memo` ( /*!40101 SET character_set_client = @saved_cs_client */; -- --- Table structure for table `discord` +-- Table structure for table `ipintel` -- -DROP TABLE IF EXISTS `discord`; +DROP TABLE IF EXISTS `ipintel`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE IF NOT EXISTS `discord` ( - `ckey` varchar(32) NOT NULL, - `discord_id` bigint(20) NOT NULL, - `notify` int(11) NOT NULL, - PRIMARY KEY (`ckey`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; +CREATE TABLE `ipintel` ( +`ip` INT UNSIGNED NOT NULL , +`date` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL , +`intel` REAL NOT NULL DEFAULT '0', +PRIMARY KEY ( `ip` ) +) ENGINE = INNODB; /*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `vpn_whitelist` +-- +DROP TABLE IF EXISTS `vpn_whitelist`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `vpn_whitelist` ( + `ckey` VARCHAR(32) NOT NULL, + `reason` text + PRIMARY KEY (`ckey`) +) ENGINE=INNODB; diff --git a/SQL/paradise_schema_prefixed.sql b/SQL/paradise_schema_prefixed.sql index e9a622cf037..ecb28a867e4 100644 --- a/SQL/paradise_schema_prefixed.sql +++ b/SQL/paradise_schema_prefixed.sql @@ -265,6 +265,8 @@ CREATE TABLE `SS13_player` ( `exp` mediumtext, `clientfps` smallint(4) DEFAULT '0', `atklog` smallint(4) DEFAULT '0', + `fuid` BIGINT(20) NULL DEFAULT NULL, + `fupdate` SMALLINT(4) NULL DEFAULT 0, PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) ) ENGINE=InnoDB AUTO_INCREMENT=32446 DEFAULT CHARSET=latin1; @@ -522,15 +524,27 @@ CREATE TABLE `SS13_memo` ( /*!40101 SET character_set_client = @saved_cs_client */; -- --- Table structure for table `SS13_discord` +-- Table structure for table `SS13_ipintel` -- -DROP TABLE IF EXISTS `SS13_discord`; +DROP TABLE IF EXISTS `SS13_ipintel`; /*!40101 SET @saved_cs_client = @@character_set_client */; /*!40101 SET character_set_client = utf8 */; -CREATE TABLE IF NOT EXISTS `SS13_discord` ( - `ckey` varchar(32) NOT NULL, - `discord_id` bigint(20) NOT NULL, - `notify` int(11) NOT NULL, - PRIMARY KEY (`ckey`) -) ENGINE=InnoDB DEFAULT CHARSET=latin1; +CREATE TABLE `SS13_ipintel` ( +`ip` INT UNSIGNED NOT NULL , +`date` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL , +`intel` REAL NOT NULL DEFAULT '0', +PRIMARY KEY ( `ip` ) +) ENGINE = INNODB; /*!40101 SET character_set_client = @saved_cs_client */; + +-- +-- Table structure for table `SS13_vpn_whitelist` +-- +DROP TABLE IF EXISTS `SS13_vpn_whitelist`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8 */; +CREATE TABLE `SS13_vpn_whitelist` ( + `ckey` VARCHAR(32) NOT NULL, + `reason` text, + PRIMARY KEY (`ckey`) +) ENGINE=INNODB; \ No newline at end of file diff --git a/SQL/updates/5-6.sql b/SQL/updates/5-6.sql new file mode 100644 index 00000000000..91bf4328a2a --- /dev/null +++ b/SQL/updates/5-6.sql @@ -0,0 +1,34 @@ +#Updating the SQL from version 5 to version 6. -Kyep + +#Make a table to track the results of VPN/proxy lookups for IPs (IPINTEL, TG PORT) +CREATE TABLE `ipintel` ( +`ip` INT UNSIGNED NOT NULL , +`date` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL , +`intel` REAL NOT NULL DEFAULT '0', +PRIMARY KEY ( `ip` ) +) ENGINE = INNODB; + +#Make a table to track which ckeys are whitelisted for use of VPNs (IPINTEL, CUSTOM) +CREATE TABLE `vpn_whitelist` ( + `ckey` VARCHAR(32) NOT NULL, + `reason` text, + PRIMARY KEY (`ckey`) +) ENGINE=INNODB; + +# Add fuid (forum userid) which enables quick lookup of which ckey is associated with a specific forum account. (FORUM LINK) +ALTER TABLE `player` ADD `fuid` BIGINT(20) NULL DEFAULT NULL; +ALTER TABLE `player` ADD INDEX(`fuid`); + +# Add fupdate (forum update required) which flags specific ckeys as having been banned/unbanned, which requires an update of their forum/etc permissions (FORUM LINK) +ALTER TABLE `player` ADD `fupdate` SMALLINT(4) NULL DEFAULT 0; +ALTER TABLE `player` ADD INDEX(`fupdate`); + +#Make a table to track oauth tokens for linking forum/web accounts (FORUM LINK) +CREATE TABLE `oauth_tokens` ( + `ckey` VARCHAR(32) NOT NULL, + `token` VARCHAR(32) NOT NULL, + PRIMARY KEY (`token`) +) ENGINE=INNODB; + +#Drop the old 'discord' table that is not used anymore +DROP TABLE `discord`; diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm index 1c390bdf5ff..3418938d955 100644 --- a/code/__DEFINES/misc.dm +++ b/code/__DEFINES/misc.dm @@ -326,7 +326,7 @@ #define INVESTIGATE_BOMB "bombs" // The SQL version required by this version of the code -#define SQL_VERSION 5 +#define SQL_VERSION 6 // Vending machine stuff #define CAT_NORMAL 1 diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index 13d3fb2a4bb..3f155fa8031 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -129,6 +129,18 @@ var/slime_delay = 0 var/animal_delay = 0 + //IP Intel vars + var/ipintel_email + var/ipintel_rating_bad = 1 + var/ipintel_save_good = 12 + var/ipintel_save_bad = 1 + var/ipintel_domain = "check.getipintel.net" + var/ipintel_maxplaytime = 0 + var/ipintel_whitelist = 0 + var/ipintel_detailsurl = "https://iphub.info/?ip=" + + var/forum_link_url + var/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system. Config option in config.txt var/ban_legacy_system = 0 //Defines whether the server uses the legacy banning system with the files in /data or the SQL system. Config option in config.txt var/use_age_restriction_for_jobs = 0 //Do jobs use account age restrictions? --requires database @@ -304,10 +316,30 @@ if("auto_cryo_ssd_mins") config.auto_cryo_ssd_mins = text2num(value) - if("ssd_warning") config.ssd_warning = 1 + if("ipintel_email") + if(value != "ch@nge.me") + config.ipintel_email = value + if("ipintel_rating_bad") + config.ipintel_rating_bad = text2num(value) + if("ipintel_domain") + config.ipintel_domain = value + if("ipintel_save_good") + config.ipintel_save_good = text2num(value) + if("ipintel_save_bad") + config.ipintel_save_bad = text2num(value) + if("ipintel_maxplaytime") + config.ipintel_maxplaytime = text2num(value) + if("ipintel_whitelist") + config.ipintel_whitelist = 1 + if("ipintel_detailsurl") + config.ipintel_detailsurl = value + + if("forum_link_url") + config.forum_link_url = value + if("log_ooc") config.log_ooc = 1 diff --git a/code/controllers/subsystem/ipintel.dm b/code/controllers/subsystem/ipintel.dm new file mode 100644 index 00000000000..92f02a404a1 --- /dev/null +++ b/code/controllers/subsystem/ipintel.dm @@ -0,0 +1,15 @@ +SUBSYSTEM_DEF(ipintel) + name = "XKeyScore" + wait = 1 + flags = SS_NO_FIRE + init_order = INIT_ORDER_XKEYSCORE // 10 + var/enabled = 0 //disable at round start to avoid checking reconnects + var/throttle = 0 + var/errors = 0 + + var/list/cache = list() + +/datum/controller/subsystem/ipintel/Initialize(timeofday, zlevel) + enabled = 1 + . = ..() + diff --git a/code/modules/admin/DB ban/functions.dm b/code/modules/admin/DB ban/functions.dm index 5eec9d76bdd..1ce6c2b90f0 100644 --- a/code/modules/admin/DB ban/functions.dm +++ b/code/modules/admin/DB ban/functions.dm @@ -150,6 +150,8 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = if(isjobban) jobban_client_fullban(ckey, job) + else + flag_account_for_forum_sync(ckey) datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "") @@ -228,6 +230,8 @@ datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "") DB_ban_unban_by_id(ban_id) if(isjobban) jobban_unban_client(ckey, job) + else + flag_account_for_forum_sync(ckey) datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null) @@ -333,6 +337,8 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) var/DBQuery/query_update = dbcon.NewQuery(sql_update) query_update.Execute() + flag_account_for_forum_sync(pckey) + /client/proc/DB_ban_panel() set category = "Admin" @@ -566,4 +572,12 @@ datum/admins/proc/DB_ban_unban_by_id(var/id) output += "" - usr << browse(output,"window=lookupbans;size=900x700") \ No newline at end of file + usr << browse(output,"window=lookupbans;size=900x700") + +/proc/flag_account_for_forum_sync(ckey) + if(!dbcon) + return + var/skey = sanitizeSQL(ckey) + var/sql = "UPDATE [format_table_name("player")] SET fupdate = 1 WHERE ckey = '[skey]'" + var/DBQuery/adm_query = dbcon.NewQuery(sql) + adm_query.Execute() diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index ec9fa9af05e..9245f5174ce 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -1,5 +1,12 @@ //Blocks an attempt to connect before even creating our client datum thing. -world/IsBanned(key,address,computer_id) +world/IsBanned(key, address, computer_id, check_ipintel = TRUE) + + if(!config.ban_legacy_system) + if(address) + address = sanitizeSQL(address) + if(computer_id) + computer_id = sanitizeSQL(computer_id) + if(!key || !address || !computer_id) log_adminwarn("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.") @@ -31,6 +38,14 @@ world/IsBanned(key,address,computer_id) mistakemessage = "\nIf you believe this is a mistake, please request help at [config.banappeals]." return list("reason"="using Tor", "desc"="\nReason: The network you are using to connect has been banned.[mistakemessage]") + //check if the IP address is a known proxy/vpn, and the user is not whitelisted + if(check_ipintel && config.ipintel_email && config.ipintel_whitelist && ipintel_is_banned(key, address)) + log_adminwarn("Failed Login: [key] [computer_id] [address] - Proxy/VPN") + var/mistakemessage = "" + if(config.banappeals) + mistakemessage = "\nIf you have to use one, request whitelisting at: [config.banappeals]" + return list("reason"="using proxy or vpn", "desc"="\nReason: Proxies/VPNs are not allowed here. [mistakemessage]") + if(config.ban_legacy_system) //Ban Checking diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index 1a9f38b1486..c9c03303f7e 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -276,6 +276,15 @@ var/global/nologevent = 0 show_note(key) +/datum/admins/proc/vpn_whitelist() + set category = "Admin" + set name = "VPN Ckey Whitelist" + if(!check_rights(R_ADMIN)) + return + var/key = stripped_input(usr, "Enter ckey to add/remove, or leave blank to cancel:", "VPN Whitelist add/remove", max_length=32) + if(key) + vpn_whitelist_panel(key) + /datum/admins/proc/access_news_network() //MARKER set category = "Event" set name = "Access Newscaster Network" diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 4a455cd8e5d..06c2361b90a 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -53,6 +53,7 @@ var/list/admin_verbs_admin = list( /datum/admins/proc/PlayerNotes, /client/proc/cmd_mentor_say, /datum/admins/proc/show_player_notes, + /datum/admins/proc/vpn_whitelist, /client/proc/free_slot, /*frees slot for chosen job*/ /client/proc/toggleattacklogs, /client/proc/toggleadminlogs, diff --git a/code/modules/admin/ipintel.dm b/code/modules/admin/ipintel.dm new file mode 100644 index 00000000000..75f2422681a --- /dev/null +++ b/code/modules/admin/ipintel.dm @@ -0,0 +1,228 @@ +/datum/ipintel + var/ip + var/intel = 0 + var/cache = FALSE + var/cacheminutesago = 0 + var/cachedate = "" + var/cacherealtime = 0 + +/datum/ipintel/New() + cachedate = SQLtime() + cacherealtime = world.realtime + +/datum/ipintel/proc/is_valid() + . = FALSE + if(intel < 0) + return + if(intel <= config.ipintel_rating_bad) + if(world.realtime < cacherealtime + (config.ipintel_save_good HOURS)) + return TRUE + else + if(world.realtime < cacherealtime + (config.ipintel_save_bad HOURS)) + return TRUE + +/proc/get_ip_intel(ip, bypasscache = FALSE, updatecache = TRUE) + var/datum/ipintel/res = new() + ip = sanitizeSQL(ip) + res.ip = ip + . = res + if(!ip || !config.ipintel_email || !SSipintel.enabled) + return + if(!bypasscache) + var/datum/ipintel/cachedintel = SSipintel.cache[ip] + if(cachedintel && cachedintel.is_valid()) + cachedintel.cache = TRUE + return cachedintel + + if(dbcon.IsConnected()) + var/rating_bad = config.ipintel_rating_bad + var/DBQuery/query_get_ip_intel = dbcon.NewQuery({" + SELECT date, intel, TIMESTAMPDIFF(MINUTE,date,NOW()) + FROM [format_table_name("ipintel")] + WHERE + ip = INET_ATON('[ip]') + AND (( + intel < [rating_bad] + AND + date + INTERVAL [config.ipintel_save_good] HOUR > NOW() + ) OR ( + intel >= [rating_bad] + AND + date + INTERVAL [config.ipintel_save_bad] HOUR > NOW() + )) + "}) + if(!query_get_ip_intel.Execute()) + qdel(query_get_ip_intel) + return + if(query_get_ip_intel.NextRow()) + res.cache = TRUE + res.cachedate = query_get_ip_intel.item[1] + res.intel = text2num(query_get_ip_intel.item[2]) + res.cacheminutesago = text2num(query_get_ip_intel.item[3]) + res.cacherealtime = world.realtime - (text2num(query_get_ip_intel.item[3])*10*60) + SSipintel.cache[ip] = res + qdel(query_get_ip_intel) + return + qdel(query_get_ip_intel) + res.intel = ip_intel_query(ip) + if(updatecache && res.intel >= 0) + SSipintel.cache[ip] = res + if(dbcon.IsConnected()) + var/DBQuery/query_add_ip_intel = dbcon.NewQuery("INSERT INTO [format_table_name("ipintel")] (ip, intel) VALUES (INET_ATON('[ip]'), [res.intel]) ON DUPLICATE KEY UPDATE intel = VALUES(intel), date = NOW()") + query_add_ip_intel.Execute() + qdel(query_add_ip_intel) + + +/proc/ip_intel_query(ip, var/retryed=0) + . = -1 //default + if(!ip) + return + if(SSipintel.throttle > world.timeofday) + return + if(!SSipintel.enabled) + return + + var/list/http[] = world.Export("http://[config.ipintel_domain]/check.php?ip=[ip]&contact=[config.ipintel_email]&format=json&flags=b") + + if(http) + var/status = text2num(http["STATUS"]) + + if(status == 200) + var/response = json_decode(file2text(http["CONTENT"])) + if(response) + if(response["status"] == "success") + var/intelnum = text2num(response["result"]) + if(isnum(intelnum)) + return text2num(response["result"]) + else + ipintel_handle_error("Bad intel from server: [response["result"]].", ip, retryed) + if(!retryed) + sleep(25) + return .(ip, 1) + else + ipintel_handle_error("Bad response from server: [response["status"]].", ip, retryed) + if(!retryed) + sleep(25) + return .(ip, 1) + + else if(status == 429) + ipintel_handle_error("Error #429: We have exceeded the rate limit.", ip, 1) + return + else + ipintel_handle_error("Unknown status code: [status].", ip, retryed) + if(!retryed) + sleep(25) + return .(ip, 1) + else + ipintel_handle_error("Unable to connect to API.", ip, retryed) + if(!retryed) + sleep(25) + return .(ip, 1) + + +/proc/ipintel_handle_error(error, ip, retryed) + if(retryed) + SSipintel.errors++ + error += " Could not check [ip]. Disabling IPINTEL for [SSipintel.errors] minute[( SSipintel.errors == 1 ? "" : "s" )]" + SSipintel.throttle = world.timeofday + (2 * SSipintel.errors MINUTES) + else + error += " Attempting retry on [ip]." + log_ipintel(error) + +/proc/log_ipintel(text) + log_game("IPINTEL: [text]") + log_debug("IPINTEL: [text]") + + +/proc/ipintel_is_banned(t_ckey, t_ip) + if(!config.ipintel_email) + return FALSE + if(!config.ipintel_whitelist) + return FALSE + if(!dbcon.IsConnected()) + return FALSE + if(!ipintel_badip_check(t_ip)) + return FALSE + if(vpn_whitelist_check(t_ckey)) + return FALSE + return TRUE + +/proc/ipintel_badip_check(target_ip) + var/rating_bad = config.ipintel_rating_bad + if(!rating_bad) + log_debug("ipintel_badip_check reports misconfigured rating_bad directive") + return FALSE + var/valid_hours = config.ipintel_save_bad + if(!valid_hours) + log_debug("ipintel_badip_check reports misconfigured ipintel_save_bad directive") + return FALSE + target_ip = sanitizeSQL(target_ip) + rating_bad = sanitizeSQL(rating_bad) + valid_hours = sanitizeSQL(valid_hours) + var/check_sql = {"SELECT * FROM [format_table_name("ipintel")] WHERE ip = INET_ATON('[target_ip]') AND intel >= [rating_bad] AND (date + INTERVAL [valid_hours] HOUR) > NOW()"} + var/DBQuery/query_get_ip_intel = dbcon.NewQuery(check_sql) + if(!query_get_ip_intel.Execute()) + log_debug("ipintel_badip_check reports failed query execution") + qdel(query_get_ip_intel) + return FALSE + if(!query_get_ip_intel.NextRow()) + qdel(query_get_ip_intel) + return FALSE + qdel(query_get_ip_intel) + return TRUE + +/proc/vpn_whitelist_check(target_ckey) + if(!config.ipintel_whitelist) + return FALSE + var/target_sql_ckey = ckey(target_ckey) + var/DBQuery/query_whitelist_check = dbcon.NewQuery("SELECT * FROM [format_table_name("vpn_whitelist")] WHERE ckey = '[target_sql_ckey]'") + if(!query_whitelist_check.Execute()) + var/err = query_whitelist_check.ErrorMsg() + log_debug("SQL ERROR on proc/vpn_whitelist_check for ckey '[target_sql_ckey]'. Error : \[[err]\]\n") + return FALSE + if(query_whitelist_check.NextRow()) + return TRUE // At least one row in the whitelist names their ckey. That means they are whitelisted. + return FALSE + +/proc/vpn_whitelist_add(target_ckey) + var/target_sql_ckey = ckey(target_ckey) + var/reason_string = input(usr, "Enter link to the URL of their whitelist request on the forum.","Reason required") as message|null + if(!reason_string) + return FALSE + reason_string = sanitizeSQL(reason_string) + var/DBQuery/query_whitelist_add = dbcon.NewQuery("INSERT INTO [format_table_name("vpn_whitelist")] (ckey,reason) VALUES ('[target_sql_ckey]','[reason_string]')") + if(!query_whitelist_add.Execute()) + var/err = query_whitelist_add.ErrorMsg() + log_debug("SQL ERROR on proc/vpn_whitelist_add for ckey '[target_sql_ckey]'. Error : \[[err]\]\n") + return FALSE + return TRUE + +/proc/vpn_whitelist_remove(target_ckey) + var/target_sql_ckey = ckey(target_ckey) + var/DBQuery/query_whitelist_remove = dbcon.NewQuery("DELETE FROM [format_table_name("vpn_whitelist")] WHERE ckey = '[target_sql_ckey]'") + if(!query_whitelist_remove.Execute()) + var/err = query_whitelist_remove.ErrorMsg() + log_debug("SQL ERROR on proc/vpn_whitelist_remove for ckey '[target_sql_ckey]'. Error : \[[err]\]\n") + return FALSE + return TRUE + +/proc/vpn_whitelist_panel(target_ckey as text) + if(!check_rights(R_ADMIN)) + return + if(!target_ckey) + return + var/is_already_whitelisted = vpn_whitelist_check(target_ckey) + if(is_already_whitelisted) + var/confirm = alert("[target_ckey] is already whitelisted. Remove them?", "Confirm Removal", "No", "Yes") + if(!confirm || confirm != "Yes") + to_chat(usr, "VPN whitelist alteration cancelled.") + return + else if(vpn_whitelist_remove(target_ckey)) + to_chat(usr, "[target_ckey] was removed from the VPN whitelist.") + else + to_chat(usr, "VPN whitelist unchanged.") + else + if(vpn_whitelist_add(target_ckey)) + to_chat(usr, "[target_ckey] was added to the VPN whitelist.") + else + to_chat(usr, "VPN whitelist unchanged.") \ No newline at end of file diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm index a6bc558842b..995ee519474 100644 --- a/code/modules/client/client defines.dm +++ b/code/modules/client/client defines.dm @@ -72,6 +72,8 @@ control_freak = CONTROL_FREAK_ALL | CONTROL_FREAK_SKIN | CONTROL_FREAK_MACROS + var/ip_intel = "Disabled" + var/datum/click_intercept/click_intercept = null //datum that controls the displaying and hiding of tooltips diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index c6ab57bae4d..922502698fa 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -229,7 +229,8 @@ if(href_list["ssdwarning"]) ssd_warning_acknowledged = TRUE to_chat(src, "SSD warning acknowledged.") - + if(href_list["link_forum_account"]) + link_forum_account() switch(href_list["action"]) if("openLink") src << link(href_list["link"]) @@ -320,8 +321,7 @@ //Admin Authorisation // Automatically makes localhost connection an admin if(!config.disable_localhost_admin) - var/localhost_addresses = list("127.0.0.1", "::1") // Adresses - if(!isnull(address) && address in localhost_addresses) + if(is_connecting_from_localhost()) new /datum/admins("!LOCALHOST!", R_HOST, ckey) // Makes localhost rank holder = admin_datums[ckey] if(holder) @@ -370,8 +370,9 @@ to_chat(src, message) clientmessages.Remove(ckey) - donator_check() + donator_check() + check_ip_intel() send_resources() if(prefs.toggles & UI_DARKMODE) // activates dark mode if its flagged. -AA07 @@ -393,6 +394,8 @@ generate_clickcatcher() apply_clickcatcher() + check_forum_link() + if(custom_event_msg && custom_event_msg != "") to_chat(src, "