Guest User

client procs.dm for anonymous Ckey

a guest
Jan 22nd, 2017
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 17.05 KB | None | 0 0
  1. ////////////
  2. //SECURITY//
  3. ////////////
  4. #define TOPIC_SPAM_DELAY 2 //2 ticks is about 2/10ths of a second; it was 4 ticks, but that caused too many clicks to be lost due to lag
  5. #define UPLOAD_LIMIT 10485760 //Restricts client uploads to the server to 10MB //Boosted this thing. What's the worst that can happen?
  6. #define MIN_CLIENT_VERSION 510 //Just an ambiguously low version for now, I don't want to suddenly stop people playing.
  7. //I would just like the code ready should it ever need to be used.
  8. /*
  9. When somebody clicks a link in game, this Topic is called first.
  10. It does the stuff in this proc and then is redirected to the Topic() proc for the src=[0xWhatever]
  11. (if specified in the link). ie locate(hsrc).Topic()
  12.  
  13. Such links can be spoofed.
  14.  
  15. Because of this certain things MUST be considered whenever adding a Topic() for something:
  16. - Can it be fed harmful values which could cause runtimes?
  17. - Is the Topic call an admin-only thing?
  18. - If so, does it have checks to see if the person who called it (usr.client) is an admin?
  19. - Are the processes being called by Topic() particularly laggy?
  20. - If so, is there any protection against somebody spam-clicking a link?
  21. If you have any questions about this stuff feel free to ask. ~Carn
  22. */
  23. /client
  24. var/account_joined = ""
  25. var/account_age
  26.  
  27. /client/Topic(href, href_list, hsrc)
  28. //var/timestart = world.timeofday
  29. //testing("topic call for [usr] [href]")
  30. if(!usr || usr != mob) //stops us calling Topic for somebody else's client. Also helps prevent usr=null
  31. return
  32.  
  33. //Reduces spamming of links by dropping calls that happen during the delay period
  34. // if(next_allowed_topic_time > world.time)
  35. // return
  36. //next_allowed_topic_time = world.time + TOPIC_SPAM_DELAY
  37.  
  38. //search the href for script injection
  39. if( findtext(href,"<script",1,0) )
  40. world.log << "Attempted use of scripts within a topic call, by [src]"
  41. message_admins("Attempted use of scripts within a topic call, by [src]")
  42. //del(usr)
  43. return
  44.  
  45. //Admin PM
  46. if(href_list["priv_msg"])
  47. var/client/C = locate(href_list["priv_msg"])
  48. if(ismob(C)) //Old stuff can feed-in mobs instead of clients
  49. var/mob/M = C
  50. C = M.client
  51. cmd_admin_pm(C,null)
  52. return
  53.  
  54. //Wiki shortcuts
  55. if(href_list["getwiki"])
  56. var/url = href_list["getwiki"]
  57. usr << link(getVGWiki(url))
  58. return
  59.  
  60. // Global Asset cache stuff.
  61. if(href_list["asset_cache_confirm_arrival"])
  62. // to_chat(src, "ASSET JOB [href_list["asset_cache_confirm_arrival"]] ARRIVED.")
  63. var/job = text2num(href_list["asset_cache_confirm_arrival"])
  64. completed_asset_jobs += job
  65. return
  66.  
  67. if(href_list["_src_"] == "chat") // Oh god the ping hrefs.
  68. return chatOutput.Topic(href, href_list)
  69.  
  70. //Logs all hrefs
  71. if(config && config.log_hrefs && investigations[I_HREFS])
  72. var/datum/log_controller/I = investigations[I_HREFS]
  73. I.write("<small>[time_stamp()] [src] (usr:[usr])</small> || [hsrc ? "[hsrc] " : ""][copytext(sanitize(href), 1, 3000)]<br />")
  74.  
  75. switch(href_list["_src_"])
  76. if("holder")
  77. hsrc = holder
  78. if("usr")
  79. hsrc = mob
  80. if("prefs")
  81. return prefs.process_link(usr,href_list)
  82. if("vars")
  83. return view_var_Topic(href,href_list,hsrc)
  84.  
  85. switch(href_list["action"])
  86. if ("openLink")
  87. src << link(href_list["link"])
  88.  
  89. ..() //redirect to hsrc.Topic()
  90. //testing("[usr] topic call took [(world.timeofday - timestart)/10] seconds")
  91.  
  92. /client/proc/handle_spam_prevention(var/message, var/mute_type)
  93. if(config.automute_on && !holder && src.last_message == message)
  94. src.last_message_count++
  95. if(src.last_message_count >= SPAM_TRIGGER_AUTOMUTE)
  96. to_chat(src, "<span class='warning'>You have exceeded the spam filter limit for identical messages. An auto-mute was applied.</span>")
  97. cmd_admin_mute(src.mob, mute_type, 1)
  98. return 1
  99. if(src.last_message_count >= SPAM_TRIGGER_WARNING)
  100. to_chat(src, "<span class='warning'>You are nearing the spam filter limit for identical messages.</span>")
  101. return 0
  102. else
  103. last_message = message
  104. src.last_message_count = 0
  105. return 0
  106.  
  107. //This stops files larger than UPLOAD_LIMIT being sent from client to server via input(), client.Import() etc.
  108. /client/AllowUpload(filename, filelength)
  109. if(filelength > UPLOAD_LIMIT)
  110. to_chat(src, "<font color='red'>Error: AllowUpload(): File Upload too large. Upload Limit: [UPLOAD_LIMIT/1024]KiB.</font>")
  111. return 0
  112. /* //Don't need this at the moment. But it's here if it's needed later.
  113. //Helps prevent multiple files being uploaded at once. Or right after eachother.
  114. var/time_to_wait = fileaccess_timer - world.time
  115. if(time_to_wait > 0)
  116. to_chat(src, "<font color='red'>Error: AllowUpload(): Spam prevention. Please wait [round(time_to_wait/10)] seconds.</font>")
  117. return 0
  118. fileaccess_timer = world.time + FTPDELAY */
  119. return 1
  120.  
  121.  
  122. ///////////
  123. //CONNECT//
  124. ///////////
  125. /client/New(TopicData)
  126. // world.log << "creating chatOutput"
  127. chatOutput = new /datum/chatOutput(src) // Right off the bat.
  128. // world.log << "Done creating chatOutput"
  129. if(config)
  130. winset(src, null, "outputwindow.output.style=[config.world_style_config];")
  131. winset(src, null, "window1.msay_output.style=[config.world_style_config];") // it isn't possible to set two window elements in the same winset so we need to call it for each element we're assigning a stylesheet.
  132. else
  133. to_chat(src, "<span class='warning'>The stylesheet wasn't properly setup call an administrator to reload the stylesheet or relog.</span>")
  134.  
  135. TopicData = null //Prevent calls to client.Topic from connect
  136.  
  137. //Admin Authorisation
  138. holder = admin_datums[ckey]
  139. if(holder)
  140. admins += src
  141. holder.owner = src
  142.  
  143. if(connection != "seeker") //Invalid connection type.
  144. if(connection == "web")
  145. if(!holder)
  146. return null
  147. else
  148. return null
  149.  
  150. if(byond_version < MIN_CLIENT_VERSION) //Out of date client.
  151. message_admins("[key]/[ckey] has connected with an out of date client! Their version: [byond_version]. They will be kicked shortly.")
  152. alert(src,"Your BYOND client is out of date. Please make sure you have have at least version [world.byond_version] installed. Check for a beta update if necessary.", "Update Yo'Self", "OK")
  153. spawn(5 SECONDS)
  154. del(src)
  155.  
  156. if(!guests_allowed && IsGuestKey(key))
  157. alert(src,"This server doesn't allow guest accounts to play. Please go to http://www.byond.com/ and register for a key.","Guest","OK")
  158. del(src)
  159. return
  160.  
  161. // Change the way they should download resources.
  162. if(config.resource_urls)
  163. src.preload_rsc = pick(config.resource_urls)
  164. else
  165. src.preload_rsc = 1 // If config.resource_urls is not set, preload like normal.
  166.  
  167. to_chat(src, "<span class='warning'>If the title screen is black, resources are still downloading. Please be patient until the title screen appears.</span>")
  168.  
  169. clients += src
  170. directory[ckey] = src
  171.  
  172.  
  173. //preferences datum - also holds some persistant data for the client (because we may as well keep these datums to a minimum)
  174. prefs = preferences_datums[ckey]
  175. if(!prefs)
  176. prefs = new /datum/preferences(src)
  177. preferences_datums[ckey] = prefs
  178. prefs.last_ip = address //these are gonna be used for banning
  179. prefs.last_id = computer_id //these are gonna be used for banning
  180.  
  181. . = ..() //calls mob.Login()
  182. chatOutput.start()
  183.  
  184. if(custom_event_msg && custom_event_msg != "")
  185. to_chat(src, "<h1 class='alert'>Custom Event</h1>")
  186. to_chat(src, "<h2 class='alert'>A custom event is taking place. OOC Info:</h2>")
  187. to_chat(src, "<span class='alert'>[html_encode(custom_event_msg)]</span>")
  188. to_chat(src, "<br>")
  189.  
  190. if( (world.address == address || !address) && !host )
  191. host = key
  192. world.update_status()
  193.  
  194. if(holder)
  195. add_admin_verbs()
  196. admin_memo_show()
  197.  
  198. log_client_to_db()
  199.  
  200. send_resources()
  201.  
  202. var/number = rand(1, 1000)
  203. anonymous_key = "Anonymous #[number]"
  204.  
  205. if(prefs.lastchangelog != changelog_hash) //bolds the changelog button on the interface so we know there are updates.
  206. winset(src, "rpane.changelog", "background-color=#eaeaea;font-style=bold")
  207. prefs.SetChangelog(ckey,changelog_hash)
  208. to_chat(src, "<span class='info'>Changelog has changed since your last visit.</span>")
  209.  
  210. //Set map label to correct map name
  211. winset(src, "rpane.map", "text=\"[map.nameLong]\"")
  212.  
  213. // Notify scanners.
  214. INVOKE_EVENT(on_login,list(
  215. "client"=src,
  216. "admin"=(holder!=null)
  217. ))
  218.  
  219. if(!winexists(src, "asset_cache_browser")) // The client is using a custom skin, tell them.
  220. to_chat(src, "<span class='warning'>Unable to access asset cache browser, if you are using a custom skin file, please allow DS to download the updated version, if you are not, then make a bug report. This is not a critical issue but can cause issues with resource downloading, as it is impossible to know when extra resources arrived to you.</span>")
  221. //This is down here because of the browse() calls in tooltip/New()
  222. if(!tooltips)
  223. tooltips = new /datum/tooltip(src)
  224.  
  225. //////////////
  226. //DISCONNECT//
  227. //////////////
  228. /client/Del()
  229. if(holder)
  230. holder.owner = null
  231. admins -= src
  232. directory -= ckey
  233. clients -= src
  234.  
  235. return ..()
  236.  
  237. /client/proc/log_client_to_db()
  238. if(IsGuestKey(key))
  239. return
  240.  
  241. establish_db_connection()
  242.  
  243. if(!dbcon.IsConnected())
  244. return
  245. var/list/http[] = world.Export("http://www.byond.com/members/[src.key]?format=text") // Retrieve information from BYOND
  246. var/Joined = 2550-01-01
  247. if(http && http.len && ("CONTENT" in http))
  248. var/String = file2text(http["CONTENT"]) // Convert the HTML file to text
  249. var/JoinPos = findtext(String, "joined")+10 // Parse for the joined date
  250. Joined = copytext(String, JoinPos, JoinPos+10) // Get the date in the YYYY-MM-DD format
  251.  
  252. account_joined = Joined
  253.  
  254. var/sql_ckey = sanitizeSQL(ckey)
  255. var/age
  256. testing("sql_ckey = [sql_ckey]")
  257. var/DBQuery/query = dbcon.NewQuery("SELECT id, datediff(Now(),firstseen) as age, datediff(Now(),accountjoined) as age2 FROM erro_player WHERE ckey = '[sql_ckey]'")
  258. query.Execute()
  259. var/sql_id = 0
  260. while(query.NextRow())
  261. sql_id = query.item[1]
  262. player_age = text2num(query.item[2])
  263. age = text2num(query.item[3])
  264. break
  265.  
  266. var/sql_address = sanitizeSQL(address)
  267.  
  268. var/DBQuery/query_ip = dbcon.NewQuery("SELECT distinct ckey FROM erro_connection_log WHERE ip = '[sql_address]'")
  269. query_ip.Execute()
  270. related_accounts_ip = ""
  271. while(query_ip.NextRow())
  272. related_accounts_ip += "[query_ip.item[1]], "
  273.  
  274.  
  275. var/sql_computerid = sanitizeSQL(computer_id)
  276.  
  277. var/DBQuery/query_cid = dbcon.NewQuery("SELECT distinct ckey FROM erro_connection_log WHERE computerid = '[sql_computerid]'")
  278. query_cid.Execute()
  279. related_accounts_cid = ""
  280. while(query_cid.NextRow())
  281. related_accounts_cid += "[query_cid.item[1]], "
  282.  
  283. //Just the standard check to see if it's actually a number
  284. if(sql_id)
  285. if(istext(sql_id))
  286. sql_id = text2num(sql_id)
  287. if(!isnum(sql_id))
  288. return
  289.  
  290. var/admin_rank = "Player"
  291.  
  292. if(istype(holder))
  293. admin_rank = holder.rank
  294.  
  295. var/sql_admin_rank = sanitizeSQL(admin_rank)
  296.  
  297. if(sql_id)
  298. //Player already identified previously, we need to just update the 'lastseen', 'ip' and 'computer_id' variables
  299. var/DBQuery/query_update
  300. if(isnum(age))
  301. query_update = dbcon.NewQuery("UPDATE erro_player SET lastseen = Now(), ip = '[sql_address]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]' WHERE id = [sql_id]")
  302. else
  303. query_update = dbcon.NewQuery("UPDATE erro_player SET lastseen = Now(), ip = '[sql_address]', computerid = '[sql_computerid]', lastadminrank = '[sql_admin_rank]', accountjoined = '[Joined]' WHERE id = [sql_id]")
  304. query_update.Execute()
  305. if(query_update.ErrorMsg())
  306. WARNING("FINGERPRINT: [query_update.ErrorMsg()]")
  307.  
  308. else
  309. //New player!! Need to insert all the stuff
  310. var/DBQuery/query_insert = dbcon.NewQuery("INSERT INTO erro_player (id, ckey, firstseen, lastseen, ip, computerid, lastadminrank, accountjoined) VALUES (null, '[sql_ckey]', Now(), Now(), '[sql_address]', '[sql_computerid]', '[sql_admin_rank]', '[Joined]')")
  311. query_insert.Execute()
  312. if(query_insert.ErrorMsg())
  313. WARNING("FINGERPRINT: [query_insert.ErrorMsg()]")
  314.  
  315. if(!isnum(age))
  316. var/DBQuery/query_age = dbcon.NewQuery("SELECT datediff(Now(),accountjoined) as age2 FROM erro_player WHERE ckey = '[sql_ckey]'")
  317. query_age.Execute()
  318. while(query_age.NextRow())
  319. age = text2num(query_age.item[1])
  320. if(!isnum(player_age))
  321. player_age = 0
  322. if(age < 14)
  323. message_admins("[ckey(key)]/([src]) is a relatively new player, may consider watching them. AGE = [age] First seen = [player_age]")
  324. log_admin(("[ckey(key)]/([src]) is a relatively new player, may consider watching them. AGE = [age] First seen = [player_age]"))
  325. testing("[src]/[ckey(key)] logged in with age of [age]/[player_age]/[Joined]")
  326. account_age = age
  327.  
  328. // logging player access
  329. var/server_address_port = "[world.internet_address]:[world.port]"
  330. var/sql_server_address_port = sanitizeSQL(server_address_port)
  331. var/DBQuery/query_connection_log = dbcon.NewQuery("INSERT INTO `erro_connection_log`(`id`,`datetime`,`serverip`,`ckey`,`ip`,`computerid`) VALUES(null,Now(),'[sql_server_address_port]','[sql_ckey]','[sql_address]','[sql_computerid]');")
  332.  
  333. query_connection_log.Execute()
  334. if(query_connection_log.ErrorMsg())
  335. WARNING("FINGERPRINT: [query_connection_log.ErrorMsg()]")
  336.  
  337. #undef TOPIC_SPAM_DELAY
  338. #undef UPLOAD_LIMIT
  339. #undef MIN_CLIENT_VERSION
  340.  
  341. //checks if a client is afk
  342. //3000 frames = 5 minutes
  343. /client/proc/is_afk(duration=3000)
  344. if(inactivity > duration)
  345. return inactivity
  346. return 0
  347.  
  348. /client/verb/resend_resources()
  349. set name = "Resend Resources"
  350. set desc = "Re-send resources for NanoUI. May help those with NanoUI issues."
  351. set category = "OOC"
  352.  
  353. to_chat(usr, "<span class='notice'>Re-sending NanoUI resources. This may result in lag.</span>")
  354. nanomanager.send_resources(src)
  355. send_html_resources()
  356.  
  357. //send resources to the client. It's here in its own proc so we can move it around easiliy if need be
  358. /client/proc/send_resources()
  359. // preload_vox() //Causes long delays with initial start window and subsequent windows when first logged in.
  360.  
  361. getFiles(
  362. 'html/search.js',
  363. 'html/panels.css',
  364. )
  365.  
  366. // Preload the crew monitor. This needs to be done due to BYOND bug http://www.byond.com/forum/?post=1487244
  367. //The above bug report thing doesn't exist anymore so uh, whatever.
  368. spawn
  369. send_html_resources()
  370.  
  371. // Send NanoUI resources to this client
  372. spawn nanomanager.send_resources(src)
  373.  
  374.  
  375. /client/proc/send_html_resources()
  376. if(crewmonitor && minimapinit)
  377. crewmonitor.sendResources(src)
  378. if(adv_camera && minimapinit)
  379. adv_camera.sendResources(src)
  380. while(!vote || !vote.interface)
  381. sleep(1)
  382. vote.interface.sendAssets(src)
  383.  
  384. /proc/get_role_desire_str(var/rolepref)
  385. switch(rolepref & ROLEPREF_VALMASK)
  386. if(ROLEPREF_NEVER)
  387. return "Never"
  388. if(ROLEPREF_NO)
  389. return "No"
  390. if(ROLEPREF_YES)
  391. return "Yes"
  392. if(ROLEPREF_ALWAYS)
  393. return "Always"
  394. return "???"
  395.  
  396. /client/proc/desires_role(var/role_id, var/display_to_user=0)
  397. var/role_desired = prefs.roles[role_id]
  398. if(display_to_user && !(role_desired & ROLEPREF_PERSIST))
  399. if(!(role_desired & ROLEPREF_POLLED))
  400. spawn
  401. var/question={"[role_id]
  402.  
  403. Yes/No: Only affects this round
  404. Never/Always: Affects future rounds, you will not be polled again.
  405.  
  406. NOTE: You will only be polled about this role once per round. To change your choice, use Preferences > Setup Special Roles. The change will take place AFTER this recruiting period."}
  407. var/answer = alert(src,question,"Role Recruitment", "Yes","No","Never")
  408. switch(answer)
  409. if("Never")
  410. prefs.roles[role_id] = ROLEPREF_NEVER
  411. if("No")
  412. prefs.roles[role_id] = ROLEPREF_NO
  413. if("Yes")
  414. prefs.roles[role_id] = ROLEPREF_YES
  415. //if("Always")
  416. // prefs.roles[role_id] = ROLEPREF_ALWAYS
  417. //testing("Client [src] answered [answer] to [role_id] poll.")
  418. prefs.roles[role_id] |= ROLEPREF_POLLED
  419. else
  420. to_chat(src, "<span style='recruit'>The game is currently looking for [role_id] candidates. Your current answer is <a href='?src=\ref[prefs]&preference=set_role&role_id=[role_id]'>[get_role_desire_str(role_desired)]</a>.</span>")
  421. return role_desired & ROLEPREF_ENABLE
  422.  
  423. /client/proc/colour_transition(var/list/colour_to = default_colour_matrix,var/time = 10) // call this with no parametres to reset to default.
  424. if(!color)
  425. color = default_colour_matrix
  426. if(!(colour_to.len))
  427. colour_to = default_colour_matrix
  428. animate(src, color=colour_to, time=time, easing=SINE_EASING)
  429.  
  430. /client/proc/changeView(var/newView)
  431. if(!newView)
  432. view = world.view
  433. else
  434. view = newView
  435.  
  436. if(mob && ishuman(mob))
  437. var/mob/living/carbon/human/H = mob
  438. var/obj/item/clothing/under/U = H.get_item_by_slot(slot_w_uniform)
  439. if(istype(U))
  440. for(var/obj/item/clothing/accessory/holomap_chip/HC in U.accessories)
  441. HC.update_holomap()
  442.  
  443. /client/verb/SwapSides()
  444. set name = "swapsides"
  445. set hidden = 1
  446. var/newsplit = 100 - text2num(winget(usr, "mainwindow.mainvsplit", "splitter"))
  447. if(winget(usr, "mainwindow.mainvsplit", "right") == "rpane")
  448. winset(usr, "mainwindow.mainvsplit", "right=mapwindow;left=rpane;splitter=[newsplit]")
  449. else
  450. winset(usr, "mainwindow.mainvsplit", "right=rpane;left=mapwindow;splitter=[newsplit]")
Add Comment
Please, Sign In to add comment