Current section
Files
Jump to
Current section
Files
lib/html_sanitize_ex/scrubber/css.ex
defmodule HtmlSanitizeEx.Scrubber.CSS do @moduledoc """ Scrub CSS. """ def scrub(nil), do: "" def scrub(text) do text = String.replace(text, ~r/(\/\*|\*\/|<!--|-->)/, " ") Regex.replace(~r/([-\w]+)\s*:\s*([^:;]*)/, text, fn _all, a, b -> case scrub_css(a, b) do {property, value} -> "#{property}: #{value}" nil -> "" end end) end defp scrub_css("azimuth", val), do: validate({"azimuth", scrub_val(val)}) defp scrub_css("background-color", val), do: validate({"background-color", scrub_val(val)}) defp scrub_css("border-bottom-color", val), do: validate({"border-bottom-color", scrub_val(val)}) defp scrub_css("border-collapse", val), do: validate({"border-collapse", scrub_val(val)}) defp scrub_css("border-color", val), do: validate({"border-color", scrub_val(val)}) defp scrub_css("border-left-color", val), do: validate({"border-left-color", scrub_val(val)}) defp scrub_css("border-right-color", val), do: validate({"border-right-color", scrub_val(val)}) defp scrub_css("border-top-color", val), do: validate({"border-top-color", scrub_val(val)}) defp scrub_css("clear", val), do: validate({"clear", scrub_val(val)}) defp scrub_css("color", val), do: validate({"color", scrub_val(val)}) defp scrub_css("cursor", val), do: validate({"cursor", scrub_val(val)}) defp scrub_css("direction", val), do: validate({"direction", scrub_val(val)}) defp scrub_css("display", val), do: validate({"display", scrub_val(val)}) defp scrub_css("elevation", val), do: validate({"elevation", scrub_val(val)}) defp scrub_css("float", val), do: validate({"float", scrub_val(val)}) defp scrub_css("font", val), do: validate({"font", scrub_val(val)}) defp scrub_css("font-family", val), do: validate({"font-family", scrub_val(val)}) defp scrub_css("font-size", val), do: validate({"font-size", scrub_val(val)}) defp scrub_css("font-style", val), do: validate({"font-style", scrub_val(val)}) defp scrub_css("font-variant", val), do: validate({"font-variant", scrub_val(val)}) defp scrub_css("font-weight", val), do: validate({"font-weight", scrub_val(val)}) defp scrub_css("height", val), do: validate({"height", scrub_val(val)}) defp scrub_css("letter-spacing", val), do: validate({"letter-spacing", scrub_val(val)}) defp scrub_css("line-height", val), do: validate({"line-height", scrub_val(val)}) defp scrub_css("overflow", val), do: validate({"overflow", scrub_val(val)}) defp scrub_css("pause", val), do: validate({"pause", scrub_val(val)}) defp scrub_css("pause-after", val), do: validate({"pause-after", scrub_val(val)}) defp scrub_css("pause-before", val), do: validate({"pause-before", scrub_val(val)}) defp scrub_css("pitch", val), do: validate({"pitch", scrub_val(val)}) defp scrub_css("pitch-range", val), do: validate({"pitch-range", scrub_val(val)}) defp scrub_css("richness", val), do: validate({"richness", scrub_val(val)}) defp scrub_css("speak", val), do: validate({"speak", scrub_val(val)}) defp scrub_css("speak-header", val), do: validate({"speak-header", scrub_val(val)}) defp scrub_css("speak-numeral", val), do: validate({"speak-numeral", scrub_val(val)}) defp scrub_css("speak-punctuation", val), do: validate({"speak-punctuation", scrub_val(val)}) defp scrub_css("speech-rate", val), do: validate({"speech-rate", scrub_val(val)}) defp scrub_css("stress", val), do: validate({"stress", scrub_val(val)}) defp scrub_css("text-align", val), do: validate({"text-align", scrub_val(val)}) defp scrub_css("text-decoration", val), do: validate({"text-decoration", scrub_val(val)}) defp scrub_css("text-indent", val), do: validate({"text-indent", scrub_val(val)}) defp scrub_css("unicode-bidi", val), do: validate({"unicode-bidi", scrub_val(val)}) defp scrub_css("vertical-align", val), do: validate({"vertical-align", scrub_val(val)}) defp scrub_css("voice-family", val), do: validate({"voice-family", scrub_val(val)}) defp scrub_css("volume", val), do: validate({"volume", scrub_val(val)}) defp scrub_css("white-space", val), do: validate({"white-space", scrub_val(val)}) defp scrub_css("width", val), do: validate({"width", scrub_val(val)}) defp scrub_css("background", val), do: validate({"background", scrub_val(val)}) defp scrub_css("background-" <> prop, val), do: validate({"background-#{prop}", scrub_val(val)}) defp scrub_css("border", val), do: validate({"border", scrub_val(val)}) defp scrub_css("border-" <> prop, val), do: validate({"border-#{prop}", scrub_val(val)}) defp scrub_css("margin", val), do: validate({"margin", scrub_val(val)}) defp scrub_css("margin-" <> prop, val), do: validate({"margin-#{prop}", scrub_val(val)}) defp scrub_css("padding", val), do: validate({"padding", scrub_val(val)}) defp scrub_css("padding-" <> prop, val), do: validate({"padding-#{prop}", scrub_val(val)}) defp scrub_css(_, _), do: nil defp validate({_property, ""}), do: nil defp validate({property, val}), do: {property, val} defp scrub_val(val) do val = if String.match?(val, ~r/(\\|&)/), do: "", else: val Regex.replace(~r/(\S+)/, val, fn _all, a -> if(allowed_keyword?(a) || measured_unit?(a), do: a, else: "") end) end @allowed_keywords [ "auto", "aqua", "black", "block", "blue", "bold", "both", "bottom", "brown", "center", "collapse", "dashed", "dotted", "fuchsia", "gray", "green", "!important", "italic", "left", "lime", "maroon", "medium", "middle", "none", "navy", "normal", "nowrap", "olive", "pointer", "purple", "red", "right", "solid", "silver", "teal", "top", "transparent", "underline", "white", "yellow" ] def allowed_keyword?(val) do Enum.member?(@allowed_keywords, String.downcase(val)) end defp measured_unit?(val) do String.match?( val, ~r/\A(#[0-9a-f]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|-?\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)\z/ ) endend