mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 09:42:29 +00:00
[MIRROR] Uses regex datums and macros for text-manipulation (#7805)
* Uses regex datums and macros for text-manipulation (#61042) * Uses regex datums and macros for text-manipulation * a Co-authored-by: Rohesie <rohesie@gmail.com> Co-authored-by: Gandalf <jzo123@hotmail.com>
This commit is contained in:
@@ -3,3 +3,9 @@
|
|||||||
|
|
||||||
/// Macro from Lummox used to get height from a MeasureText proc
|
/// Macro from Lummox used to get height from a MeasureText proc
|
||||||
#define WXH_TO_HEIGHT(x) text2num(copytext(x, findtextEx(x, "x") + 1))
|
#define WXH_TO_HEIGHT(x) text2num(copytext(x, findtextEx(x, "x") + 1))
|
||||||
|
|
||||||
|
/// Removes characters incompatible with file names.
|
||||||
|
#define SANITIZE_FILENAME(text) (GLOB.filename_forbidden_chars.Replace(text, ""))
|
||||||
|
|
||||||
|
/// Simply removes the < and > characters, and limits the length of the message.
|
||||||
|
#define STRIP_HTML_SIMPLE(text, limit) (GLOB.angular_brackets.Replace(copytext(text, 1, limit), ""))
|
||||||
|
|||||||
@@ -1082,7 +1082,7 @@ GLOBAL_LIST_INIT(freon_color_matrix, list("#2E5E69", "#60A2A8", "#A1AFB1", rgb(0
|
|||||||
|
|
||||||
if (!isicon(I))
|
if (!isicon(I))
|
||||||
if (isfile(thing)) //special snowflake
|
if (isfile(thing)) //special snowflake
|
||||||
var/name = sanitize_filename("[generate_asset_name(thing)].png")
|
var/name = SANITIZE_FILENAME("[generate_asset_name(thing)].png")
|
||||||
if (!SSassets.cache[name])
|
if (!SSassets.cache[name])
|
||||||
SSassets.transport.register_asset(name, thing)
|
SSassets.transport.register_asset(name, thing)
|
||||||
for (var/thing2 in targets)
|
for (var/thing2 in targets)
|
||||||
|
|||||||
@@ -20,28 +20,6 @@
|
|||||||
* Text sanitization
|
* 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 + length(char))
|
|
||||||
index = findtext(t, char, index + length(char))
|
|
||||||
return t
|
|
||||||
|
|
||||||
/proc/sanitize_filename(t)
|
|
||||||
return sanitize_simple(t, list("\n"="", "\t"="", "/"="", "\\"="", "?"="", "%"="", "*"="", ":"="", "|"="", "\""="", "<"="", ">"=""))
|
|
||||||
|
|
||||||
///returns nothing with an alert instead of the message if it contains something in the ic filter, and sanitizes normally if the name is fine. It returns nothing so it backs out of the input the same way as if you had entered nothing.
|
///returns nothing with an alert instead of the message if it contains something in the ic filter, and sanitizes normally if the name is fine. It returns nothing so it backs out of the input the same way as if you had entered nothing.
|
||||||
/proc/sanitize_name(t,allow_numbers=FALSE)
|
/proc/sanitize_name(t,allow_numbers=FALSE)
|
||||||
@@ -54,19 +32,22 @@
|
|||||||
return ""
|
return ""
|
||||||
return sanitize(r)
|
return sanitize(r)
|
||||||
|
|
||||||
//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
|
/// Runs byond's html encoding sanitization proc, after replacing new-lines and tabs for the # character.
|
||||||
//I believe strip_html_simple() is required to run first to prevent '<' from displaying as '<' after sanitize() calls byond's html_encode()
|
/proc/sanitize(text)
|
||||||
/proc/strip_html(t,limit=MAX_MESSAGE_LEN)
|
var/static/regex/regex = regex(@"[\n\t]", "g")
|
||||||
return copytext((sanitize(strip_html_simple(t))),1,limit)
|
return html_encode(regex.Replace(text, "#"))
|
||||||
|
|
||||||
|
|
||||||
|
/// Runs STRIP_HTML_SIMPLE and sanitize.
|
||||||
|
/proc/strip_html(text, limit = MAX_MESSAGE_LEN)
|
||||||
|
return sanitize(STRIP_HTML_SIMPLE(text, limit))
|
||||||
|
|
||||||
|
|
||||||
|
/// Runs STRIP_HTML_SIMPLE and byond's sanitization proc.
|
||||||
|
/proc/adminscrub(text, limit = MAX_MESSAGE_LEN)
|
||||||
|
return html_encode(STRIP_HTML_SIMPLE(text, 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)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform a whitespace cleanup on the text, similar to what HTML renderers do
|
* Perform a whitespace cleanup on the text, similar to what HTML renderers do
|
||||||
@@ -91,31 +72,34 @@
|
|||||||
|
|
||||||
return t
|
return t
|
||||||
|
|
||||||
//Returns null if there is any bad text in the string
|
|
||||||
|
/**
|
||||||
|
* Returns the text if properly formatted, or null else.
|
||||||
|
*
|
||||||
|
* Things considered improper:
|
||||||
|
* * Larger than max_length.
|
||||||
|
* * Presence of non-ASCII characters if asci_only is set to TRUE.
|
||||||
|
* * Only whitespaces, tabs and/or line breaks in the text.
|
||||||
|
* * Presence of the <, >, \ and / characters.
|
||||||
|
* * Presence of ASCII special control characters (horizontal tab and new line not included).
|
||||||
|
* */
|
||||||
/proc/reject_bad_text(text, max_length = 512, ascii_only = TRUE)
|
/proc/reject_bad_text(text, max_length = 512, ascii_only = TRUE)
|
||||||
var/char_count = 0
|
if(ascii_only)
|
||||||
var/non_whitespace = FALSE
|
if(length(text) > max_length)
|
||||||
var/lenbytes = length(text)
|
return null
|
||||||
var/char = ""
|
var/static/regex/non_ascii = regex(@"[^\x20-\x7E\t\n]")
|
||||||
for(var/i = 1, i <= lenbytes, i += length(char))
|
if(non_ascii.Find(text))
|
||||||
char = text[i]
|
return null
|
||||||
char_count++
|
else if(length_char(text) > max_length)
|
||||||
if(char_count > max_length)
|
return null
|
||||||
return
|
var/static/regex/non_whitespace = regex(@"\S")
|
||||||
switch(text2ascii(char))
|
if(!non_whitespace.Find(text))
|
||||||
if(62, 60, 92, 47) // <, >, \, /
|
return null
|
||||||
return
|
var/static/regex/bad_chars = regex(@"[\\<>/\x00-\x08\x11-\x1F]")
|
||||||
if(0 to 31)
|
if(bad_chars.Find(text))
|
||||||
return
|
return null
|
||||||
if(32)
|
return text
|
||||||
continue
|
|
||||||
if(127 to INFINITY)
|
|
||||||
if(ascii_only)
|
|
||||||
return
|
|
||||||
else
|
|
||||||
non_whitespace = TRUE
|
|
||||||
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
|
/// Used to get a properly sanitized input, of max_length
|
||||||
/// no_trim is self explanatory but it prevents the input from being trimed if you intend to parse newlines or whitespace.
|
/// no_trim is self explanatory but it prevents the input from being trimed if you intend to parse newlines or whitespace.
|
||||||
|
|||||||
@@ -9,3 +9,10 @@ GLOBAL_DATUM_INIT(is_color, /regex, regex("^#\[0-9a-fA-F]{6}$"))
|
|||||||
|
|
||||||
//finds text strings recognized as links on discord. Mainly used to stop embedding.
|
//finds text strings recognized as links on discord. Mainly used to stop embedding.
|
||||||
GLOBAL_DATUM_INIT(has_discord_embeddable_links, /regex, regex("(https?://\[^\\s|<\]{2,})"))
|
GLOBAL_DATUM_INIT(has_discord_embeddable_links, /regex, regex("(https?://\[^\\s|<\]{2,})"))
|
||||||
|
|
||||||
|
//All < and > characters
|
||||||
|
GLOBAL_DATUM_INIT(angular_brackets, /regex, regex(@"[<>]", "g"))
|
||||||
|
|
||||||
|
//All characters forbidden by filenames: ", \, \n, \t, /, ?, %, *, :, |, <, >
|
||||||
|
GLOBAL_DATUM_INIT(filename_forbidden_chars, /regex, regex(@{""|[\\\n\t/?%*:|<>]"}, "g"))
|
||||||
|
// had to use the OR operator for quotes instead of putting them in the character class because it breaks the syntax highlighting otherwise.
|
||||||
|
|||||||
@@ -376,7 +376,7 @@
|
|||||||
/obj/structure/sign/painting/proc/save_persistent()
|
/obj/structure/sign/painting/proc/save_persistent()
|
||||||
if(!persistence_id || !current_canvas || current_canvas.no_save)
|
if(!persistence_id || !current_canvas || current_canvas.no_save)
|
||||||
return
|
return
|
||||||
if(sanitize_filename(persistence_id) != persistence_id)
|
if(SANITIZE_FILENAME(persistence_id) != persistence_id)
|
||||||
stack_trace("Invalid persistence_id - [persistence_id]")
|
stack_trace("Invalid persistence_id - [persistence_id]")
|
||||||
return
|
return
|
||||||
if(!current_canvas.painting_name)
|
if(!current_canvas.painting_name)
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
|||||||
var/item_filename
|
var/item_filename
|
||||||
|
|
||||||
/datum/asset/changelog_item/New(date)
|
/datum/asset/changelog_item/New(date)
|
||||||
item_filename = sanitize_filename("[date].yml")
|
item_filename = SANITIZE_FILENAME("[date].yml")
|
||||||
SSassets.transport.register_asset(item_filename, file("html/changelogs/archive/" + item_filename))
|
SSassets.transport.register_asset(item_filename, file("html/changelogs/archive/" + item_filename))
|
||||||
|
|
||||||
/datum/asset/changelog_item/send(client)
|
/datum/asset/changelog_item/send(client)
|
||||||
@@ -301,7 +301,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
|||||||
continue
|
continue
|
||||||
asset = fcopy_rsc(asset) //dedupe
|
asset = fcopy_rsc(asset) //dedupe
|
||||||
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]." : ""
|
var/prefix2 = (directions.len > 1) ? "[dir2text(direction)]." : ""
|
||||||
var/asset_name = sanitize_filename("[prefix].[prefix2][icon_state_name].png")
|
var/asset_name = SANITIZE_FILENAME("[prefix].[prefix2][icon_state_name].png")
|
||||||
if (generic_icon_names)
|
if (generic_icon_names)
|
||||||
asset_name = "[generate_asset_name(asset)].png"
|
asset_name = "[generate_asset_name(asset)].png"
|
||||||
|
|
||||||
|
|||||||
@@ -355,12 +355,12 @@
|
|||||||
if("edit_admin_note")
|
if("edit_admin_note")
|
||||||
var/msg = input(usr, "Set your note to admins!", "Note to admins", note_to_admins) as message|null
|
var/msg = input(usr, "Set your note to admins!", "Note to admins", note_to_admins) as message|null
|
||||||
if(msg)
|
if(msg)
|
||||||
note_to_admins = strip_html_simple(msg, MAX_FLAVOR_LEN, TRUE)
|
note_to_admins = strip_html(msg, MAX_FLAVOR_LEN, TRUE)
|
||||||
log_action("NOTE: [note_to_admins]", FALSE)
|
log_action("NOTE: [note_to_admins]", FALSE)
|
||||||
if("set_narrative")
|
if("set_narrative")
|
||||||
var/msg = input(usr, "Set your narrative!", "Narrative", narrative) as message|null
|
var/msg = input(usr, "Set your narrative!", "Narrative", narrative) as message|null
|
||||||
if(msg)
|
if(msg)
|
||||||
narrative = strip_html_simple(msg, MAX_FLAVOR_LEN, TRUE)
|
narrative = strip_html(msg, MAX_FLAVOR_LEN, TRUE)
|
||||||
log_action("NARRATIVE - change: [narrative]")
|
log_action("NARRATIVE - change: [narrative]")
|
||||||
un_submit()
|
un_submit()
|
||||||
if("remove_objective")
|
if("remove_objective")
|
||||||
@@ -379,13 +379,13 @@
|
|||||||
if(msg)
|
if(msg)
|
||||||
if(length(objectives) < index)
|
if(length(objectives) < index)
|
||||||
return
|
return
|
||||||
objectives[index] = strip_html_simple(msg, MAX_FLAVOR_LEN, TRUE)
|
objectives[index] = strip_html(msg, MAX_FLAVOR_LEN, TRUE)
|
||||||
un_submit()
|
un_submit()
|
||||||
log_action("OBJ - edit: [old_obj] TO-> [objectives[index]]")
|
log_action("OBJ - edit: [old_obj] TO-> [objectives[index]]")
|
||||||
if("add_objective")
|
if("add_objective")
|
||||||
var/msg = input(usr, "Add new objective:", "Objectives", "") as message|null
|
var/msg = input(usr, "Add new objective:", "Objectives", "") as message|null
|
||||||
if(msg)
|
if(msg)
|
||||||
var/new_obj = strip_html_simple(msg, MAX_FLAVOR_LEN, TRUE)
|
var/new_obj = strip_html(msg, MAX_FLAVOR_LEN, TRUE)
|
||||||
objectives += new_obj
|
objectives += new_obj
|
||||||
log_action("OBJ - add: [new_obj]")
|
log_action("OBJ - add: [new_obj]")
|
||||||
un_submit()
|
un_submit()
|
||||||
|
|||||||
@@ -2154,42 +2154,42 @@ GLOBAL_LIST_INIT(food, list(
|
|||||||
if("flavor_text")
|
if("flavor_text")
|
||||||
var/msg = input(usr, "Set the flavor text in your 'examine' verb. This is for describing what people can tell by looking at your character.", "Flavor Text", features["flavor_text"]) as message|null //Skyrat edit, removed stripped_multiline_input()
|
var/msg = input(usr, "Set the flavor text in your 'examine' verb. This is for describing what people can tell by looking at your character.", "Flavor Text", features["flavor_text"]) as message|null //Skyrat edit, removed stripped_multiline_input()
|
||||||
if(!isnull(msg))
|
if(!isnull(msg))
|
||||||
features["flavor_text"] = strip_html_simple(msg, MAX_FLAVOR_LEN, TRUE)
|
features["flavor_text"] = strip_html(msg, MAX_FLAVOR_LEN, TRUE)
|
||||||
|
|
||||||
if("silicon_flavor_text")
|
if("silicon_flavor_text")
|
||||||
var/msg = input(usr, "Set the flavor text in your 'examine' verb. This is for describing what people can tell by looking at your character.", "Silicon Flavor Text", features["silicon_flavor_text"]) as message|null
|
var/msg = input(usr, "Set the flavor text in your 'examine' verb. This is for describing what people can tell by looking at your character.", "Silicon Flavor Text", features["silicon_flavor_text"]) as message|null
|
||||||
if(!isnull(msg))
|
if(!isnull(msg))
|
||||||
features["silicon_flavor_text"] = strip_html_simple(msg, MAX_FLAVOR_LEN, TRUE)
|
features["silicon_flavor_text"] = strip_html(msg, MAX_FLAVOR_LEN, TRUE)
|
||||||
|
|
||||||
if("ooc_prefs")
|
if("ooc_prefs")
|
||||||
var/msg = input(usr, "Set your OOC preferences.", "OOC Prefs", ooc_prefs) as message|null
|
var/msg = input(usr, "Set your OOC preferences.", "OOC Prefs", ooc_prefs) as message|null
|
||||||
if(!isnull(msg))
|
if(!isnull(msg))
|
||||||
ooc_prefs = strip_html_simple(msg, MAX_FLAVOR_LEN, TRUE)
|
ooc_prefs = strip_html(msg, MAX_FLAVOR_LEN, TRUE)
|
||||||
|
|
||||||
if("general_record")
|
if("general_record")
|
||||||
var/msg = input(usr, "Set your general record. This is more or less public information, available from security, medical and command consoles", "General Record", general_record) as message|null
|
var/msg = input(usr, "Set your general record. This is more or less public information, available from security, medical and command consoles", "General Record", general_record) as message|null
|
||||||
if(!isnull(msg))
|
if(!isnull(msg))
|
||||||
general_record = strip_html_simple(msg, MAX_FLAVOR_LEN, TRUE)
|
general_record = strip_html(msg, MAX_FLAVOR_LEN, TRUE)
|
||||||
|
|
||||||
if("medical_record")
|
if("medical_record")
|
||||||
var/msg = input(usr, "Set your medical record. ", "Medical Record", medical_record) as message|null
|
var/msg = input(usr, "Set your medical record. ", "Medical Record", medical_record) as message|null
|
||||||
if(!isnull(msg))
|
if(!isnull(msg))
|
||||||
medical_record = strip_html_simple(msg, MAX_FLAVOR_LEN, TRUE)
|
medical_record = strip_html(msg, MAX_FLAVOR_LEN, TRUE)
|
||||||
|
|
||||||
if("security_record")
|
if("security_record")
|
||||||
var/msg = input(usr, "Set your security record. ", "Medical Record", security_record) as message|null
|
var/msg = input(usr, "Set your security record. ", "Medical Record", security_record) as message|null
|
||||||
if(!isnull(msg))
|
if(!isnull(msg))
|
||||||
security_record = strip_html_simple(msg, MAX_FLAVOR_LEN, TRUE)
|
security_record = strip_html(msg, MAX_FLAVOR_LEN, TRUE)
|
||||||
|
|
||||||
if("background_info")
|
if("background_info")
|
||||||
var/msg = input(usr, "Set your background information. (Where you come from, which culture were you raised in and why you are working here etc.)", "Background Info", background_info) as message|null
|
var/msg = input(usr, "Set your background information. (Where you come from, which culture were you raised in and why you are working here etc.)", "Background Info", background_info) as message|null
|
||||||
if(!isnull(msg))
|
if(!isnull(msg))
|
||||||
background_info = strip_html_simple(msg, MAX_FLAVOR_LEN, TRUE)
|
background_info = strip_html(msg, MAX_FLAVOR_LEN, TRUE)
|
||||||
|
|
||||||
if("exploitable_info")
|
if("exploitable_info")
|
||||||
var/msg = input(usr, "Set your exploitable information. This is sensitive informations that antagonists may get to see, recommended for better roleplay experience", "Exploitable Info", exploitable_info) as message|null
|
var/msg = input(usr, "Set your exploitable information. This is sensitive informations that antagonists may get to see, recommended for better roleplay experience", "Exploitable Info", exploitable_info) as message|null
|
||||||
if(!isnull(msg))
|
if(!isnull(msg))
|
||||||
exploitable_info = strip_html_simple(msg, MAX_FLAVOR_LEN, TRUE)
|
exploitable_info = strip_html(msg, MAX_FLAVOR_LEN, TRUE)
|
||||||
|
|
||||||
if("uses_skintones")
|
if("uses_skintones")
|
||||||
needs_update = TRUE
|
needs_update = TRUE
|
||||||
|
|||||||
@@ -12,5 +12,5 @@
|
|||||||
if(msg == "")
|
if(msg == "")
|
||||||
temporary_flavor_text = null
|
temporary_flavor_text = null
|
||||||
else
|
else
|
||||||
temporary_flavor_text = strip_html_simple(msg, MAX_FLAVOR_LEN, TRUE)
|
temporary_flavor_text = strip_html(msg, MAX_FLAVOR_LEN, TRUE)
|
||||||
return
|
return
|
||||||
|
|||||||
Reference in New Issue
Block a user