mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-21 20:11:04 +01:00
Implements IPIntel, Panic Bunker, and custom access control (#2436)
What it says on the tin. IPIntel and BYOND account age relating panic bunker settings from TG. Also implements methods for potentially tagging VM users. Ontop of all of this, creates a spiffy UI for admins with R_SERVER to adjust the settings of the entire suite at runtime.
This commit is contained in:
@@ -178,7 +178,8 @@ var/list/asset_datums = list()
|
||||
"bootstrap.min.css" = 'html/bootstrap/css/bootstrap.min.css',
|
||||
"bootstrap.min.js" = 'html/bootstrap/js/bootstrap.min.js',
|
||||
"jquery-2.0.0.min.js" = 'html/jquery/jquery-2.0.0.min.js',
|
||||
"ie-truth.min.js" = 'html/iestats/ie-truth.min.js'
|
||||
"ie-truth.min.js" = 'html/iestats/ie-truth.min.js',
|
||||
"conninfo.min.js" = 'html/iestats/conninfo.min.js'
|
||||
)
|
||||
|
||||
/datum/asset/simple/paper
|
||||
@@ -221,7 +222,7 @@ var/list/asset_datums = list()
|
||||
var/name = "pill[i].png"
|
||||
register_asset(name, icon('icons/obj/chemical.dmi', "pill[i]"))
|
||||
assets += name
|
||||
|
||||
|
||||
for (var/sprite in bottle_sprites)
|
||||
var/name = "[sprite].png"
|
||||
register_asset(name, icon('icons/obj/chemical.dmi', sprite))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/client
|
||||
parent_type = /datum
|
||||
|
||||
|
||||
////////////////
|
||||
//ADMIN THINGS//
|
||||
////////////////
|
||||
@@ -41,6 +41,7 @@
|
||||
var/info_sent = 0
|
||||
// comment out the line below when debugging locally to enable the options & messages menu
|
||||
//control_freak = 1
|
||||
var/ip_intel = "Disabled"
|
||||
|
||||
var/received_discord_pm = -99999
|
||||
var/discord_admin //IRC- no more IRC, K? Discord admin that spoke with them last.
|
||||
@@ -55,6 +56,8 @@
|
||||
var/related_accounts_cid = "Requires database" //So admins know why it isn't working - Used to determine what other accounts previously logged in from this computer id
|
||||
var/whitelist_status = 0 //Used to determine what whitelists the player has access to. Uses bitflag values!
|
||||
var/need_saves_migrated = "Requires database" //Used to determine whether or not the ckey needs their saves migrated over to the database. Default is 0 upon successful connection.
|
||||
var/account_age = -1 // Age on the BYOND account in days.
|
||||
var/account_join_date = null // Date of the BYOND account creation in ISO 8601 format.
|
||||
|
||||
preload_rsc = 0 // This is 0 so we can set it to an URL once the player logs in and have them download the resources from a different server.
|
||||
|
||||
|
||||
@@ -222,6 +222,7 @@
|
||||
|
||||
src << "<span class='danger'>You have tripped the macro filter. An auto-mute was applied.</span>"
|
||||
last_message_time = world.time
|
||||
spam_alert = 4
|
||||
return 1
|
||||
else
|
||||
spam_alert = max(0, spam_alert--)
|
||||
@@ -292,6 +293,35 @@
|
||||
|
||||
log_client_to_db()
|
||||
|
||||
// New player, and we don't want any.
|
||||
if (!holder)
|
||||
if (config.access_deny_new_players && !player_age)
|
||||
log_access("Failed Login: [key] [computer_id] [address] - New player attempting connection during panic bunker.", ckey = ckey)
|
||||
message_admins("Failed Login: [key] [computer_id] [address] - New player attempting connection during panic bunker.")
|
||||
to_chat(src, "<span class='danger'>Apologies, but the server is currently not accepting connections from never before seen players.</span>")
|
||||
del(src)
|
||||
return 0
|
||||
|
||||
// Check if the account is too young.
|
||||
if (config.access_deny_new_accounts != -1 && account_age != -1 && account_age <= config.access_deny_new_accounts)
|
||||
log_access("Failed Login: [key] [computer_id] [address] - Account too young to play. [account_age] days.", ckey = ckey)
|
||||
message_admins("Failed Login: [key] [computer_id] [address] - Account too young to play. [account_age] days.")
|
||||
to_chat(src, "<span class='danger'>Apologies, but the server is currently not accepting connections from BYOND accounts this young.</span>")
|
||||
del(src)
|
||||
return 0
|
||||
|
||||
if (byond_version < config.client_error_version)
|
||||
src << "<span class='danger'><b>Your version of BYOND is too old!</b></span>"
|
||||
src << config.client_error_message
|
||||
src << "Your version: [byond_version]."
|
||||
src << "Required version: [config.client_error_version] or later."
|
||||
src << "Visit http://www.byond.com/download/ to get the latest version of BYOND."
|
||||
if (holder)
|
||||
src << "Admins get a free pass. However, <b>please</b> update your BYOND as soon as possible. Certain things may cause crashes if you play with your present version."
|
||||
else
|
||||
del(src)
|
||||
return 0
|
||||
|
||||
//preferences datum - also holds some persistant data for the client (because we may as well keep these datums to a minimum)
|
||||
prefs = preferences_datums[ckey]
|
||||
if(!prefs)
|
||||
@@ -307,19 +337,6 @@
|
||||
|
||||
prefs.sanitize_preferences()
|
||||
|
||||
if (byond_version < config.client_error_version)
|
||||
src << "<span class='danger'><b>Your version of BYOND is too old!</b></span>"
|
||||
src << config.client_error_message
|
||||
src << "Your version: [byond_version]."
|
||||
src << "Required version: [config.client_error_version] or later."
|
||||
src << "Visit http://www.byond.com/download/ to get the latest version of BYOND."
|
||||
if (holder)
|
||||
src << "Admins get a free pass. However, <b>please</b> update your BYOND as soon as possible. Certain things may cause crashes if you play with your present version."
|
||||
else
|
||||
del(src)
|
||||
return 0
|
||||
|
||||
|
||||
if(holder)
|
||||
add_admin_verbs()
|
||||
|
||||
@@ -340,6 +357,8 @@
|
||||
// Check code/modules/admin/verbs/antag-ooc.dm for definition
|
||||
add_aooc_if_necessary()
|
||||
|
||||
check_ip_intel()
|
||||
|
||||
//////////////
|
||||
//DISCONNECT//
|
||||
//////////////
|
||||
@@ -372,26 +391,38 @@
|
||||
return -1
|
||||
|
||||
/client/proc/log_client_to_db()
|
||||
|
||||
if ( IsGuestKey(src.key) )
|
||||
if (IsGuestKey(src.key))
|
||||
return
|
||||
|
||||
establish_db_connection(dbcon)
|
||||
if(!dbcon.IsConnected())
|
||||
if(!establish_db_connection(dbcon))
|
||||
return
|
||||
|
||||
var/sql_ckey = sql_sanitize_text(src.ckey)
|
||||
|
||||
var/DBQuery/query = dbcon.NewQuery("SELECT id, datediff(Now(),firstseen) as age, whitelist_status, migration_status FROM ss13_player WHERE ckey = '[sql_ckey]'")
|
||||
query.Execute()
|
||||
var/sql_id = 0
|
||||
var/DBQuery/query = dbcon.NewQuery("SELECT datediff(Now(),firstseen) as age, whitelist_status, account_join_date, DATEDIFF(NOW(), account_join_date) FROM ss13_player WHERE ckey = '[sql_ckey]'")
|
||||
|
||||
if(!query.Execute())
|
||||
return
|
||||
|
||||
var/found = 0
|
||||
player_age = 0 // New players won't have an entry so knowing we have a connection we set this to zero to be updated if their is a record.
|
||||
while(query.NextRow())
|
||||
sql_id = query.item[1]
|
||||
player_age = text2num(query.item[2])
|
||||
whitelist_status = text2num(query.item[3])
|
||||
need_saves_migrated = text2num(query.item[4])
|
||||
break
|
||||
|
||||
if (query.NextRow())
|
||||
found = 1
|
||||
player_age = text2num(query.item[1])
|
||||
whitelist_status = text2num(query.item[2])
|
||||
account_join_date = query.item[3]
|
||||
account_age = text2num(query.item[4])
|
||||
if (!account_age)
|
||||
account_join_date = sanitizeSQL(findJoinDate())
|
||||
if (!account_join_date)
|
||||
account_age = -1
|
||||
else
|
||||
var/DBQuery/query_datediff = dbcon.NewQuery("SELECT DATEDIFF(NOW(), [account_join_date])")
|
||||
if (!query_datediff.Execute())
|
||||
return
|
||||
if (query_datediff.NextRow())
|
||||
account_age = text2num(query_datediff.item[1])
|
||||
|
||||
var/DBQuery/query_ip = dbcon.NewQuery("SELECT ckey FROM ss13_player WHERE ip = '[address]'")
|
||||
query_ip.Execute()
|
||||
@@ -407,13 +438,6 @@
|
||||
related_accounts_cid += "[query_cid.item[1]], "
|
||||
break
|
||||
|
||||
//Just the standard check to see if it's actually a number
|
||||
if(sql_id)
|
||||
if(istext(sql_id))
|
||||
sql_id = text2num(sql_id)
|
||||
if(!isnum(sql_id))
|
||||
return
|
||||
|
||||
var/admin_rank = "Player"
|
||||
if(src.holder)
|
||||
admin_rank = src.holder.rank
|
||||
@@ -422,16 +446,18 @@
|
||||
var/sql_computerid = sql_sanitize_text(src.computer_id)
|
||||
var/sql_admin_rank = sql_sanitize_text(admin_rank)
|
||||
|
||||
|
||||
if(sql_id)
|
||||
if(found)
|
||||
//Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables
|
||||
var/DBQuery/query_update = dbcon.NewQuery("UPDATE ss13_player SET lastseen = Now(), ip = '[sql_ip]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]' WHERE id = [sql_id]")
|
||||
var/DBQuery/query_update = dbcon.NewQuery("UPDATE ss13_player SET lastseen = Now(), ip = '[sql_ip]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]', account_join_date = [account_join_date ? "'[account_join_date]'" : "NULL"] WHERE ckey = '[sql_ckey]'")
|
||||
query_update.Execute()
|
||||
else
|
||||
//New player!! Need to insert all the stuff
|
||||
var/DBQuery/query_insert = dbcon.NewQuery("INSERT INTO ss13_player (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[sql_ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]')")
|
||||
var/DBQuery/query_insert = dbcon.NewQuery("INSERT INTO ss13_player (ckey, firstseen, lastseen, ip, computerid, lastadminrank, account_join_date) VALUES ('[sql_ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]', [account_join_date ? "'[account_join_date]'" : "NULL"])")
|
||||
query_insert.Execute()
|
||||
|
||||
if (!account_join_date)
|
||||
account_join_date = "Error"
|
||||
|
||||
//Logging player access
|
||||
var/serverip = "[world.internet_address]:[world.port]"
|
||||
var/DBQuery/query_accesslog = dbcon.NewQuery("INSERT INTO `ss13_connection_log`(`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[serverip]','[sql_ckey]','[sql_ip]','[sql_computerid]');")
|
||||
@@ -585,6 +611,32 @@
|
||||
|
||||
server_greeting.display_to_client(src)
|
||||
|
||||
/client/proc/check_ip_intel()
|
||||
set waitfor = 0 //we sleep when getting the intel, no need to hold up the client connection while we sleep
|
||||
if (config.ipintel_email)
|
||||
var/datum/ipintel/res = get_ip_intel(address)
|
||||
if (config.ipintel_rating_kick && res.intel >= config.ipintel_rating_kick)
|
||||
message_admins("Proxy Detection: [key_name_admin(src)] IP intel rated [res.intel*100]% likely to be a proxy/VPN. They are being kicked because of this.")
|
||||
log_admin("Proxy Detection: [key_name_admin(src)] IP intel rated [res.intel*100]% likely to be a proxy/VPN. They are being kicked because of this.")
|
||||
to_chat(src, "<span class='danger'>Usage of proxies is not permitted by the rules. You are being kicked because of this.</span>")
|
||||
del(src)
|
||||
else if (res.intel >= config.ipintel_rating_bad)
|
||||
message_admins("Proxy Detection: [key_name_admin(src)] IP intel rated [res.intel*100]% likely to be a Proxy/VPN.")
|
||||
ip_intel = res.intel
|
||||
|
||||
/client/proc/findJoinDate()
|
||||
var/list/http = world.Export("http://byond.com/members/[ckey]?format=text")
|
||||
if(!http)
|
||||
log_debug("ACCESS CONTROL: Failed to connect to byond age check for [ckey]")
|
||||
return
|
||||
var/F = file2text(http["CONTENT"])
|
||||
if(F)
|
||||
var/regex/R = regex("joined = \"(\\d{4}-\\d{2}-\\d{2})\"")
|
||||
if(R.Find(F))
|
||||
. = R.group[1]
|
||||
else
|
||||
CRASH("Age check regex failed for [src.ckey]")
|
||||
|
||||
// Byond seemingly calls stat, each tick.
|
||||
// Calling things each tick can get expensive real quick.
|
||||
// So we slow this down a little.
|
||||
|
||||
Reference in New Issue
Block a user