mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-15 18:06:48 +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:
@@ -135,7 +135,33 @@
|
||||
update_connection_data(C)
|
||||
return
|
||||
|
||||
var/list/conn_info = json_decode(data)
|
||||
var/list/data_object = json_decode(data)
|
||||
|
||||
if (!data_object || !data_object.len)
|
||||
log_debug("CONN DATA: [C.ckey] has no connection data to showcase.")
|
||||
return
|
||||
|
||||
if (data_object["vms"])
|
||||
var/A = data_object["vms"]
|
||||
var/count = 0
|
||||
if (A & 1)
|
||||
count++
|
||||
if (A & 2)
|
||||
count++
|
||||
|
||||
if (config.access_deny_vms && count >= config.access_deny_vms)
|
||||
log_access("Failed Login: [C.ckey] [C.address] [C.computer_id] - Matching [count]/[config.access_deny_vms] VM identifiers. IDs: [A].", ckey = C.ckey)
|
||||
message_admins("Failed Login: [C.ckey] [C.address] [C.computer_id] - Matching [count]/[config.access_deny_vms] VM identifiers. IDs: [A].")
|
||||
spawn(20)
|
||||
if (C)
|
||||
del(C)
|
||||
return
|
||||
|
||||
if (config.access_warn_vms && count >= config.access_warn_vms)
|
||||
log_access("Notice: [key_name(C)] [C.address] [C.computer_id] - Matching [count] VM identifiers. IDs: [A].", ckey = C.ckey)
|
||||
message_admins("Notice: [key_name(C)] [C.address] [C.computer_id] - Matching [count] VM identifiers. IDs: [A].")
|
||||
|
||||
var/list/conn_info = data_object["conn"]
|
||||
|
||||
if (!conn_info || !conn_info.len)
|
||||
return
|
||||
|
||||
@@ -169,7 +169,8 @@ var/list/admin_verbs_server = list(
|
||||
/client/proc/admin_edit_motd,
|
||||
/client/proc/toggle_recursive_explosions,
|
||||
/client/proc/restart_controller,
|
||||
/client/proc/cmd_ss_panic
|
||||
/client/proc/cmd_ss_panic,
|
||||
/client/proc/configure_access_control
|
||||
)
|
||||
var/list/admin_verbs_debug = list(
|
||||
/client/proc/getruntimelog, // allows us to access runtime logs to somebody,
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/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*60*60*10))
|
||||
return TRUE
|
||||
else
|
||||
if (world.realtime < cacherealtime+(config.ipintel_save_bad*60*60*10))
|
||||
return TRUE
|
||||
|
||||
/proc/get_ip_intel(ip, bypasscache = FALSE, updatecache = TRUE)
|
||||
var/datum/ipintel/res = new()
|
||||
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(establish_db_connection(dbcon))
|
||||
var/DBQuery/query_get_ip_intel = dbcon.NewQuery({"
|
||||
SELECT date, intel, TIMESTAMPDIFF(MINUTE,date,NOW())
|
||||
FROM ss13_ipintel
|
||||
WHERE
|
||||
ip = INET6_ATON('[ip]')
|
||||
AND ((
|
||||
intel < [config.ipintel_rating_bad]
|
||||
AND
|
||||
date + INTERVAL [config.ipintel_save_good] HOUR > NOW()
|
||||
) OR (
|
||||
intel >= [config.ipintel_rating_bad]
|
||||
AND
|
||||
date + INTERVAL [config.ipintel_save_bad] HOUR > NOW()
|
||||
))
|
||||
"})
|
||||
if(!query_get_ip_intel.Execute())
|
||||
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
|
||||
return
|
||||
res.intel = ip_intel_query(ip)
|
||||
if (updatecache && res.intel >= 0)
|
||||
SSipintel.cache[ip] = res
|
||||
if(establish_db_connection(dbcon))
|
||||
var/DBQuery/query_add_ip_intel = dbcon.NewQuery("INSERT INTO ss13_ipintel (ip, intel) VALUES (INET6_ATON('[ip]'), [res.intel]) ON DUPLICATE KEY UPDATE intel = VALUES(intel), date = NOW()")
|
||||
query_add_ip_intel.Execute()
|
||||
|
||||
|
||||
|
||||
/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=f")
|
||||
|
||||
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 + (10 * 120 * SSipintel.errors)
|
||||
else
|
||||
error += " Attempting retry on [ip]."
|
||||
log_ipintel(error)
|
||||
|
||||
/proc/log_ipintel(text)
|
||||
log_game("IPINTEL: [text]")
|
||||
log_debug("IPINTEL: [text]")
|
||||
@@ -1606,6 +1606,10 @@
|
||||
|
||||
return
|
||||
|
||||
else if(href_list["access_control"])
|
||||
access_control_topic(href_list["access_control"])
|
||||
return
|
||||
|
||||
mob/living/proc/can_centcom_reply()
|
||||
return 0
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/client/proc/configure_access_control()
|
||||
set category = "Server"
|
||||
set name = "Configure Access Control"
|
||||
|
||||
if (!check_rights(R_SERVER))
|
||||
return
|
||||
|
||||
var/datum/browser/config_window = new(usr, "access_control", "Access Control")
|
||||
config_window.add_head_content("<title>Access Control</title>")
|
||||
|
||||
var/data = "These settings control who can access the server during this round.<br>"
|
||||
data += "They must be reset every single time the server restarts.<br>"
|
||||
data += "<b>If you do not know what these do, you shouldn't be touching them!</b><hr>"
|
||||
|
||||
data += "<h2>IP Intel Settings:</h2><br><ul>"
|
||||
data += "<li>Current warning level: [config.ipintel_rating_bad ? "[config.ipintel_rating_bad]" : "<font color='red'>DISABLED</font>"]. <a href='?_src_=holder;access_control=intel_bad'>Edit</a></li>"
|
||||
data += "<li>Current kick level: [config.ipintel_rating_kick ? "[config.ipintel_rating_kick]" : "<font color='red'>DISABLED</font>"]. <a href='?_src_=holder;access_control=intel_kick'>Edit</a></li>"
|
||||
data += "</ul><hr>"
|
||||
|
||||
data += "<h2>Player Age Settings:</h2><br><ul>"
|
||||
data += "<li>New players: [config.access_deny_new_players ? "<font color='green'>ALLOWED</font>" : "<font color='red'>DENIED</font>"]. <a href='?_src_=holder;access_control=new_players;'>Toggle</a></li>"
|
||||
data += "<li>Account age restriction: [config.access_deny_new_accounts == -1 ? "<font color='red'>DISABLED</font>" : "[config.access_deny_new_accounts] DAYS"]. <a href='?_src_=holder;access_control=new_accounts;'>Edit</a></li>"
|
||||
data += "</ul><hr>"
|
||||
|
||||
data += "<h2>VM Detection Settings:</h2><br><ul>"
|
||||
data += "<li>VM identifier count to warn on: [config.access_warn_vms ? "[config.access_warn_vms]" : "<font color='red'>DISABLED</font>"]. <a href='?_src_=holder;access_control=vm_warn;'>Edit</a></li>"
|
||||
data += "<li>VM identifier count to kick on: [config.access_deny_vms ? "[config.access_deny_vms]" : "<font color='red'>DISABLED</font>"]. <a href='?_src_=holder;access_control=vm_kick;'>Edit</a></li>"
|
||||
data += "</ul>"
|
||||
|
||||
config_window.set_user(src.mob)
|
||||
config_window.set_content(data)
|
||||
config_window.open()
|
||||
|
||||
/datum/admins/proc/access_control_topic(control)
|
||||
if (!control)
|
||||
to_chat(usr, "<span class='warning'>No control option sent. Cancelling.</span>")
|
||||
return
|
||||
|
||||
if (!check_rights(R_SERVER))
|
||||
log_and_message_admins("has tried editing access control without the permissions to do so.")
|
||||
return
|
||||
|
||||
switch(control)
|
||||
if ("intel_bad")
|
||||
var/num = input("Please set the new threshold for warning based on IPintel (0 to disable).", "New Threshold", config.ipintel_rating_kick) as num
|
||||
if (num < 0 || num > 1)
|
||||
to_chat(usr, "<span class='warning'>Invalid number. Cancelling.</span>")
|
||||
return
|
||||
|
||||
config.ipintel_rating_bad = num
|
||||
if (num)
|
||||
log_and_message_admins("has set the IPIntel warn threshold to [num].")
|
||||
else
|
||||
log_and_message_admins("has disabled warn based on IPIntel.")
|
||||
if ("intel_kick")
|
||||
var/num = input("Please set the new threshold for kicking based on IPintel (0 to disable).", "New Threshold", config.ipintel_rating_kick) as num
|
||||
if (num < 0 || num > 1)
|
||||
to_chat(usr, "<span class='warning'>Invalid number. Cancelling.</span>")
|
||||
return
|
||||
|
||||
config.ipintel_rating_kick = num
|
||||
if (num)
|
||||
log_and_message_admins("has set the IPIntel kick threshold to [num].")
|
||||
else
|
||||
log_and_message_admins("has disabled kicking based on IPIntel.")
|
||||
if ("new_players")
|
||||
config.access_deny_new_players = !config.access_deny_new_players
|
||||
log_and_message_admins("has [config.access_deny_new_players ? "ENABLED" : "DISABLED"] the kicking of new players.")
|
||||
if ("new_accounts")
|
||||
var/num = input("Please set the new threshold for denying access based on BYOND account age. (-1 to disable.)", "New Threshold", config.access_deny_new_accounts) as num
|
||||
if (num < 0 && num != -1)
|
||||
to_chat(usr, "<span class='warning'>Invalid number. Cancelling.</span>")
|
||||
return
|
||||
|
||||
config.access_deny_new_accounts = num
|
||||
if (num != -1)
|
||||
log_and_message_admins("has set the access barrier for new BYOND accounts to [num] days.")
|
||||
else
|
||||
log_and_message_admins("has disabled kicking based on BYOND account age.")
|
||||
if ("vm_warn")
|
||||
var/num = input("Please set the new threshold for warning on login based on positive VM identifiers. (0 to disable.)", "New Threshold") in list(0, 1, 2)
|
||||
|
||||
config.access_warn_vms = num
|
||||
if (num)
|
||||
log_and_message_admins("has set players with [config.access_warn_vms] positive identifiers out of 2 for VM usage to be warned.")
|
||||
else
|
||||
log_and_message_admins("has disabled warnings based on potential VM usage.")
|
||||
if ("vm_kick")
|
||||
var/num = input("Please set the new threshold for warning on login based on positive VM identifiers. (0 to disable.)", "New Threshold") in list(0, 1, 2)
|
||||
|
||||
config.access_deny_vms = num
|
||||
if (num)
|
||||
log_and_message_admins("has set players with [config.access_deny_vms] positive identifiers out of 2 for VM usage to be warned.")
|
||||
else
|
||||
log_and_message_admins("has disabled warnings based on potential VM usage.")
|
||||
else
|
||||
to_chat(usr, "<span class='danger'>Unknown control message sent. Cancelling.</span>")
|
||||
|
||||
owner.configure_access_control()
|
||||
@@ -9,6 +9,19 @@ var/list/VVlocked = list("vars", "holder", "client", "virus", "viruses", "cuffed
|
||||
var/list/VVicon_edit_lock = list("icon", "icon_state", "overlays", "underlays")
|
||||
var/list/VVckey_edit = list("key", "ckey")
|
||||
|
||||
// The paranoia box. Specify a var name => bitflags required to edit it.
|
||||
// Allows the securing of specific variables for, for example, config. That alter
|
||||
// how players could join! Definitely not something you want folks to touch if they
|
||||
// don't have the perms.
|
||||
var/list/VVdynamic_lock = list(
|
||||
"access_deny_new_players" = R_SERVER,
|
||||
"access_deny_new_accounts" = R_SERVER,
|
||||
"access_deny_vms" = R_SERVER,
|
||||
"access_warn_vms" = R_SERVER,
|
||||
"ipintel_rating_bad" = R_SERVER,
|
||||
"ipintel_rating_kick" = R_SERVER
|
||||
)
|
||||
|
||||
/*
|
||||
/client/proc/cmd_modify_object_variables(obj/O as obj|mob|turf|area in world) // Acceptable 'in world', as VV would be incredibly hampered otherwise
|
||||
set category = "Debug"
|
||||
@@ -171,6 +184,8 @@ var/list/VVckey_edit = list("key", "ckey")
|
||||
if(!check_rights(R_SPAWN|R_DEBUG|R_DEV)) return
|
||||
if(variable in VVicon_edit_lock)
|
||||
if(!check_rights(R_FUN|R_DEBUG|R_DEV)) return
|
||||
if(VVdynamic_lock[variable])
|
||||
if(!check_rights(VVdynamic_lock[variable])) return
|
||||
|
||||
if(isnull(variable))
|
||||
usr << "Unable to determine variable type."
|
||||
@@ -364,6 +379,8 @@ var/list/VVckey_edit = list("key", "ckey")
|
||||
if(!check_rights(R_SPAWN|R_DEBUG|R_DEV)) return
|
||||
if(param_var_name in VVicon_edit_lock)
|
||||
if(!check_rights(R_FUN|R_DEBUG|R_DEV)) return
|
||||
if(VVdynamic_lock[variable])
|
||||
if(!check_rights(VVdynamic_lock[variable])) return
|
||||
|
||||
variable = param_var_name
|
||||
|
||||
@@ -426,6 +443,8 @@ var/list/VVckey_edit = list("key", "ckey")
|
||||
if(!check_rights(R_SPAWN|R_DEBUG|R_DEV)) return
|
||||
if(variable in VVicon_edit_lock)
|
||||
if(!check_rights(R_FUN|R_DEBUG|R_DEV)) return
|
||||
if(VVdynamic_lock[variable])
|
||||
if(!check_rights(VVdynamic_lock[variable])) return
|
||||
|
||||
if(!autodetect_class)
|
||||
|
||||
|
||||
@@ -197,6 +197,7 @@ proc/cmd_admin_mute(mob/M as mob, mute_type, automute = 0)
|
||||
if(M.client.prefs.muted & mute_type)
|
||||
muteunmute = "unmuted"
|
||||
M.client.prefs.muted &= ~mute_type
|
||||
M.client.spam_alert = 0
|
||||
else
|
||||
muteunmute = "muted"
|
||||
M.client.prefs.muted |= mute_type
|
||||
@@ -623,7 +624,7 @@ Traitors and the like can also be revived with the previous role mostly intact.
|
||||
if (!holder)
|
||||
src << "Only administrators may use this command."
|
||||
return
|
||||
|
||||
|
||||
for(var/datum/job/job in SSjobs.occupations)
|
||||
src << "[job.title]: [job.total_positions]"
|
||||
feedback_add_details("admin_verb","LFS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
|
||||
|
||||
Reference in New Issue
Block a user