Files
vgstation13/code/modules/client/client procs.dm
elly1989@rocketmail.com 30357d18ce SANITY: Created a series of generalised sanity procs. They can be found in code/__HELPERS/sanitize_values.dm
They include such procs as sanitize_integer(num, min, max, default) which will check num is a number, round num to make it an integer, then check if it is between min and max (inclusive). If it fails the bound-checks it will return default. There are others, have a look.

PERSISTENT PREFERENCES: Every ckey which connects to the game gets its own persistent /datum/preferences datum.
It is archived in var/list/preferences_datums = list("ckey" = datum)
At connect it is automatically associated with the client defines.dm (or a new one is created if it can't find an archived prefs datum). This means clients will ALWAYS have a var/datum/preferences/prefs which references this datum. So you can use it without checking if(client.prefs)
This has simplified only a few bits of code. It will however, allow us to make preferences like see_deadchat ghost_ears etc, persistent. So they will not reset when you DC.

SAVEFILES: Changed the player savefile code a lot. Hopefully I've not fucked it up too much. Every single variable loaded from saves is now sanity checked using the new sanity procs. This should help prevent savefiles becomming obsolete by sanitizing input to meet current requirements, without deleting all the ok variables and making you start from scratch >_> NOTE: I still need to sort out the savefile version stuff. I'll probably figure it out before the server updates anyway. It sees to be fine without it.

You can no longer choose your blood type. It is randomised (with each bloodtype having a realistic probability of occuring). This is to make blood analysis (detective/medical) less pointless. It is chosen as soon as you connect. It remains persistent throughout each round so you won't be able to change it by logging in/out over and over.

Replaces some copypasta code with is_afk() (still a fair bit to do)

There are new hyperlink shortcut things. _src_=vars will direct your hyperlink to viewvars. _src_=prefs to your preferences datum. (These are the only way to access those bits of code via links). This means that the overall amount of operations in almost every Topic has pretty much halved and is much prettier.

Replaced and removed adminplayervars from datum/admins/Topic. It was superfluous. They now all point directly to the viewvars code using _src_=vars

Removed the changelog popup at round start. Instead a button on your game-window will glow white if there are new updates. To peruse at your convenience. This will speed up connect times.

Removed the AFK_THRESHOLD define. It is integrated into is_afk() now.

TODO: remove the prefs stuff from mobs and clients and update code to use client.prefs to access that info.



git-svn-id: http://tgstation13.googlecode.com/svn/trunk@5121 316c924e-a436-60f5-8080-3fe189b3f50e
2012-11-19 15:13:57 +00:00

243 lines
8.2 KiB
Plaintext

////////////
//SECURITY//
////////////
#define TOPIC_SPAM_DELAY 4 //4 ticks is about 3/10ths of a second
#define UPLOAD_LIMIT 1048576 //Restricts client uploads to the server to 1MB //Could probably do with being lower.
#define MIN_CLIENT_VERSION 0 //Just an ambiguously low version for now, I don't want to suddenly stop people playing.
//I would just like the code ready should it ever need to be used.
/*
When somebody clicks a link in game, this Topic is called first.
It does the stuff in this proc and then is redirected to the Topic() proc for the src=[0xWhatever]
(if specified in the link). ie locate(hsrc).Topic()
Such links can be spoofed.
Because of this certain things MUST be considered whenever adding a Topic() for something:
- Can it be fed harmful values which could cause runtimes?
- Is the Topic call an admin-only thing?
- If so, does it have checks to see if the person who called it (usr.client) is an admin?
- Are the processes being called by Topic() particularly laggy?
- If so, is there any protection against somebody spam-clicking a link?
If you have any questions about this stuff feel free to ask. ~Carn
*/
/client/Topic(href, href_list, hsrc)
if(!usr || usr != mob) //stops us calling Topic for somebody else's client. Also helps prevent usr=null
return
//Reduces spamming of links by dropping calls that happen during the delay period
if(next_allowed_topic_time > world.time)
return
next_allowed_topic_time = world.time + TOPIC_SPAM_DELAY
//search the href for script injection
if( findtext(href,"<script",1,0) )
world.log << "Attempted use of scripts within a topic call, by [src]"
message_admins("Attempted use of scripts within a topic call, by [src]")
//del(usr)
return
//Admin PM
if(href_list["priv_msg"])
var/client/C = locate(href_list["priv_msg"])
if(ismob(C)) //Old stuff can feed-in mobs instead of clients
var/mob/M = C
C = M.client
cmd_admin_pm(C,null)
return
//Logs all hrefs
if(config && config.log_hrefs && href_logfile)
href_logfile << "<small>[time2text(world.timeofday,"hh:mm")] [src] (usr:[usr])</small> || [hsrc ? "[hsrc] " : ""][href]<br>"
switch(href_list["_src_"])
if("holder") hsrc = holder
if("usr") hsrc = mob
if("prefs") return prefs.process_link(usr,href_list)
if("vars") return view_var_Topic(href,href_list,hsrc)
..() //redirect to hsrc.Topic()
/client/proc/handle_spam_prevention(var/message, var/mute_type)
if(config.automute_on && !holder && src.last_message == message)
src.last_message_count++
if(src.last_message_count >= SPAM_TRIGGER_AUTOMUTE)
src << "\red You have exceeded the spam filter limit for identical messages. An auto-mute was applied."
cmd_admin_mute(src.mob, mute_type, 1)
return 1
if(src.last_message_count >= SPAM_TRIGGER_WARNING)
src << "\red You are nearing the spam filter limit for identical messages."
return 0
else
last_message = message
src.last_message_count = 0
return 0
//This stops files larger than UPLOAD_LIMIT being sent from client to server via input(), client.Import() etc.
/client/AllowUpload(filename, filelength)
if(filelength > UPLOAD_LIMIT)
src << "<font color='red'>Error: AllowUpload(): File Upload too large. Upload Limit: [UPLOAD_LIMIT/1024]KiB.</font>"
return 0
/* //Don't need this at the moment. But it's here if it's needed later.
//Helps prevent multiple files being uploaded at once. Or right after eachother.
var/time_to_wait = fileaccess_timer - world.time
if(time_to_wait > 0)
src << "<font color='red'>Error: AllowUpload(): Spam prevention. Please wait [round(time_to_wait/10)] seconds.</font>"
return 0
fileaccess_timer = world.time + FTPDELAY */
return 1
///////////
//CONNECT//
///////////
/client/New(TopicData)
TopicData = null //Prevent calls to client.Topic from connect
if(connection != "seeker") //Invalid connection type.
return null
if(byond_version < MIN_CLIENT_VERSION) //Out of date client.
return null
clients += src
directory[ckey] = src
//Admin Authorisation
holder = admin_datums[ckey]
if(holder)
admins += src
holder.owner = src
//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)
prefs = new /datum/preferences(src)
preferences_datums[ckey] = prefs
. = ..() //calls mob.Login()
if( (world.address == address || !address) && !host )
host = key
world.update_status()
if(holder)
add_admin_verbs()
admin_memo_show()
log_client_to_db()
send_resources()
if(prefs.lastchangelog != changelog_hash) //bolds the changelog button on the interface so we know there are updates.
winset(src, "rpane.changelog", "background-color=#eaeaea;font-style=bold")
//////////////
//DISCONNECT//
//////////////
/client/Del()
if(holder)
holder.owner = null
admins -= src
directory -= ckey
clients -= src
return ..()
/client/proc/log_client_to_db()
if ( IsGuestKey(src.key) )
return
establish_db_connection()
if(!dbcon.IsConnected())
return
var/sql_ckey = sql_sanitize_text(src.ckey)
var/DBQuery/query = dbcon.NewQuery("SELECT id FROM erro_player WHERE ckey = '[sql_ckey]'")
query.Execute()
var/sql_id = 0
while(query.NextRow())
sql_id = query.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
var/sql_ip = sql_sanitize_text(src.address)
var/sql_computerid = sql_sanitize_text(src.computer_id)
var/sql_admin_rank = sql_sanitize_text(admin_rank)
if(sql_id)
//Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables
var/DBQuery/query_update = dbcon.NewQuery("UPDATE erro_player SET lastseen = Now(), ip = '[sql_ip]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]' WHERE id = [sql_id]")
query_update.Execute()
else
//New player!! Need to insert all the stuff
var/DBQuery/query_insert = dbcon.NewQuery("INSERT INTO erro_player (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank) VALUES (null, '[sql_ckey]', Now(), Now(), '[sql_ip]', '[sql_computerid]', '[sql_admin_rank]')")
query_insert.Execute()
#undef TOPIC_SPAM_DELAY
#undef UPLOAD_LIMIT
#undef MIN_CLIENT_VERSION
//checks if a client is afk
//3000 frames = 5 minutes
/client/proc/is_afk(duration=3000)
if(inactivity > duration) return inactivity
return 0
//send resources to the client. It's here in its own proc so we can move it around easiliy if need be
/client/proc/send_resources()
getFiles(
'html/search.js',
'html/panels.css',
'icons/pda_icons/pda_atmos.png',
'icons/pda_icons/pda_back.png',
'icons/pda_icons/pda_bell.png',
'icons/pda_icons/pda_blank.png',
'icons/pda_icons/pda_boom.png',
'icons/pda_icons/pda_bucket.png',
'icons/pda_icons/pda_crate.png',
'icons/pda_icons/pda_cuffs.png',
'icons/pda_icons/pda_eject.png',
'icons/pda_icons/pda_exit.png',
'icons/pda_icons/pda_flashlight.png',
'icons/pda_icons/pda_honk.png',
'icons/pda_icons/pda_mail.png',
'icons/pda_icons/pda_medical.png',
'icons/pda_icons/pda_menu.png',
'icons/pda_icons/pda_mule.png',
'icons/pda_icons/pda_notes.png',
'icons/pda_icons/pda_power.png',
'icons/pda_icons/pda_rdoor.png',
'icons/pda_icons/pda_reagent.png',
'icons/pda_icons/pda_refresh.png',
'icons/pda_icons/pda_scanner.png',
'icons/pda_icons/pda_signaler.png',
'icons/pda_icons/pda_status.png',
'icons/spideros_icons/sos_1.png',
'icons/spideros_icons/sos_2.png',
'icons/spideros_icons/sos_3.png',
'icons/spideros_icons/sos_4.png',
'icons/spideros_icons/sos_5.png',
'icons/spideros_icons/sos_6.png',
'icons/spideros_icons/sos_7.png',
'icons/spideros_icons/sos_8.png',
'icons/spideros_icons/sos_9.png',
'icons/spideros_icons/sos_10.png',
'icons/spideros_icons/sos_11.png',
'icons/spideros_icons/sos_12.png',
'icons/spideros_icons/sos_13.png',
'icons/spideros_icons/sos_14.png'
)