diff --git a/.github/workflows/turdis.yml b/.github/workflows/turdis.yml index 05b89c70a59a..becbb10fd599 100644 --- a/.github/workflows/turdis.yml +++ b/.github/workflows/turdis.yml @@ -133,8 +133,6 @@ jobs: #tools/travis/install_extools.sh mysql -u root -h 127.0.0.1 -e 'CREATE DATABASE tg_travis;' mysql -u root -h 127.0.0.1 tg_travis < SQL/tgstation_schema.sql - mysql -u root -h 127.0.0.1 -e 'CREATE DATABASE tg_travis_prefixed;' - mysql -u root -h 127.0.0.1 tg_travis_prefixed < SQL/tgstation_schema_prefixed.sql - name: Compile run: | tools/build/build --ci dm -DCIBUILDING diff --git a/SQL/database_changelog.txt b/SQL/database_changelog.txt index a1a370ab6861..ef9e3dc2e40c 100644 --- a/SQL/database_changelog.txt +++ b/SQL/database_changelog.txt @@ -1,13 +1,30 @@ 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.12; The query to update the schema revision table is: +The latest database version is 5.13; The query to update the schema revision table is: -INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 12); +INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 13); or -INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 12); +INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 13); In any query remember to add a prefix to the table names if you use one. +version 5.13 2023-05-10 +Adds allow_vpn to bound credentials flags + +ALTER TABLE `bound_credentials` MODIFY COLUMN flags set('bypass_bans','allow_proxies') DEFAULT NULL NULL; +CREATE TABLE `proxy_cache` ( + `ip` int(11) unsigned NOT NULL, + `data` mediumtext NOT NULL, + `last_updated` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), + PRIMARY KEY (`ip`), + CONSTRAINT `data` CHECK (json_valid(`data`)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE OR REPLACE EVENT proxy_cache_ttl + ON SCHEDULE EVERY 1 HOUR + DO + DELETE FROM proxy_cache WHERE (last_updated + INTERVAL 1 DAY) < current_timestamp(); + version 5.12 2023-04-10 Adds playtime to notes diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql index fb4c26dc2eb4..5bba26bcaac5 100644 --- a/SQL/tgstation_schema.sql +++ b/SQL/tgstation_schema.sql @@ -3,7 +3,6 @@ /*!50503 SET NAMES utf8mb4 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; - DROP TABLE IF EXISTS `achievements`; CREATE TABLE IF NOT EXISTS `achievements` ( `name` mediumtext NOT NULL, @@ -122,7 +121,7 @@ CREATE TABLE `bound_credentials` ( `ckey` varchar(32) NOT NULL, `computerid` varchar(32) DEFAULT NULL, `ip` int(10) unsigned DEFAULT NULL, - `flags` set('bypass_bans') DEFAULT NULL, + `flags` set('bypass_bans','allow_proxies') DEFAULT NULL, `comment` text NULL, PRIMARY KEY (`id`), KEY `idx_ckey_lookup` (`ckey`), @@ -533,6 +532,19 @@ CREATE TABLE IF NOT EXISTS `stickyban_matched_ip` ( PRIMARY KEY (`stickyban`,`matched_ip`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +DROP TABLE IF EXISTS `proxy_cache`; +CREATE TABLE `proxy_cache` ( + `ip` int(11) unsigned NOT NULL, + `data` mediumtext NOT NULL, + `last_updated` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), + PRIMARY KEY (`ip`), + CONSTRAINT `data` CHECK (json_valid(`data`)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE OR REPLACE EVENT proxy_cache_ttl + ON SCHEDULE EVERY 1 HOUR + DO + DELETE FROM proxy_cache WHERE (last_updated + INTERVAL 1 DAY) < current_timestamp(); -- Dumping structure for trigger yogstation_copy.role_timeTlogdelete DROP TRIGGER IF EXISTS `role_timeTlogdelete`; diff --git a/SQL/tgstation_schema_prefixed.sql b/SQL/tgstation_schema_prefixed.sql deleted file mode 100644 index a64c4eea23c6..000000000000 --- a/SQL/tgstation_schema_prefixed.sql +++ /dev/null @@ -1,571 +0,0 @@ -/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; -/*!40101 SET NAMES utf8 */; -/*!50503 SET NAMES utf8mb4 */; -/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; -/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; - -DROP TABLE IF EXISTS `SS13_achievements`; -CREATE TABLE IF NOT EXISTS `SS13_achievements` ( - `name` mediumtext NOT NULL, - `id` int(10) unsigned NOT NULL, - `descr` varchar(2048) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_admin`; -CREATE TABLE IF NOT EXISTS `SS13_admin` ( - `ckey` varchar(32) NOT NULL, - `rank` varchar(32) NOT NULL, - PRIMARY KEY (`ckey`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_admin_log`; -CREATE TABLE IF NOT EXISTS `SS13_admin_log` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `datetime` datetime NOT NULL, - `round_id` int(10) unsigned NOT NULL, - `adminckey` varchar(32) NOT NULL, - `adminip` int(10) unsigned NOT NULL, - `operation` enum('add admin','remove admin','change admin rank','add rank','remove rank','change rank flags', 'add mentor') NOT NULL, - `target` varchar(32) NOT NULL, - `log` varchar(1000) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=342 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_admin_ranks`; -CREATE TABLE IF NOT EXISTS `SS13_admin_ranks` ( - `rank` varchar(32) NOT NULL, - `flags` smallint(5) unsigned NOT NULL, - `exclude_flags` smallint(5) unsigned NOT NULL, - `can_edit_flags` smallint(5) unsigned NOT NULL, - PRIMARY KEY (`rank`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `ss13_admin_tickets`; -CREATE TABLE IF NOT EXISTS `ss13_admin_tickets` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `round_id` int(10) unsigned NOT NULL DEFAULT 0, - `ticket_id` int(10) unsigned NOT NULL DEFAULT 0, - `when` datetime NOT NULL DEFAULT current_timestamp(), - `ckey` varchar(32) NOT NULL, - `a_ckey` varchar(32), - PRIMARY KEY (`id`), - KEY `idx_round` (`round_id`), - KEY `idx_round_ticket` (`round_id`,`ticket_id`) -) ENGINE=InnoDB AUTO_INCREMENT=157319 DEFAULT CHARSET=utf8; - -DROP TABLE IF EXISTS `ss13_admin_ticket_interactions`; -CREATE TABLE IF NOT EXISTS `ss13_admin_ticket_content` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `ticket_id` int(10) unsigned, - `when` datetime NOT NULL DEFAULT current_timestamp(), - `user` varchar(32) NOT NULL, - `text` text, - PRIMARY KEY (`id`), - FOREIGN KEY (`ticket_id`) REFERENCES `ss13_admin_tickets`(`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_antag_tokens`; -CREATE TABLE IF NOT EXISTS `SS13_antag_tokens` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `ckey` varchar(32) NOT NULL, - `reason` varchar(2048) NOT NULL, - `denial_reason` varchar(2048) DEFAULT NULL, - `applying_admin` varchar(32) NOT NULL, - `denying_admin` varchar(32) DEFAULT NULL, - `granted_time` datetime NOT NULL, - `redeemed` tinyint(3) unsigned NOT NULL DEFAULT 0, - `round_id` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=273 DEFAULT CHARSET=latin1; - - -DROP TABLE IF EXISTS `SS13_ban`; -CREATE TABLE IF NOT EXISTS `SS13_ban` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `bantime` datetime NOT NULL, - `server_ip` int(10) unsigned NOT NULL, - `server_port` smallint(5) unsigned NOT NULL, - `round_id` int(10) unsigned NOT NULL, - `role` varchar(32) DEFAULT NULL, - `expiration_time` datetime DEFAULT NULL, - `applies_to_admins` tinyint(3) unsigned NOT NULL DEFAULT 0, - `reason` varchar(2048) NOT NULL, - `ckey` varchar(32) DEFAULT NULL, - `ip` int(10) unsigned DEFAULT NULL, - `computerid` varchar(32) DEFAULT NULL, - `a_ckey` varchar(32) NOT NULL, - `a_ip` int(10) unsigned NOT NULL, - `a_computerid` varchar(32) NOT NULL, - `who` varchar(2048) NOT NULL, - `adminwho` varchar(2048) NOT NULL, - `edits` mediumtext DEFAULT NULL, - `unbanned_datetime` datetime DEFAULT NULL, - `unbanned_ckey` varchar(32) DEFAULT NULL, - `unbanned_ip` int(10) unsigned DEFAULT NULL, - `unbanned_computerid` varchar(32) DEFAULT NULL, - `unbanned_round_id` int(10) unsigned DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `idx_ban_isbanned` (`ckey`,`role`,`unbanned_datetime`,`expiration_time`), - KEY `idx_ban_isbanned_details` (`ckey`,`ip`,`computerid`,`role`,`unbanned_datetime`,`expiration_time`), - KEY `idx_ban_count` (`bantime`,`a_ckey`,`applies_to_admins`,`unbanned_datetime`,`expiration_time`) -) ENGINE=InnoDB AUTO_INCREMENT=39587 DEFAULT CHARSET=utf8; - -DROP TABLE IF EXISTS `SS13_bound_credentials`; -CREATE TABLE `SS13_bound_credentials` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `ckey` varchar(32) NOT NULL, - `computerid` varchar(32) DEFAULT NULL, - `ip` int(10) unsigned DEFAULT NULL, - `flags` set('bypass_bans') DEFAULT NULL, - `comment` text NULL, - PRIMARY KEY (`id`), - KEY `idx_ckey_lookup` (`ckey`), - KEY `idx_cid_lookup` (`computerid`), - KEY `idx_ip_lookup` (`ip`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -DROP TABLE IF EXISTS `SS13_connection_log`; -CREATE TABLE IF NOT EXISTS `SS13_connection_log` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `datetime` datetime DEFAULT NULL, - `left` datetime DEFAULT NULL, - `server_ip` int(10) unsigned NOT NULL, - `server_port` smallint(5) unsigned NOT NULL, - `round_id` int(10) unsigned NOT NULL, - `ckey` varchar(45) DEFAULT NULL, - `ip` int(10) unsigned NOT NULL, - `computerid` varchar(45) DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `idx_review` (`ckey`, `computerid`, `ip`) -) ENGINE=InnoDB AUTO_INCREMENT=4192042 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_death`; -CREATE TABLE IF NOT EXISTS `SS13_death` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `pod` varchar(50) NOT NULL, - `x_coord` smallint(5) unsigned NOT NULL, - `y_coord` smallint(5) unsigned NOT NULL, - `z_coord` smallint(5) unsigned NOT NULL, - `mapname` varchar(32) NOT NULL, - `server_ip` int(10) unsigned NOT NULL, - `server_port` smallint(5) unsigned NOT NULL, - `round_id` int(11) NOT NULL, - `tod` datetime NOT NULL COMMENT 'Time of death', - `job` varchar(32) NOT NULL, - `special` varchar(32) DEFAULT NULL, - `name` varchar(96) NOT NULL, - `byondkey` varchar(32) NOT NULL, - `laname` varchar(96) DEFAULT NULL, - `lakey` varchar(32) DEFAULT NULL, - `bruteloss` smallint(5) unsigned NOT NULL, - `brainloss` smallint(5) unsigned NOT NULL, - `fireloss` smallint(5) unsigned NOT NULL, - `oxyloss` smallint(5) unsigned NOT NULL, - `toxloss` smallint(5) unsigned NOT NULL, - `cloneloss` smallint(5) unsigned NOT NULL, - `staminaloss` smallint(5) unsigned NOT NULL, - `last_words` varchar(255) DEFAULT NULL, - `suicide` tinyint(4) NOT NULL DEFAULT 0, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=1422836 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_donors`; -CREATE TABLE IF NOT EXISTS `SS13_donors` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `ckey` varchar(32) NOT NULL, - `discord_id` varchar(32) DEFAULT NULL, - `transaction_id` varchar(70) NOT NULL, - `amount` decimal(10,2) NOT NULL, - `datetime` timestamp NOT NULL DEFAULT current_timestamp(), - `expiration_time` datetime DEFAULT NULL, - `revoked` int(11) DEFAULT NULL, - `revoked_ckey` varchar(32) DEFAULT NULL, - `revoked_time` datetime DEFAULT NULL, - `payer_email` varchar(256) DEFAULT NULL, - `status` varchar(32) NOT NULL, - `notes` varchar(1024) DEFAULT NULL, - `valid` tinyint(4) NOT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `id` (`id`), - UNIQUE KEY `transaction_id` (`transaction_id`), - KEY `ckey` (`ckey`), - KEY `forum_username` (`discord_id`) -) ENGINE=InnoDB AUTO_INCREMENT=761 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_earned_achievements`; -CREATE TABLE IF NOT EXISTS `SS13_earned_achievements` ( - `ckey` varchar(32) NOT NULL, - `id` int(10) unsigned NOT NULL -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_feedback`; -CREATE TABLE IF NOT EXISTS `SS13_feedback` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `datetime` datetime NOT NULL, - `round_id` int(10) unsigned NOT NULL, - `key_name` varchar(32) NOT NULL, - `key_type` enum('text','amount','tally','nested tally','associative') NOT NULL, - `version` tinyint(3) unsigned NOT NULL, - `json` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL CHECK (json_valid(`json`)), - PRIMARY KEY (`id`) -) ENGINE=MyISAM AUTO_INCREMENT=349150 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_feedback_normalized`; -CREATE TABLE IF NOT EXISTS `SS13_feedback_normalized` ( - `id` int(10) unsigned NOT NULL AUTO_INCREMENT, - `datetime` datetime NOT NULL, - `round_id` int(10) unsigned NOT NULL, - `category_primary` text NOT NULL DEFAULT '', - `category_secondary` text NOT NULL DEFAULT '', - `category_tertiary` text NOT NULL DEFAULT '', - `version` tinyint(3) unsigned NOT NULL, - `data` longtext NOT NULL DEFAULT '0', - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=6204920 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_ipintel`; -CREATE TABLE IF NOT EXISTS `SS13_ipintel` ( - `ip` int(10) unsigned NOT NULL, - `date` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), - `intel` double NOT NULL DEFAULT 0, - PRIMARY KEY (`ip`), - KEY `idx_ipintel` (`ip`,`intel`,`date`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_legacy_population`; -CREATE TABLE IF NOT EXISTS `SS13_legacy_population` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `playercount` int(11) DEFAULT NULL, - `admincount` int(11) DEFAULT NULL, - `time` datetime NOT NULL, - `server_ip` int(10) unsigned NOT NULL, - `server_port` smallint(5) unsigned NOT NULL, - `round_id` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=490160 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_library`; -CREATE TABLE IF NOT EXISTS `SS13_library` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `author` varchar(45) NOT NULL, - `title` varchar(45) NOT NULL, - `content` mediumtext NOT NULL, - `category` enum('Any','Fiction','Non-Fiction','Adult','Reference','Religion') NOT NULL, - `ckey` varchar(32) NOT NULL DEFAULT 'LEGACY', - `datetime` datetime NOT NULL, - `deleted` tinyint(3) unsigned DEFAULT NULL, - `round_id_created` int(10) unsigned NOT NULL, - PRIMARY KEY (`id`), - KEY `deleted_idx` (`deleted`), - KEY `idx_lib_id_del` (`id`,`deleted`), - KEY `idx_lib_del_title` (`deleted`,`title`), - KEY `idx_lib_search` (`deleted`,`author`,`title`,`category`) -) ENGINE=InnoDB AUTO_INCREMENT=2017 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_loa`; -CREATE TABLE IF NOT EXISTS `SS13_loa` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `ckey` varchar(32) NOT NULL, - `time` date NOT NULL, - `expiry_time` date NOT NULL, - `revoked` bit(1) DEFAULT NULL, - `reason` text NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=419 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_mentor`; -CREATE TABLE IF NOT EXISTS `SS13_mentor` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `ckey` varchar(32) NOT NULL, - `position` varchar(32) NOT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=130 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_mentor_memo`; -CREATE TABLE IF NOT EXISTS `SS13_mentor_memo` ( - `ckey` varchar(32) NOT NULL, - `memotext` mediumtext NOT NULL, - `timestamp` datetime NOT NULL, - `last_editor` varchar(32) DEFAULT NULL, - `edits` mediumtext DEFAULT NULL, - PRIMARY KEY (`ckey`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_messages`; -CREATE TABLE IF NOT EXISTS `SS13_messages` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `type` varchar(32) NOT NULL, - `targetckey` varchar(32) NOT NULL, - `adminckey` varchar(32) NOT NULL, - `text` mediumtext NOT NULL, - `timestamp` datetime NOT NULL, - `server` varchar(32) DEFAULT NULL, - `server_ip` int(10) unsigned NOT NULL, - `server_port` smallint(5) unsigned NOT NULL, - `round_id` int(10) unsigned NOT NULL, - `secret` tinyint(1) DEFAULT 1, - `expire_timestamp` datetime DEFAULT NULL, - `lasteditor` varchar(32) DEFAULT NULL, - `edits` mediumtext DEFAULT NULL, - `deleted` tinyint(3) unsigned NOT NULL DEFAULT 0, - `playtime` int(10) unsigned DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `idx_msg_ckey_time` (`targetckey`,`timestamp`,`deleted`), - KEY `idx_msg_type_ckeys_time` (`type`,`targetckey`,`adminckey`,`timestamp`,`deleted`), - KEY `idx_msg_type_ckey_time_odr` (`type`,`targetckey`,`timestamp`,`deleted`) -) ENGINE=InnoDB AUTO_INCREMENT=75629 DEFAULT CHARSET=utf8; - -DROP TABLE IF EXISTS `SS13_mfa_logins`; -CREATE TABLE IF NOT EXISTS `SS13_mfa_logins` ( - `ckey` varchar(32) NOT NULL, - `ip` int(10) unsigned NOT NULL, - `cid` varchar(32) NOT NULL, - `datetime` timestamp NOT NULL DEFAULT current_timestamp(), - PRIMARY KEY (`ckey`,`ip`,`cid`,`datetime`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -DROP TABLE IF EXISTS `SS13_misc`; -CREATE TABLE IF NOT EXISTS `SS13_misc` ( - `key` varchar(32) NOT NULL, - `value` varchar(2048) NOT NULL, - PRIMARY KEY (`key`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_player`; -CREATE TABLE IF NOT EXISTS `SS13_player` ( - `ckey` varchar(32) NOT NULL, - `byond_key` varchar(32) DEFAULT NULL, - `firstseen` datetime NOT NULL, - `firstseen_round_id` int(10) unsigned NOT NULL, - `lastseen` datetime NOT NULL, - `lastseen_round_id` int(10) unsigned NOT NULL, - `ip` int(10) unsigned NOT NULL, - `computerid` varchar(32) NOT NULL, - `lastadminrank` varchar(32) NOT NULL DEFAULT 'Player', - `accountjoindate` date DEFAULT NULL, - `flags` int(11) NOT NULL DEFAULT 0, - `discord_id` bigint(20) DEFAULT NULL, - `antag_tokens` int(10) unsigned NOT NULL DEFAULT 0, - `credits` bigint(20) unsigned NOT NULL DEFAULT 0, - `antag_weight` mediumint(8) unsigned NOT NULL DEFAULT 100, - `job_whitelisted` tinyint(3) unsigned NOT NULL DEFAULT 0, - `totp_seed` varchar(20), - `mfa_backup` varchar(128), - PRIMARY KEY (`ckey`), - KEY `idx_player_cid_ckey` (`computerid`,`ckey`), - KEY `idx_player_ip_ckey` (`ip`,`ckey`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_poll_option`; -CREATE TABLE IF NOT EXISTS `SS13_poll_option` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `pollid` int(11) NOT NULL, - `text` varchar(255) NOT NULL, - `minval` int(11) DEFAULT NULL, - `maxval` int(11) DEFAULT NULL, - `descmin` varchar(32) DEFAULT NULL, - `descmid` varchar(32) DEFAULT NULL, - `descmax` varchar(32) DEFAULT NULL, - `default_percentage_calc` tinyint(3) unsigned NOT NULL DEFAULT 1, - PRIMARY KEY (`id`), - KEY `idx_pop_pollid` (`pollid`) -) ENGINE=InnoDB AUTO_INCREMENT=272 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_poll_question`; -CREATE TABLE IF NOT EXISTS `SS13_poll_question` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `polltype` enum('OPTION','TEXT','NUMVAL','MULTICHOICE','IRV') NOT NULL, - `starttime` datetime NOT NULL, - `endtime` datetime NOT NULL, - `question` varchar(255) NOT NULL, - `adminonly` tinyint(3) unsigned NOT NULL, - `multiplechoiceoptions` int(11) DEFAULT NULL, - `createdby_ckey` varchar(32) DEFAULT NULL, - `createdby_ip` int(10) unsigned NOT NULL, - `dontshow` tinyint(3) unsigned NOT NULL, - PRIMARY KEY (`id`), - KEY `idx_pquest_question_time_ckey` (`question`,`starttime`,`endtime`,`createdby_ckey`,`createdby_ip`), - KEY `idx_pquest_time_admin` (`starttime`,`endtime`,`adminonly`), - KEY `idx_pquest_id_time_type_admin` (`id`,`starttime`,`endtime`,`polltype`,`adminonly`) -) ENGINE=InnoDB AUTO_INCREMENT=61 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_poll_textreply`; -CREATE TABLE IF NOT EXISTS `SS13_poll_textreply` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `datetime` datetime NOT NULL, - `pollid` int(11) NOT NULL, - `ckey` varchar(32) NOT NULL, - `ip` int(10) unsigned NOT NULL, - `replytext` varchar(2048) NOT NULL, - `adminrank` varchar(32) NOT NULL DEFAULT 'Player', - PRIMARY KEY (`id`), - KEY `idx_ptext_pollid_ckey` (`pollid`,`ckey`) -) ENGINE=InnoDB AUTO_INCREMENT=365 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_poll_vote`; -CREATE TABLE IF NOT EXISTS `SS13_poll_vote` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `datetime` datetime NOT NULL, - `pollid` int(11) NOT NULL, - `optionid` int(11) NOT NULL, - `ckey` varchar(32) NOT NULL, - `ip` int(10) unsigned NOT NULL, - `adminrank` varchar(32) NOT NULL, - `rating` int(11) DEFAULT NULL, - PRIMARY KEY (`id`), - KEY `idx_pvote_pollid_ckey` (`pollid`,`ckey`), - KEY `idx_pvote_optionid_ckey` (`optionid`,`ckey`) -) ENGINE=InnoDB AUTO_INCREMENT=12987 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_role_time`; -CREATE TABLE IF NOT EXISTS `SS13_role_time` ( - `ckey` varchar(32) NOT NULL, - `job` varchar(128) NOT NULL, - `minutes` int(10) unsigned NOT NULL, - PRIMARY KEY (`ckey`,`job`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_role_time_log`; -CREATE TABLE IF NOT EXISTS `SS13_role_time_log` ( - `id` bigint(20) NOT NULL AUTO_INCREMENT, - `ckey` varchar(32) NOT NULL, - `job` varchar(128) NOT NULL, - `delta` int(11) NOT NULL, - `datetime` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), - PRIMARY KEY (`id`), - KEY `ckey` (`ckey`), - KEY `job` (`job`), - KEY `datetime` (`datetime`) -) ENGINE=InnoDB AUTO_INCREMENT=7175905 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_round`; -CREATE TABLE IF NOT EXISTS `SS13_round` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `initialize_datetime` datetime NOT NULL, - `start_datetime` datetime DEFAULT NULL, - `shutdown_datetime` datetime DEFAULT NULL, - `end_datetime` datetime DEFAULT NULL, - `server_ip` int(10) unsigned NOT NULL, - `server_port` smallint(5) unsigned NOT NULL, - `commit_hash` char(40) DEFAULT NULL, - `game_mode` varchar(32) DEFAULT NULL, - `game_mode_result` varchar(64) DEFAULT NULL, - `end_state` varchar(64) DEFAULT NULL, - `shuttle_name` varchar(64) DEFAULT NULL, - `map_name` varchar(32) DEFAULT NULL, - `station_name` varchar(80) DEFAULT NULL, - PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=32366 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_schema_revision`; -CREATE TABLE IF NOT EXISTS `SS13_schema_revision` ( - `major` tinyint(3) unsigned NOT NULL, - `minor` tinyint(3) unsigned NOT NULL, - `date` datetime NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(), - PRIMARY KEY (`major`,`minor`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_stickyban`; -CREATE TABLE IF NOT EXISTS `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 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_stickyban_matched_cid`; -CREATE TABLE IF NOT EXISTS `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 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_stickyban_matched_ckey`; -CREATE TABLE IF NOT EXISTS `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 DEFAULT CHARSET=utf8; - - -DROP TABLE IF EXISTS `SS13_stickyban_matched_ip`; -CREATE TABLE IF NOT EXISTS `SS13_stickyban_matched_ip` ( - `stickyban` varchar(32) NOT NULL, - `matched_ip` int(10) 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 DEFAULT CHARSET=utf8; - - --- Dumping structure for trigger yogstation_copy.role_timeTlogdelete -DROP TRIGGER IF EXISTS `role_timeTlogdelete`; -SET @OLDTMP_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO'; -DELIMITER // -CREATE TRIGGER `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 ; -SET SQL_MODE=@OLDTMP_SQL_MODE; - --- Dumping structure for trigger yogstation_copy.role_timeTloginsert -DROP TRIGGER IF EXISTS `role_timeTloginsert`; -SET @OLDTMP_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO'; -DELIMITER // -CREATE TRIGGER `role_timeTloginsert` AFTER INSERT ON `SS13_role_time` FOR EACH ROW BEGIN INSERT into SS13_role_time_log (ckey, job, delta) VALUES (NEW.ckey, NEW.job, NEW.minutes); -END// -DELIMITER ; -SET SQL_MODE=@OLDTMP_SQL_MODE; - --- Dumping structure for trigger yogstation_copy.role_timeTlogupdate -DROP TRIGGER IF EXISTS `role_timeTlogupdate`; -SET @OLDTMP_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO'; -DELIMITER // -CREATE TRIGGER `role_timeTlogupdate` AFTER UPDATE ON `SS13_role_time` FOR EACH ROW BEGIN INSERT into SS13_role_time_log (ckey, job, delta) VALUES (NEW.CKEY, NEW.job, NEW.minutes-OLD.minutes); -END// -DELIMITER ; -SET SQL_MODE=@OLDTMP_SQL_MODE; - -DROP TRIGGER IF EXISTS messagesTloghours; -CREATE TRIGGER messagesTloghours - BEFORE INSERT ON `SS13_messages` FOR EACH ROW - SET NEW.playtime = (SELECT minutes FROM SS13_role_time rt WHERE rt.ckey = NEW.targetckey AND rt.job = 'Living'); - -/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; -/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; -/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index 9baa347c414f..26cc4a4e88a3 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -21,7 +21,9 @@ * make sure you add an update to the schema_version stable in the db changelog */ -#define DB_MINOR_VERSION 12 +#define DB_MINOR_VERSION 13 +#define DB_BOUND_CREDENTIALS_FLAG_BYPASS_BANS "bypass_bans" +#define DB_BOUND_CREDENTIALS_FLAG_ALLOW_PROXIES "allow_proxies" //! ## Timing subsystem /** @@ -156,6 +158,7 @@ #define INIT_ORDER_OVERLAY -6 #define INIT_ORDER_XKEYSCORE -10 #define INIT_ORDER_STICKY_BAN -10 +#define INIT_ORDER_ECHELON -10 #define INIT_ORDER_LIGHTING -20 #define INIT_ORDER_SHUTTLE -21 #define INIT_ORDER_MINOR_MAPPING -40 diff --git a/code/controllers/subsystem/echelon.dm b/code/controllers/subsystem/echelon.dm new file mode 100644 index 000000000000..cd0f2c2448a1 --- /dev/null +++ b/code/controllers/subsystem/echelon.dm @@ -0,0 +1,104 @@ +SUBSYSTEM_DEF(echelon) + name = "ECHELON" + init_order = INIT_ORDER_ECHELON + flags = SS_NO_FIRE + var/enabled = TRUE + +/datum/controller/subsystem/echelon/Initialize(timeofday, zlevel) + return SS_INIT_SUCCESS + +/datum/controller/subsystem/echelon/proc/is_exception(ckey) + PRIVATE_PROC(TRUE) + + var/datum/DBQuery/query_get_flags = SSdbcore.NewQuery({" + SELECT + flags + FROM [format_table_name("bound_credentials")] + WHERE + ckey = :ckey AND + FIND_IN_SET('[DB_BOUND_CREDENTIALS_FLAG_ALLOW_PROXIES]', flags) + "}, list("ckey" = ckey)) + if(!query_get_flags.Execute()) + qdel(query_get_flags) + return FALSE + + var/result = query_get_flags.rows.len >= 1 + qdel(query_get_flags) + return result + + +/datum/controller/subsystem/echelon/proc/is_using_proxy(ip) + PRIVATE_PROC(TRUE) + + if(IsAdminAdvancedProcCall()) return + + var/datum/DBQuery/query_get_cached_matches = SSdbcore.NewQuery({" + SELECT + JSON_VALUE(data, "$.should_block") + FROM [format_table_name("proxy_cache")] + WHERE + (ip = INET_ATON(:ip)) + "}, list("ip" = ip)) + + //This is just the cached value, we can carry on if this fails + if(!query_get_cached_matches.Execute()) + var/msg = "An error occured while attempting to fetch a cached proxy result. Check server sql logs." + log_world(msg) + message_admins(msg) + else if(query_get_cached_matches.NextRow()) + var/result = query_get_cached_matches.item[1] == "true" + qdel(query_get_cached_matches) + return result + qdel(query_get_cached_matches) + + //At this point, we couldnt fetch a cached value + var/datum/http_request/req = new() + var/url = CONFIG_GET(string/vpn_lookup_api) + url = replacetextEx(url, "{key}", CONFIG_GET(string/vpn_lookup_key)) + url = replacetextEx(url, "{ip}", ip) + req.prepare(RUSTG_HTTP_METHOD_GET, url) + req.begin_async() + UNTIL(req.is_complete()) + var/datum/http_response/res = req.into_response() + var/json = json_decode(res.body) + + var/datum/DBQuery/query_update_cache = SSdbcore.NewQuery({" + INSERT INTO [format_table_name("proxy_cache")] + SET ip = INET_ATON(:ip), data = :data + "}, list("ip" = ip, "data" = res.body)) + query_update_cache.Execute(); + qdel(query_update_cache) + + var/status = json["status"] + switch(status) + if("warning") + var/msg = "The proxy checking API has returned a warning. Please inform a server operator." + log_world(msg) + message_admins(msg) + if("denied") + var/msg = "The proxy checking API has refused to answer. Please inform a server operator. The ip [ip] was let through by default." + log_world(msg) + message_admins(msg) + return FALSE + if("error") + var/msg = "Unable to fetch proxy information. Please inform a server operator. The ip [ip] was let through by default." + log_world(msg) + message_admins(msg) + return FALSE + + + return json["should_block"] == "true" + + +/datum/controller/subsystem/echelon/proc/is_match(ckey, ip, allow_exceptions=TRUE) + if(!CONFIG_GET(string/vpn_lookup_api) || !CONFIG_GET(string/vpn_lookup_key)) + return FALSE + if(!enabled) + return FALSE + + if(allow_exceptions && is_exception(ckey)) return FALSE + + return is_using_proxy(ip) + + + \ No newline at end of file diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm index 36aa37d11941..19e813b4efa6 100644 --- a/code/modules/admin/IsBanned.dm +++ b/code/modules/admin/IsBanned.dm @@ -137,6 +137,11 @@ Yogs End*/ qdel(query_get_bound_creds) + if(SSechelon.is_match(ckey, address)) + log_access("Failed Login: [key] [computer_id] [address] - Blocked due to proxy") + key_cache[key] = FALSE + return list("reason" = "proxy", "desc" = "Round ID [GLOB.round_id]: Your connection has been blocked due to originating from a suspicious IP. If you are using a VPN product, disable it and reconnect. If you are not using a VPN or if you are required to use one to connect to the server, please visit [CONFIG_GET(string/banappeals) || "the forums"].") + var/list/ban_details = is_banned_from_with_details(ckey, address, computer_id, "Server") for(var/i in ban_details) if(admin) diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm index de6fee14eb33..6bb6861d57e2 100644 --- a/code/modules/admin/admin.dm +++ b/code/modules/admin/admin.dm @@ -62,8 +62,6 @@ body += "

Show related accounts by: " body += "\[ CID | " body += "IP \]" - if(CONFIG_GET(string/vpn_lookup_api) && CONFIG_GET(string/vpn_lookup_key) && M.lastKnownIP) - body += " \[Check for VPN\]" var/rep = 0 rep += SSpersistence.antag_rep[M.ckey] body += "

Antagonist reputation: [rep]" diff --git a/code/modules/admin/sql_ban_system.dm b/code/modules/admin/sql_ban_system.dm index 9f4762a316fc..117208ec8695 100644 --- a/code/modules/admin/sql_ban_system.dm +++ b/code/modules/admin/sql_ban_system.dm @@ -59,7 +59,7 @@ FROM [format_table_name("bound_credentials")] WHERE ckey = :ckey AND - FIND_IN_SET('bypass_bans', [format_table_name("bound_credentials")].flags) + FIND_IN_SET('[DB_BOUND_CREDENTIALS_FLAG_BYPASS_BANS]', [format_table_name("bound_credentials")].flags) "}, list("ckey" = player_ckey)); if(!query_get_bypass_creds.warn_execute()) qdel(query_get_bypass_creds) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index d7043bf6912b..0c30a071d368 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -2103,60 +2103,6 @@ popup.set_content(dat.Join()) popup.open(FALSE) - else if(href_list["vpnlookup"]) - if(!check_rights(R_ADMIN)) - return - - var/ip = href_list["vpnlookup"] - - if(!ip) - return - - if(!CONFIG_GET(string/vpn_lookup_api) || !CONFIG_GET(string/vpn_lookup_key)) - to_chat(usr, span_warning("VPN Lookup is disabled!")) - return - - var/datum/http_request/req = new() - req.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/vpn_lookup_api)]/[ip]?vpn=1&risk=1&asn=1&key=[CONFIG_GET(string/vpn_lookup_key)]") - req.begin_async() - UNTIL(req.is_complete()) - var/datum/http_response/response = req.into_response() - var/list/body = json_decode(response.body) - var/list/dat = list() - dat += "
STATUS: [uppertext(body["status"])]
" - dat += "
" - if(body["status"] != "ok" && body["message"]) - dat += "
[uppertext(body["message"])]
" - dat += "
" - if(body[ip] && islist(body[ip])) - if(body[ip]["proxy"]) - dat += "
Proxy?: [body[ip]["proxy"]]
" - dat += "
" - if(body[ip]["type"]) - dat += "
Type: [body[ip]["type"]]
" - dat += "
" - if(body[ip]["risk"]) - dat += "
Risk Rating: [body[ip]["risk"]]/100
" - dat += "
" - if(body[ip]["operator"] && islist(body[ip]["operator"]) && body[ip]["operator"]["name"]) - dat += "
" - dat += "Operator: [body[ip]["operator"]["name"]]" - if(body[ip]["operator"]["url"]) - dat += " @ [body[ip]["operator"]["url"]]" - dat += "

" - dat += "Additional Info:" - dat += "
" - dat += "[ip]" - dat += "
" - for(var/P in body[ip]) - if(P != "proxy" && P != "type" && P != "risk" && P != "operator") - dat += "[P]: [body[ip][P]]" - dat += "
" - - var/datum/browser/popup = new(usr, "vpnlookup-[ip]", "
VPN Lookup
", 700, 600) - popup.set_content(dat.Join()) - popup.open(FALSE) - else if(href_list["modantagrep"]) if(!check_rights(R_ADMIN)) return diff --git a/config/secret.txt b/config/secret.txt index 022398d1f536..dda123be782f 100644 --- a/config/secret.txt +++ b/config/secret.txt @@ -27,7 +27,7 @@ $include private_default.txt # IPINTEL_EMAIL ch@nge.me ## VPN Lookup -## URL, see code/modules/admin/topic.dm to change args +## URL, {ip} gets replaced with the ip to check and {key} gets replaced with the creds # VPN_LOOKUP_API https://website.com/v1 ## API Key # VPN_LOOKUP_KEY insertkey diff --git a/yogstation.dme b/yogstation.dme index 2f0726319bdd..12c27aefa345 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -327,6 +327,7 @@ #include "code\controllers\subsystem\discord.dm" #include "code\controllers\subsystem\disease.dm" #include "code\controllers\subsystem\early_assets.dm" +#include "code\controllers\subsystem\echelon.dm" #include "code\controllers\subsystem\economy.dm" #include "code\controllers\subsystem\events.dm" #include "code\controllers\subsystem\explosions.dm"