Class RemoteText
Builds UnityEngine.UIElements.Labels for text that came from somewhere this client does not control, and sanitises such text before it reaches a log line.
public static class RemoteText
- Inheritance
-
RemoteText
- Inherited Members
Remarks
The thing this exists to prevent. A UI Toolkit UnityEngine.UIElements.TextElement — and
therefore UnityEngine.UIElements.Label and UnityEngine.UIElements.Button, both of which derive from it —
has UnityEngine.UIElements.TextElement.enableRichText defaulting to true. Assigning
label.text does not "just show the string": the text is parsed for Unity rich-text
markup, so a news feed or an update server that returns
<color=#00FF00>Verified by FishMMO</color> gets exactly that, rendered
as trusted-looking launcher chrome. <size=2000> is the same primitive
pointed at the layout instead: one tag makes the pane unusable.
The launcher's news renderer additionally runs every text node through
WebUtility.HtmlDecode, which turns an *escaped* <color=...>
back into a live tag — so escaping upstream is not a defence, and a feed that looks inert
as HTML is not inert as Unity markup.
Belt and braces, deliberately. CreateLabel(string, string, bool, int) turns rich text off, which
is the actual fix; Sanitize(string, int, bool) strips the control characters and caps the
length, which is what protects the log file and anything that later renders the same
string somewhere this helper did not build. Either alone would be enough today. Both,
because "today" is the part that changes: a future panel that builds its own Label from
the same string is a one-line regression, and one that logs it is not covered by
enableRichText at all.
Nothing here parses or rewrites markup. There is no tag allowlist and no attempt to "clean" tags, because a sanitiser that rewrites markup is a parser, and a parser is something to be bypassed. Remote text is rendered as literal characters or not at all.
Fields
MaxLength
Longest remote string rendered or logged verbatim.
public const int MaxLength = 2048
Field Value
Remarks
Generous for a status line or an error detail; nowhere near enough to be a layout or a log-file problem. The news body is bounded separately and much higher — this cap is for the short server-controlled strings (versions, error details) that reach the status label.
Methods
CreateLabel(string, string, bool, int)
Creates a UnityEngine.UIElements.Label that renders text literally.
public static Label CreateLabel(string text, string ussClass = null, bool allowNewlines = false, int maxLength = 2048)
Parameters
textstringUntrusted text. Null is treated as empty.
ussClassstringOptional USS class to add.
allowNewlinesboolTrue for body copy that is meant to wrap across paragraphs; false (the default) for single-line chrome such as a status line, where an embedded newline is only ever a way to push real text out of view.
maxLengthintLength cap; defaults to MaxLength.
Returns
- Label
A label with rich text disabled and the text sanitised.
Sanitize(string, int, bool)
Returns text with control characters removed and its length
capped, safe to put in a log line or a single-line UI element.
public static string Sanitize(string text, int maxLength = 2048, bool allowNewlines = false)
Parameters
textstringUntrusted text. Null returns an empty string.
maxLengthintLength cap; defaults to MaxLength.
allowNewlinesboolTrue to preserve line breaks. Only for text rendered as a wrapping block; never for a log line, where a newline is the log-forging primitive, and never for single-line chrome. CR and CRLF are normalised to a single LF either way so one line break is one line break regardless of who authored the string.
Returns
Remarks
Removes CR and LF (CWE-117: a server-controlled error string containing a newline forges whole log lines, which is how a real failure gets buried under fabricated "success" entries), the remaining C0/C1 control characters, and the bidirectional override codepoints — U+202A-U+202E and U+2066-U+2069 — which reorder rendered text and can make a hostile version string display as a benign one.
Tabs are kept: they are ordinary layout in a status message and carry no ambiguity.
SetText(Label, string, bool, int)
Assigns text to label as literal text.
public static void SetText(Label label, string text, bool allowNewlines = false, int maxLength = 2048)
Parameters
labelLabelThe label to write into. Null is ignored.
textstringUntrusted text. Null is treated as empty.
allowNewlinesboolTrue to keep line breaks (body copy).
maxLengthintLength cap; defaults to MaxLength.
Remarks
Use this for every write of remote content into an existing label, not just the
first: enableRichText is a property of the element, and a label resolved from
a freshly cloned UXML tree is a different element with the default back in place.
(See the project's "mutate then Show" contract — UIDocument re-clones its tree
on every enable, so a flag set once on a cached element does not survive.)