- Fixes the broken population logging

- The current, file-based ban system is now a legacy system, the use of which is strongly discouraged for servers, which are constantly online.
- Added a database-based banning system, with a new baning panel, accessible through the 'banning panel' verb. Servers, which use this new banning system, will get the new panel up even if they use the old 'unban panel' or 'display job bans' verbs. These remain there for legacy support purposes. (Panel screenshot below)
- The most notable benefits of the new system are the ability to add offline bans, meaning the person does not have to be connected for a ban to be applied to their name. The second benefit is the ability to look up all previous bans that the person had.
- The major disadvantage is the complete incompatibility between the old and new system, meaning you have to either do a lot of copy-pasting or playing around in code to sync the old system with the new one. Servers upgrading to this system might want to consider a purge of all bans, if they don't want to go through this. Due to the incompatibility, there are no transition tools provided. Please contact me (errorage/rageroro) in #coderbus for help in syncing your database. The /tg/ legacy and database systems have been synced.
- The server configuration defaults to use the legacy system, as the new one requires the database to be set up. Please hash BAN_LEGACY_SYSTEM in config.txt as explained, to use the new system. If the database connection fails, the server reverts to the legacy system.

If any bugs or errors appear with either the legacy or new ban system, please let me know ASAP. The same applies if there are any syncronization problems between the legacy and new system, resulting in banned people unbanned or unbanned people banned.

Panel screenshot:
http://www.kamletos.si/new%20ban%20panel2.PNG

git-svn-id: http://tgstation13.googlecode.com/svn/trunk@5034 316c924e-a436-60f5-8080-3fe189b3f50e
This commit is contained in:
baloh.matevz
2012-11-11 05:39:09 +00:00
parent b8cb37af2a
commit 2f57200e82
8 changed files with 386 additions and 47 deletions

View File

@@ -89,7 +89,8 @@
var/metroid_delay = 0
var/animal_delay = 0
var/admin_legacy_system = 0 //Defines whether the server uses the legacy admin system with admins.txt or the SQL system.
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
/datum/configuration/New()
var/list/L = typesof(/datum/game_mode) - /datum/game_mode
@@ -139,6 +140,9 @@
if ("admin_legacy_system")
config.admin_legacy_system = 1
if ("ban_legacy_system")
config.ban_legacy_system = 1
if ("log_ooc")
config.log_ooc = 1

View File

@@ -10,7 +10,7 @@ proc/sql_poll_players()
log_game("SQL ERROR during player polling. Failed to connect.")
else
var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")
var/DBQuery/query = dbcon.NewQuery("INSERT INTO population (playercount, time) VALUES ([playercount], '[sqltime]')")
var/DBQuery/query = dbcon_old.NewQuery("INSERT INTO population (playercount, time) VALUES ([playercount], '[sqltime]')")
if(!query.Execute())
var/err = query.ErrorMsg()
log_game("SQL ERROR during player polling. Error : \[[err]\]\n")
@@ -25,7 +25,7 @@ proc/sql_poll_admins()
log_game("SQL ERROR during admin polling. Failed to connect.")
else
var/sqltime = time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")
var/DBQuery/query = dbcon.NewQuery("INSERT INTO population (admincount, time) VALUES ([admincount], '[sqltime]')")
var/DBQuery/query = dbcon_old.NewQuery("INSERT INTO population (admincount, time) VALUES ([admincount], '[sqltime]')")
if(!query.Execute())
var/err = query.ErrorMsg()
log_game("SQL ERROR during admin polling. Error : \[[err]\]\n")

View File

@@ -1,5 +1,5 @@
datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = -1, var/reason, var/job = "", var/rounds = 0)
datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration = -1, var/reason, var/job = "", var/rounds = 0, var/banckey = null)
establish_db_connection()
if(!dbcon.IsConnected())
return
@@ -35,6 +35,17 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration =
if(banned_mob.client)
computerid = banned_mob.client.computer_id
ip = banned_mob.client.address
else if(banckey)
ckey = ckey(banckey)
var/DBQuery/query = dbcon.NewQuery("SELECT id FROM erro_player WHERE ckey = '[ckey]'")
query.Execute()
var/validckey = 0
if(query.NextRow())
validckey = 1
if(!validckey)
message_admins("<font color='red'>[key_name_admin(usr)] attempted to ban [ckey], but [ckey] has not been seen yet. Please only ban actual players.</font>",1)
return
var/a_ckey
var/a_computerid
@@ -64,6 +75,8 @@ datum/admins/proc/DB_ban_record(var/bantype, var/mob/banned_mob, var/duration =
var/sql = "INSERT INTO erro_ban VALUES (null, Now(), '[serverip]', '[bantype_str]', '[reason]', '[job]', [(duration)?"[duration]":"0"], [(rounds)?"[rounds]":"0"], Now() + INTERVAL [(duration>0) ? duration : 0] MINUTE, '[ckey]', '[computerid]', '[ip]', '[a_ckey]', '[a_computerid]', '[a_ip]', '[who]', '[adminwho]', '', null, null, null, null, null)"
var/DBQuery/query_insert = dbcon.NewQuery(sql)
query_insert.Execute()
usr << "\blue Ban saved to database."
message_admins("[key_name_admin(usr)] has added a [bantype_str] for [ckey] [(job)?"([job])":""] [(duration > 0)?"([duration] minutes)":""] with the reason: \"[reason]\" to the ban database.",1)
@@ -129,10 +142,67 @@ datum/admins/proc/DB_ban_unban(var/ckey, var/bantype, var/job = "")
DB_ban_unban_by_id(ban_id)
datum/admins/proc/DB_ban_edit(var/banid = null, var/param = null)
if(!isnum(banid) || !istext(param))
usr << "Cancelled"
return
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, duration, reason FROM erro_ban WHERE id = [banid]")
query.Execute()
var/eckey = usr.ckey //Editing admin ckey
var/pckey //(banned) Player ckey
var/duration //Old duration
var/reason //Old reason
if(query.NextRow())
pckey = query.item[1]
duration = query.item[2]
reason = query.item[3]
else
usr << "Invalid ban id. Contact the database admin"
return
reason = sql_sanitize_text(reason)
var/value
switch(param)
if("reason")
if(!value)
value = input("Insert the new reason for [pckey]'s ban", "New Reason", "[reason]", null) as null|text
value = sql_sanitize_text(value)
if(!value)
usr << "Cancelled"
return
var/DBQuery/update_query = dbcon.NewQuery("UPDATE erro_ban SET reason = '[value]', edits = CONCAT(edits,'- [eckey] changed ban reason from <cite><b>\\\"[reason]\\\"</b></cite> to <cite><b>\\\"[value]\\\"</b></cite><BR>') WHERE id = [banid]")
update_query.Execute()
message_admins("[key_name_admin(usr)] has edited a ban for [pckey]'s reason from [reason] to [value]",1)
if("duration")
if(!value)
value = input("Insert the new duration (in minutes) for [pckey]'s ban", "New Duration", "[duration]", null) as null|num
if(!isnum(value) || !value)
usr << "Cancelled"
return
var/DBQuery/update_query = dbcon.NewQuery("UPDATE erro_ban SET duration = [value], edits = CONCAT(edits,'- [eckey] changed ban duration from [duration] to [value]<br>'), expiration_time = DATE_ADD(bantime, INTERVAL [value] MINUTE) WHERE id = [banid]")
message_admins("[key_name_admin(usr)] has edited a ban for [pckey]'s duration from [duration] to [value]",1)
update_query.Execute()
if("unban")
if(alert("Unban [pckey]?", "Unban?", "Yes", "No") == "Yes")
DB_ban_unban_by_id(banid)
return
else
usr << "Cancelled"
return
else
usr << "Cancelled"
return
datum/admins/proc/DB_ban_unban_by_id(var/id)
var/sql = "SELECT id FROM erro_ban WHERE id = [id]"
var/sql = "SELECT ckey FROM erro_ban WHERE id = [id]"
establish_db_connection()
if(!dbcon.IsConnected())
@@ -140,9 +210,11 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
var/ban_number = 0 //failsafe
var/pckey
var/DBQuery/query = dbcon.NewQuery(sql)
query.Execute()
while(query.NextRow())
pckey = query.item[1]
ban_number++;
if(ban_number == 0)
@@ -161,7 +233,159 @@ datum/admins/proc/DB_ban_unban_by_id(var/id)
var/unban_ip = src.owner:address
var/sql_update = "UPDATE erro_ban SET unbanned = 1, unbanned_datetime = Now(), unbanned_ckey = '[unban_ckey]', unbanned_computerid = '[unban_computerid]', unbanned_ip = '[unban_ip]' WHERE id = [id]"
message_admins("[key_name_admin(usr)] has lifted [pckey]'s ban.",1)
var/DBQuery/query_update = dbcon.NewQuery(sql_update)
query_update.Execute()
/client/proc/DB_ban_panel()
set category = "Admin"
set name = "Banning Panel"
set desc = "Edit admin permissions"
if(!holder)
return
holder.DB_ban_panel()
/datum/admins/proc/DB_ban_panel(var/playerckey = null, var/adminckey = null)
if(!usr.client)
return
//if(check_rights(R_BAN))
// usr << "\red You do not have permission to do this!"
// return
establish_db_connection()
if(!dbcon.IsConnected())
usr << "\red Failed to establish database connection"
return
var/output = "<div align='center'><table width='90%'><tr>"
output += "<td width='35%' align='center'>"
output += "<h1>Banning panel</h1>"
output += "</td>"
output += "<td width='65%' align='center' bgcolor='#f9f9f9'>"
output += "<form method='GET' action='?src=\ref[src]'><b>Add custom ban:</b> (ONLY use this if you can't ban through any other method)"
output += "<input type='hidden' name='src' value='\ref[src]'>"
output += "<table width='100%'><tr>"
output += "<td><b>Ban type:</b><select name='dbbanaddtype'>"
output += "<option value=''>--</option>"
output += "<option value='[BANTYPE_PERMA]'>PERMABAN</option>"
output += "<option value='[BANTYPE_TEMP]'>TEMPBAN</option>"
output += "<option value='[BANTYPE_JOB_PERMA]'>JOB PERMABAN</option>"
output += "</select></td>"
output += "<td><b>Ckey:</b> <input type='text' name='dbbanaddckey'></td></tr>"
output += "<tr><td><b>Duration:</b> <input type='text' name='dbbaddduration'></td>"
output += "<td><b>Job:</b><select name='dbbanaddjob'>"
output += "<option value=''>--</option>"
for(var/j in get_all_jobs())
output += "<option value='[j]'>[j]</option>"
output += "</select></td></tr></table>"
output += "<b>Reason:<br></b><textarea name='dbbanreason' cols='50'></textarea><br>"
output += "<input type='submit' value='Add ban'>"
output += "</form>"
output += "</td>"
output += "</tr>"
output += "</table>"
output += "<form method='GET' action='?src=\ref[src]'><b>Search:</b> "
output += "<input type='hidden' name='src' value='\ref[src]'>"
output += "<b>Ckey:</b> <input type='text' name='dbsearchckey' value='[playerckey]'>"
output += "<b>Admin ckey:</b> <input type='text' name='dbsearchadmin' value='[adminckey]'>"
output += "<input type='submit' value='search'>"
output += "</form>"
output += "Please note that all jobban bans or unbans are in-effect the following round."
if(adminckey || playerckey)
var/blcolor = "#ffeeee" //banned light
var/bdcolor = "#ffdddd" //banned dark
var/ulcolor = "#eeffee" //unbanned light
var/udcolor = "#ddffdd" //unbanned dark
output += "<table width='90%' bgcolor='#e3e3e3' cellpadding='5' cellspacing='0' align='center'>"
output += "<tr>"
output += "<th width='25%'><b>TYPE</b></th>"
output += "<th width='20%'><b>CKEY</b></th>"
output += "<th width='20%'><b>TIME APPLIED</b></th>"
output += "<th width='20%'><b>ADMIN</b></th>"
output += "<th width='15%'><b>OPTIONS</b></th>"
output += "</tr>"
adminckey = ckey(adminckey)
playerckey = ckey(playerckey)
var/adminsearch = ""
var/playersearch = ""
if(adminckey)
adminsearch = "AND a_ckey = '[adminckey]' "
if(playerckey)
playersearch = "AND ckey = '[playerckey]' "
var/DBQuery/select_query = dbcon.NewQuery("SELECT id, bantime, bantype, reason, job, duration, expiration_time, ckey, a_ckey, unbanned, unbanned_ckey, unbanned_datetime, edits FROM erro_ban WHERE 1 [playersearch] [adminsearch] ORDER BY bantime DESC")
select_query.Execute()
while(select_query.NextRow())
var/banid = select_query.item[1]
var/bantime = select_query.item[2]
var/bantype = select_query.item[3]
var/reason = select_query.item[4]
var/job = select_query.item[5]
var/duration = select_query.item[6]
var/expiration = select_query.item[7]
var/ckey = select_query.item[8]
var/ackey = select_query.item[9]
var/unbanned = select_query.item[10]
var/unbanckey = select_query.item[11]
var/unbantime = select_query.item[12]
var/edits = select_query.item[13]
var/lcolor = blcolor
var/dcolor = bdcolor
if(unbanned)
lcolor = ulcolor
dcolor = udcolor
var/typedesc =""
switch(bantype)
if("PERMABAN")
typedesc = "<font color='red'><b>PERMABAN</b></font>"
if("TEMPBAN")
typedesc = "<b>TEMPBAN</b><br><font size='2'>([duration] minutes [(unbanned) ? "" : "(<a href=\"byond://?src=\ref[src];dbbanedit=duration;dbbanid=[banid]\">Edit</a>))"]<br>Expires [expiration]</font>"
if("JOB_PERMABAN")
typedesc = "<b>JOBBAN</b><br><font size='2'>([job])"
output += "<tr bgcolor='[dcolor]'>"
output += "<td align='center'>[typedesc]</td>"
output += "<td align='center'><b>[ckey]</b></td>"
output += "<td align='center'>[bantime]</td>"
output += "<td align='center'><b>[ackey]</b></td>"
output += "<td align='center'>[(unbanned) ? "" : "<b><a href=\"byond://?src=\ref[src];dbbanedit=unban;dbbanid=[banid]\">Unban</a></b>"]</td>"
output += "</tr>"
output += "<tr bgcolor='[lcolor]'>"
output += "<td align='center' colspan='5'><b>Reason: [(unbanned) ? "" : "(<a href=\"byond://?src=\ref[src];dbbanedit=reason;dbbanid=[banid]\">Edit</a>)"]</b> <cite>\"[reason]\"</cite></td>"
output += "</tr>"
if(edits)
output += "<tr bgcolor='[dcolor]'>"
output += "<td align='center' colspan='5'><b>EDITS</b></td>"
output += "</tr>"
output += "<tr bgcolor='[lcolor]'>"
output += "<td align='center' colspan='5'><font size='2'>[edits]</font></td>"
output += "</tr>"
if(unbanned)
output += "<tr bgcolor='[dcolor]'>"
output += "<td align='center' colspan='5' bgcolor=''><b>UNBANNED by admin [unbanckey] on [unbantime]</b></td>"
output += "</tr>"
output += "<tr>"
output += "<td colspan='5' bgcolor='white'>&nbsp</td>"
output += "</tr>"
output += "</table></div>"
usr << browse(output,"window=lookupbans;size=900x500")

View File

@@ -1,7 +1,9 @@
//Blocks an attempt to connect before even creating our client datum thing.
world/IsBanned(key,address,computer_id)
if(ckey(key) in admin_datums)
return ..()
//if(ckey(key) in admin_datums)
// return ..()
if(config.ban_legacy_system)
//Guest Checking
if( !guests_allowed && IsGuestKey(key) )
@@ -25,3 +27,37 @@ world/IsBanned(key,address,computer_id)
return .
return ..() //default pager ban stuff
else
var/ckeytext = ckey(key)
if(!establish_db_connection())
world.log << "Ban database connection failure. Key [ckeytext] not checked"
diary << "Ban database connection failure. Key [ckeytext] not checked"
return
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, ip, computerid, a_ckey, reason, expiration_time, duration, bantime, bantype FROM erro_Ban WHERE (ckey = '[ckeytext]' OR ip = '[address]' OR computerid = '[computer_id]') AND (bantype = 'PERMABAN' OR (bantype = 'TEMPBAN' AND expiration_time > Now())) AND isnull(unbanned)")
query.Execute()
while(query.NextRow())
var/pckey = query.item[1]
//var/pip = query.item[2]
//var/pcid = query.item[3]
var/ackey = query.item[4]
var/reason = query.item[5]
var/expiration = query.item[6]
var/duration = query.item[7]
var/bantime = query.item[8]
var/bantype = query.item[9]
var/expires = ""
if(text2num(duration) > 0)
expires = " The ban is for [duration] minutes and expires on [expiration] (server time)."
var/desc = "\nReason: You, or another user of this computer or connection ([pckey]) is banned from playing here. The ban reason is:\n[reason]\nThis ban was applied by [ackey] on [bantime], [expires]"
return list("reason"="[bantype]", "desc"="[desc]")
return ..() //default pager ban stuff

View File

@@ -59,7 +59,8 @@ var/list/admin_verbs_admin = list(
var/list/admin_verbs_ban = list(
/client/proc/unban_panel,
/client/proc/jobbans,
/client/proc/unjobban_panel
/client/proc/unjobban_panel,
/client/proc/DB_ban_panel
)
var/list/admin_verbs_sounds = list(
/client/proc/play_local_sound,
@@ -368,7 +369,10 @@ var/list/admin_verbs_hideable = list(
set name = "Display Job bans"
set category = "Admin"
if(holder)
if(config.ban_legacy_system)
holder.Jobbans()
else
holder.DB_ban_panel()
feedback_add_details("admin_verb","VJB") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
return
@@ -376,7 +380,10 @@ var/list/admin_verbs_hideable = list(
set name = "Unban Panel"
set category = "Admin"
if(holder)
if(config.ban_legacy_system)
holder.unbanpanel()
else
holder.DB_ban_panel()
feedback_add_details("admin_verb","UBP") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
return

View File

@@ -48,24 +48,31 @@ DEBUG
*/
/proc/jobban_loadbanfile()
if(config.ban_legacy_system)
var/savefile/S=new("data/job_full.ban")
S["keys[0]"] >> jobban_keylist
log_admin("Loading jobban_rank")
S["runonce"] >> jobban_runonce
/*
for(var/i = 1; i <= length(jobban_keylist); i++)
if( findtext(jobban_keylist[i],"##") )
var/index = findtext(jobban_keylist[i],"##")
var/s = jobban_keylist[i]
s = copytext( s , 1 , index ) //Removes the reason for the ban from this list
jobban_keylist[i] = s
world << "DEBUG: index: [index] - s: [s] - jobban_keylist\[[i]\] = [jobban_keylist[i]]"*/
if (!length(jobban_keylist))
jobban_keylist=list()
log_admin("jobban_keylist was empty")
else
if(!establish_db_connection())
world.log << "Database connection failed. Reverting to the legacy ban system."
diary << "Database connection failed. Reverting to the legacy ban system."
config.ban_legacy_system = 1
jobban_loadbanfile()
return
var/DBQuery/query = dbcon.NewQuery("SELECT ckey, job FROM erro_ban WHERE bantype = 'JOB_PERMABAN' AND isnull(unbanned)")
query.Execute()
while(query.NextRow())
var/ckey = query.item[1]
var/job = query.item[2]
jobban_keylist.Add("[ckey] - [job]")
/proc/jobban_savebanfile()
var/savefile/S=new("data/job_full.ban")

View File

@@ -45,6 +45,60 @@
log_admin("[key_name(usr)] has spawned a death squad.")
if(!src.makeDeathsquad())
usr << "\red Unfortunatly there were no candidates available"
else if(href_list["dbsearchckey"] || href_list["dbsearchadmin"])
var/adminckey = href_list["dbsearchadmin"]
var/playerckey = href_list["dbsearchckey"]
DB_ban_panel(playerckey, adminckey)
return
else if(href_list["dbbanedit"])
var/banedit = href_list["dbbanedit"]
var/banid = text2num(href_list["dbbanid"])
if(!banedit || !banid)
return
DB_ban_edit(banid, banedit)
return
else if(href_list["dbbanaddtype"])
var/bantype = text2num(href_list["dbbanaddtype"])
var/banckey = href_list["dbbanaddckey"]
var/banduration = text2num(href_list["dbbaddduration"])
var/banjob = href_list["dbbanaddjob"]
var/banreason = href_list["dbbanreason"]
banckey = ckey(banckey)
switch(bantype)
if(BANTYPE_PERMA)
if(!banckey || !banreason)
usr << "Not enough parameters (Requires ckey and reason)"
return
banduration = null
banjob = null
if(BANTYPE_TEMP)
if(!banckey || !banreason || !banduration)
usr << "Not enough parameters (Requires ckey, reason and duration)"
return
banjob = null
if(BANTYPE_JOB_PERMA)
if(!banckey || !banreason || !banjob)
usr << "Not enough parameters (Requires ckey, reason and job)"
return
banduration = null
var/mob/playermob
for(var/mob/M in player_list)
if(M.ckey == banckey)
playermob = M
break
banreason = "(MANUAL BAN) "+banreason
DB_ban_record(bantype, playermob, banduration, banreason, banjob, null, banckey)
else if(href_list["editadminpermissions"])
var/adm_ckey = href_list["editadminckey"]
@@ -595,6 +649,10 @@
//Unbanning joblist
//all jobs in joblist are banned already OR we didn't give a reason (implying they shouldn't be banned)
if(joblist.len) //at least 1 banned job exists in joblist so we have stuff to unban.
if(!config.ban_legacy_system)
usr << "Unfortunately, database based unbanning cannot be done through this panel"
DB_ban_panel(usr.client.ckey)
return
var/msg
for(var/job in joblist)
var/reason = jobban_isbanned(M, job)

View File

@@ -9,9 +9,12 @@ ALERT_RED_UPTO There is an immediate serious threat to the station. Security may
ALERT_RED_DOWNTO The self-destruct mechanism has been deactivated, there is still however an immediate serious threat to the station. Security may have weapons unholstered at all times, random searches are allowed and advised.
ALERT_DELTA The station's self-destruct mechanism has been engaged. All crew are instructed to obey all instructions given by heads of staff. Any violations of these orders can be punished by death. This is not a drill.
## Add a # infront of this if you want to use the SQL based admin system, the legacy system uses admins.txt
## Add a # infront of this if you want to use the SQL based admin system, the legacy system uses admins.txt. You need to set up your database to use the SQL based system.
ADMIN_LEGACY_SYSTEM
## Add a # infront of this if you want to use the SQL based banning system. The legacy systems use the files in the data folder. You need to set up your database to use the SQL based system.
BAN_LEGACY_SYSTEM
## log OOC channel
LOG_OOC