class
Components::SafeStyle
- Components::SafeStyle
- Reference
- Object
Overview
SafeStyle is the typed style-attribute builder the hardening proposal
§3.3 requires: "Ban raw strings; require a typed Style/color builder."
This is what closes the CSS-context sink class the plain brand_color
mailer bug (Stage 5, commit c6ec54f) fell into — HTML.escape alone
would not have caught a CSS-context breakout, because the attack lives in
a different parser (the CSS value parser), not the HTML parser.
Design: a narrow property allowlist, each property either typed
(SafeColor/SafeLength) or checked against a denylist of dangerous CSS
constructs (url(...), expression(...), @import, embedded
javascript:, statement separators). "Ban until typed" is the default —
adding a property means adding it to the allowlist deliberately, not
opening a general string hole.
Defined in:
components/safe/safe_style.crConstant Summary
-
COLOR_PROPERTIES =
["color", "background-color", "border-color", "outline-color"] of ::String -
KEYWORD_PROPERTIES =
{"display" => ["none", "block", "inline", "inline-block", "flex", "inline-flex", "grid", "inline-grid", "contents"] of ::String, "position" => ["static", "relative", "absolute", "fixed", "sticky"] of ::String, "text-align" => ["left", "right", "center", "justify", "start", "end"] of ::String, "font-weight" => ["normal", "bold", "lighter", "bolder", "100", "200", "300", "400", "500", "600", "700", "800", "900"] of ::String, "flex-direction" => ["row", "row-reverse", "column", "column-reverse"] of ::String, "align-items" => ["stretch", "flex-start", "flex-end", "center", "baseline"] of ::String, "justify-content" => ["flex-start", "flex-end", "center", "space-between", "space-around", "space-evenly"] of ::String, "overflow" => ["visible", "hidden", "scroll", "auto", "clip"] of ::String, "overflow-x" => ["visible", "hidden", "scroll", "auto", "clip"] of ::String, "overflow-y" => ["visible", "hidden", "scroll", "auto", "clip"] of ::String, "white-space" => ["normal", "nowrap", "pre", "pre-line", "pre-wrap"] of ::String, "text-transform" => ["none", "capitalize", "uppercase", "lowercase"] of ::String} -
LENGTH_PROPERTIES =
["width", "height", "min-width", "min-height", "max-width", "max-height", "padding", "padding-top", "padding-bottom", "padding-left", "padding-right", "margin", "margin-top", "margin-bottom", "margin-left", "margin-right", "gap", "border-radius", "font-size", "line-height"] of ::String
Constructors
Instance Method Summary
- #build : SafeStyleValue
-
#color(property : String, value : Color) : self
A color-bearing property.
-
#keyword(property : String, value : String) : self
A keyword-bearing property (e.g.
-
#length(property : String, value : SafeLength) : self
A length-bearing property.
Constructor Detail
Instance Method Detail
A color-bearing property. Only COLOR_PROPERTIES are accepted; the
value must be a Color, never a string.
A keyword-bearing property (e.g. display: flex). The value must be
one of the property's own allowlisted keywords — this is how
KEYWORD_PROPERTIES stays a closed set rather than a string hole.
A length-bearing property. Only LENGTH_PROPERTIES are accepted; the
value must be a SafeLength, never a string — so expression(...),
url(...), and --custom-property: passthrough are unreachable here.