/* * Holds procs designed to help with filtering text * Contains groups: * SQL sanitization/formating * Text sanitization * Text searches * Text modification * Misc */ /* * SQL sanitization */ // Run all strings to be used in an SQL query through this proc first to properly escape out injection attempts. /proc/sanitizeSQL(t as text) var/sqltext = dbcon.Quote(t); return copytext(sqltext, 2, lentext(sqltext));//Quote() adds quotes around input, we already do that /proc/format_table_name(table as text) return sqlfdbktableprefix + table /* * Text sanitization */ //Simply removes < and > and limits the length of the message /proc/strip_html_simple(t,limit=MAX_MESSAGE_LEN) var/list/strip_chars = list("<",">") t = copytext(t,1,limit) for(var/char in strip_chars) var/index = findtext(t, char) while(index) t = copytext(t, 1, index) + copytext(t, index+1) index = findtext(t, char) return t //Removes a few problematic characters /proc/sanitize_simple(t,list/repl_chars = list("\n"="#","\t"="#")) for(var/char in repl_chars) var/index = findtext(t, char) while(index) t = copytext(t, 1, index) + repl_chars[char] + copytext(t, index+1) index = findtext(t, char, index+1) return t //Runs byond's sanitization proc along-side sanitize_simple /proc/sanitize(t,list/repl_chars = null) return html_encode(sanitize_simple(t,repl_chars)) //Runs sanitize and strip_html_simple //I believe strip_html_simple() is required to run first to prevent '<' from displaying as '<' after sanitize() calls byond's html_encode() /proc/strip_html(t,limit=MAX_MESSAGE_LEN) return copytext((sanitize(strip_html_simple(t))),1,limit) //Runs byond's sanitization proc along-side strip_html_simple //I believe strip_html_simple() is required to run first to prevent '<' from displaying as '<' that html_encode() would cause /proc/adminscrub(t,limit=MAX_MESSAGE_LEN) return copytext((html_encode(strip_html_simple(t))),1,limit) //Returns null if there is any bad text in the string /proc/reject_bad_text(text, max_length=512) if(length(text) > max_length) return //message too long var/non_whitespace = 0 for(var/i=1, i<=length(text), i++) switch(text2ascii(text,i)) if(62,60,92,47) return //rejects the text if it contains these bad characters: <, >, \ or / if(127 to 255) return //rejects weird letters like � if(0 to 31) return //more weird stuff if(32) continue //whitespace else non_whitespace = 1 if(non_whitespace) return text //only accepts the text if it has some non-spaces // Used to get a properly sanitized input, of max_length /proc/stripped_input(mob/user, message = "", title = "", default = "", max_length=MAX_MESSAGE_LEN) var/name = input(user, message, title, default) as text|null return trim(html_encode(name), max_length) //trim is "outside" because html_encode can expand single symbols into multiple symbols (such as turning < into <) // Used to get a properly sanitized multiline input, of max_length /proc/stripped_multiline_input(mob/user, message = "", title = "", default = "", max_length=MAX_MESSAGE_LEN) var/name = input(user, message, title, default) as message|null return html_encode(trim(name, max_length)) //Filters out undesirable characters from names /proc/reject_bad_name(t_in, allow_numbers=0, max_length=MAX_NAME_LEN) if(!t_in || length(t_in) > max_length) return //Rejects the input if it is null or if it is longer then the max length allowed var/number_of_alphanumeric = 0 var/last_char_group = 0 var/t_out = "" for(var/i=1, i<=length(t_in), i++) var/ascii_char = text2ascii(t_in,i) switch(ascii_char) // A .. Z if(65 to 90) //Uppercase Letters t_out += ascii2text(ascii_char) number_of_alphanumeric++ last_char_group = 4 // a .. z if(97 to 122) //Lowercase Letters if(last_char_group<2) t_out += ascii2text(ascii_char-32) //Force uppercase first character else t_out += ascii2text(ascii_char) number_of_alphanumeric++ last_char_group = 4 // 0 .. 9 if(48 to 57) //Numbers if(!last_char_group) continue //suppress at start of string if(!allow_numbers) continue t_out += ascii2text(ascii_char) number_of_alphanumeric++ last_char_group = 3 // ' - . if(39,45,46) //Common name punctuation if(!last_char_group) continue t_out += ascii2text(ascii_char) last_char_group = 2 // ~ | @ : # $ % & * + if(126,124,64,58,35,36,37,38,42,43) //Other symbols that we'll allow (mainly for AI) if(!last_char_group) continue //suppress at start of string if(!allow_numbers) continue t_out += ascii2text(ascii_char) last_char_group = 2 //Space if(32) if(last_char_group <= 1) continue //suppress double-spaces and spaces at start of string t_out += ascii2text(ascii_char) last_char_group = 1 else return if(number_of_alphanumeric < 2) return //protects against tiny names like "A" and also names like "' ' ' ' ' ' ' '" if(last_char_group == 1) t_out = copytext(t_out,1,length(t_out)) //removes the last character (in this case a space) for(var/bad_name in list("space","floor","wall","r-wall","monkey","unknown","inactive ai")) //prevents these common metagamey names if(cmptext(t_out,bad_name)) return //(not case sensitive) return t_out //html_encode helper proc that returns the smallest non null of two numbers //or 0 if they're both null (needed because of findtext returning 0 when a value is not present) /proc/non_zero_min(a, b) if(!a) return b if(!b) return a return (a < b ? a : b) /* * Text searches */ //Checks the beginning of a string for a specified sub-string //Returns the position of the substring or 0 if it was not found /proc/dd_hasprefix(text, prefix) var/start = 1 var/end = length(prefix) + 1 return findtext(text, prefix, start, end) //Checks the beginning of a string for a specified sub-string. This proc is case sensitive //Returns the position of the substring or 0 if it was not found /proc/dd_hasprefix_case(text, prefix) var/start = 1 var/end = length(prefix) + 1 return findtextEx(text, prefix, start, end) //Checks the end of a string for a specified substring. //Returns the position of the substring or 0 if it was not found /proc/dd_hassuffix(text, suffix) var/start = length(text) - length(suffix) if(start) return findtext(text, suffix, start, null) return //Checks the end of a string for a specified substring. This proc is case sensitive //Returns the position of the substring or 0 if it was not found /proc/dd_hassuffix_case(text, suffix) var/start = length(text) - length(suffix) if(start) return findtextEx(text, suffix, start, null) //Adds 'u' number of zeros ahead of the text 't' /proc/add_zero(t, u) while (length(t) < u) t = "0[t]" return t //Adds 'u' number of spaces ahead of the text 't' /proc/add_lspace(t, u) while(length(t) < u) t = " [t]" return t //Adds 'u' number of spaces behind the text 't' /proc/add_tspace(t, u) while(length(t) < u) t = "[t] " return t //Returns a string with reserved characters and spaces before the first letter removed /proc/trim_left(text) for (var/i = 1 to length(text)) if (text2ascii(text, i) > 32) return copytext(text, i) return "" //Returns a string with reserved characters and spaces after the last letter removed /proc/trim_right(text) for (var/i = length(text), i > 0, i--) if (text2ascii(text, i) > 32) return copytext(text, 1, i + 1) return "" //Returns a string with reserved characters and spaces before the first word and after the last word removed. /proc/trim(text, max_length) if(max_length) text = copytext(text, 1, max_length) return trim_left(trim_right(text)) //Returns a string with the first element of the string capitalized. /proc/capitalize(t as text) return uppertext(copytext(t, 1, 2)) + copytext(t, 2) //Centers text by adding spaces to either side of the string. /proc/dd_centertext(message, length) var/new_message = message var/size = length(message) var/delta = length - size if(size == length) return new_message if(size > length) return copytext(new_message, 1, length + 1) if(delta == 1) return new_message + " " if(delta % 2) new_message = " " + new_message delta-- var/spaces = add_lspace("",delta/2-1) return spaces + new_message + spaces //Limits the length of the text. Note: MAX_MESSAGE_LEN and MAX_NAME_LEN are widely used for this purpose /proc/dd_limittext(message, length) var/size = length(message) if(size <= length) return message return copytext(message, 1, length + 1) /proc/stringmerge(text,compare,replace = "*") //This proc fills in all spaces with the "replace" var (* by default) with whatever //is in the other string at the same spot (assuming it is not a replace char). //This is used for fingerprints var/newtext = text if(lentext(text) != lentext(compare)) return 0 for(var/i = 1, i < lentext(text), i++) var/a = copytext(text,i,i+1) var/b = copytext(compare,i,i+1) //if it isn't both the same letter, or if they are both the replacement character //(no way to know what it was supposed to be) if(a != b) if(a == replace) //if A is the replacement char newtext = copytext(newtext,1,i) + b + copytext(newtext, i+1) else if(b == replace) //if B is the replacement char newtext = copytext(newtext,1,i) + a + copytext(newtext, i+1) else //The lists disagree, Uh-oh! return 0 return newtext /proc/stringpercent(text,character = "*") //This proc returns the number of chars of the string that is the character //This is used for detective work to determine fingerprint completion. if(!text || !character) return 0 var/count = 0 for(var/i = 1, i <= lentext(text), i++) var/a = copytext(text,i,i+1) if(a == character) count++ return count /proc/reverse_text(text = "") var/new_text = "" for(var/i = length(text); i > 0; i--) new_text += copytext(text, i, i+1) return new_text var/list/zero_character_only = list("0") var/list/hex_characters = list("0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f") var/list/alphabet = list("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z") var/list/binary = list("0","1") /proc/random_string(length, list/characters) . = "" for(var/i=1, i<=length, i++) . += pick(characters) /proc/repeat_string(times, string="") . = "" for(var/i=1, i<=times, i++) . += string /proc/random_short_color() return random_string(3, hex_characters) /proc/random_color() return random_string(6, hex_characters) /proc/add_zero2(t, u) var/temp1 while (length(t) < u) t = "0[t]" temp1 = t if (length(t) > u) temp1 = copytext(t,2,u+1) return temp1 //merges non-null characters (3rd argument) from "from" into "into". Returns result //e.g. into = "Hello World" // from = "Seeya______" // returns"Seeya World" //The returned text is always the same length as into //This was coded to handle DNA gene-splicing. /proc/merge_text(into, from, null_char="_") . = "" if(!istext(into)) into = "" if(!istext(from)) from = "" var/null_ascii = istext(null_char) ? text2ascii(null_char,1) : null_char var/previous = 0 var/start = 1 var/end = length(into) + 1 for(var/i=1, i") t = replacetext(t, "\[/center\]", "") t = replacetext(t, "\[br\]", "
") t = replacetext(t, "\[b\]", "") t = replacetext(t, "\[/b\]", "") t = replacetext(t, "\[i\]", "") t = replacetext(t, "\[/i\]", "") t = replacetext(t, "\[u\]", "") t = replacetext(t, "\[/u\]", "") t = replacetext(t, "\[large\]", "") t = replacetext(t, "\[/large\]", "") if(user) t = replacetext(t, "\[sign\]", "[user.real_name]") else t = replacetext(t, "\[sign\]", "") t = replacetext(t, "\[field\]", "") t = replacetext(t, "\[*\]", "
  • ") t = replacetext(t, "\[hr\]", "
    ") t = replacetext(t, "\[small\]", "") t = replacetext(t, "\[/small\]", "") t = replacetext(t, "\[list\]", "") return t /proc/char_split(t) . = list() for(var/x in 1 to length(t)) . += copytext(t,x,x+1) var/list/rot13_lookup = list() /proc/generate_rot13_lookup() var/letters = alphabet.Copy() for(var/c in alphabet) letters += uppertext(c) for(var/char in letters) var/ascii_char = text2ascii(char, 1) var/index switch(ascii_char) // A - Z if(65 to 90) index = 65 // a - z if(97 to 122) index = 97 var/d = ascii_char - index d += 13 if(d >= 26) d -= 26 ascii_char = index + d var/translated_char = ascii2text(ascii_char) rot13_lookup[char] = translated_char /proc/rot13(t_in) if(!rot13_lookup.len) generate_rot13_lookup() var/t_out = "" for(var/i in 1 to length(t_in)) var/char = copytext(t_in, i, i + 1) if(char in rot13_lookup) t_out += rot13_lookup[char] else t_out += char return t_out //Used in preferences' SetFlavorText and human's set_flavor verb //Previews a string of len or less length /proc/copytext_preserve_html(var/text, var/first, var/last) return html_encode(copytext(html_decode(text), first, last)) proc/TextPreview(var/string,var/len=40) if(lentext(string) <= len) if(!lentext(string)) return "\[...\]" else return string else return "[copytext(string, 1, 37)]..."