// Copyright (c) 2019, David Kitchen // // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * Neither the name of the organisation (Microcosm) nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package bluemonday import ( "regexp" "strings" ) var ( defaultStyleHandlers = map[string]func(string) bool{ "align-content": AlignContentHandler, "align-items": AlignItemsHandler, "align-self": AlignSelfHandler, "all": AllHandler, "animation": AnimationHandler, "animation-delay": AnimationDelayHandler, "animation-direction": AnimationDirectionHandler, "animation-duration": AnimationDurationHandler, "animation-fill-mode": AnimationFillModeHandler, "animation-iteration-count": AnimationIterationCountHandler, "animation-name": AnimationNameHandler, "animation-play-state": AnimationPlayStateHandler, "animation-timing-function": TimingFunctionHandler, "backface-visibility": BackfaceVisibilityHandler, "background": BackgroundHandler, "background-attachment": BackgroundAttachmentHandler, "background-blend-mode": BackgroundBlendModeHandler, "background-clip": BackgroundClipHandler, "background-color": ColorHandler, "background-image": ImageHandler, "background-origin": BackgroundOriginHandler, "background-position": BackgroundPositionHandler, "background-repeat": BackgroundRepeatHandler, "background-size": BackgroundSizeHandler, "border": BorderHandler, "border-bottom": BorderSideHandler, "border-bottom-color": ColorHandler, "border-bottom-left-radius": BorderSideRadiusHandler, "border-bottom-right-radius": BorderSideRadiusHandler, "border-bottom-style": BorderSideStyleHandler, "border-bottom-width": BorderSideWidthHandler, "border-collapse": BorderCollapseHandler, "border-color": ColorHandler, "border-image": BorderImageHandler, "border-image-outset": BorderImageOutsetHandler, "border-image-repeat": BorderImageRepeatHandler, "border-image-slice": BorderImageSliceHandler, "border-image-source": ImageHandler, "border-image-width": BorderImageWidthHandler, "border-left": BorderSideHandler, "border-left-color": ColorHandler, "border-left-style": BorderSideStyleHandler, "border-left-width": BorderSideWidthHandler, "border-radius": BorderRadiusHandler, "border-right": BorderSideHandler, "border-right-color": ColorHandler, "border-right-style": BorderSideStyleHandler, "border-right-width": BorderSideWidthHandler, "border-spacing": BorderSpacingHandler, "border-style": BorderStyleHandler, "border-top": BorderSideHandler, "border-top-color": ColorHandler, "border-top-left-radius": BorderSideRadiusHandler, "border-top-right-radius": BorderSideRadiusHandler, "border-top-style": BorderSideStyleHandler, "border-top-width": BorderSideWidthHandler, "border-width": BorderWidthHandler, "bottom": SideHandler, "box-decoration-break": BoxDecorationBreakHandler, "box-shadow": BoxShadowHandler, "box-sizing": BoxSizingHandler, "break-after": BreakBeforeAfterHandler, "break-before": BreakBeforeAfterHandler, "break-inside": BreakInsideHandler, "caption-side": CaptionSideHandler, "caret-color": CaretColorHandler, "clear": ClearHandler, "clip": ClipHandler, "color": ColorHandler, "column-count": ColumnCountHandler, "column-fill": ColumnFillHandler, "column-gap": ColumnGapHandler, "column-rule": ColumnRuleHandler, "column-rule-color": ColorHandler, "column-rule-style": BorderSideStyleHandler, "column-rule-width": ColumnRuleWidthHandler, "column-span": ColumnSpanHandler, "column-width": ColumnWidthHandler, "columns": ColumnsHandler, "cursor": CursorHandler, "direction": DirectionHandler, "display": DisplayHandler, "empty-cells": EmptyCellsHandler, "filter": FilterHandler, "flex": FlexHandler, "flex-basis": FlexBasisHandler, "flex-direction": FlexDirectionHandler, "flex-flow": FlexFlowHandler, "flex-grow": FlexGrowHandler, "flex-shrink": FlexGrowHandler, "flex-wrap": FlexWrapHandler, "float": FloatHandler, "font": FontHandler, "font-family": FontFamilyHandler, "font-kerning": FontKerningHandler, "font-language-override": FontLanguageOverrideHandler, "font-size": FontSizeHandler, "font-size-adjust": FontSizeAdjustHandler, "font-stretch": FontStretchHandler, "font-style": FontStyleHandler, "font-synthesis": FontSynthesisHandler, "font-variant": FontVariantHandler, "font-variant-caps": FontVariantCapsHandler, "font-variant-position": FontVariantPositionHandler, "font-weight": FontWeightHandler, "grid": GridHandler, "grid-area": GridAreaHandler, "grid-auto-columns": GridAutoColumnsHandler, "grid-auto-flow": GridAutoFlowHandler, "grid-auto-rows": GridAutoColumnsHandler, "grid-column": GridColumnHandler, "grid-column-end": GridAxisStartEndHandler, "grid-column-gap": LengthHandler, "grid-column-start": GridAxisStartEndHandler, "grid-gap": GridGapHandler, "grid-row": GridRowHandler, "grid-row-end": GridAxisStartEndHandler, "grid-row-gap": LengthHandler, "grid-row-start": GridAxisStartEndHandler, "grid-template": GridTemplateHandler, "grid-template-areas": GridTemplateAreasHandler, "grid-template-columns": GridTemplateColumnsHandler, "grid-template-rows": GridTemplateRowsHandler, "hanging-punctuation": HangingPunctuationHandler, "height": HeightHandler, "hyphens": HyphensHandler, "image-rendering": ImageRenderingHandler, "isolation": IsolationHandler, "justify-content": JustifyContentHandler, "left": SideHandler, "letter-spacing": LetterSpacingHandler, "line-break": LineBreakHandler, "line-height": LineHeightHandler, "list-style": ListStyleHandler, "list-style-image": ImageHandler, "list-style-position": ListStylePositionHandler, "list-style-type": ListStyleTypeHandler, "margin": MarginHandler, "margin-bottom": MarginSideHandler, "margin-left": MarginSideHandler, "margin-right": MarginSideHandler, "margin-top": MarginSideHandler, "max-height": MaxHeightWidthHandler, "max-width": MaxHeightWidthHandler, "min-height": MinHeightWidthHandler, "min-width": MinHeightWidthHandler, "mix-blend-mode": MixBlendModeHandler, "object-fit": ObjectFitHandler, "object-position": ObjectPositionHandler, "opacity": OpacityHandler, "order": OrderHandler, "orphans": OrphansHandler, "outline": OutlineHandler, "outline-color": ColorHandler, "outline-offset": OutlineOffsetHandler, "outline-style": OutlineStyleHandler, "outline-width": OutlineWidthHandler, "overflow": OverflowHandler, "overflow-wrap": OverflowWrapHandler, "overflow-x": OverflowXYHandler, "overflow-y": OverflowXYHandler, "padding": PaddingHandler, "padding-bottom": PaddingSideHandler, "padding-left": PaddingSideHandler, "padding-right": PaddingSideHandler, "padding-top": PaddingSideHandler, "page-break-after": PageBreakBeforeAfterHandler, "page-break-before": PageBreakBeforeAfterHandler, "page-break-inside": PageBreakInsideHandler, "perspective": PerspectiveHandler, "perspective-origin": PerspectiveOriginHandler, "pointer-events": PointerEventsHandler, "position": PositionHandler, "quotes": QuotesHandler, "resize": ResizeHandler, "right": SideHandler, "scroll-behavior": ScrollBehaviorHandler, "tab-size": TabSizeHandler, "table-layout": TableLayoutHandler, "text-align": TextAlignHandler, "text-align-last": TextAlignLastHandler, "text-combine-upright": TextCombineUprightHandler, "text-decoration": TextDecorationHandler, "text-decoration-color": ColorHandler, "text-decoration-line": TextDecorationLineHandler, "text-decoration-style": TextDecorationStyleHandler, "text-indent": TextIndentHandler, "text-justify": TextJustifyHandler, "text-orientation": TextOrientationHandler, "text-overflow": TextOverflowHandler, "text-shadow": TextShadowHandler, "text-transform": TextTransformHandler, "top": SideHandler, "transform": TransformHandler, "transform-origin": TransformOriginHandler, "transform-style": TransformStyleHandler, "transition": TransitionHandler, "transition-delay": TransitionDelayHandler, "transition-duration": TransitionDurationHandler, "transition-property": TransitionPropertyHandler, "transition-timing-function": TimingFunctionHandler, "unicode-bidi": UnicodeBidiHandler, "user-select": UserSelectHandler, "vertical-align": VerticalAlignHandler, "visibility": VisiblityHandler, "white-space": WhiteSpaceHandler, "widows": OrphansHandler, "width": WidthHandler, "word-break": WordBreakHandler, "word-spacing": WordSpacingHandler, "word-wrap": WordWrapHandler, "writing-mode": WritingModeHandler, "z-index": ZIndexHandler, } colorValues = []string{"initial", "inherit", "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgrey", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategrey", "darkslategray", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgrey", "lightgreen", "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteeelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen"} ) func multiSplit(value string, seps ...string) []string { curArray := []string{value} for _, i := range seps { newArray := []string{} for _, j := range curArray { newArray = append(newArray, strings.Split(j, i)...) } curArray = newArray } return curArray } func recursiveCheck(value []string, funcs []func(string) bool) bool { for i := 0; i < len(value); i++ { tempVal := strings.Join(value[:i+1], " ") for _, j := range funcs { if j(tempVal) && (len(value[i+1:]) == 0 || recursiveCheck(value[i+1:], funcs)) { return true } } } return false } func in(value []string, arr []string) bool { for _, i := range value { foundString := false for _, j := range arr { if j == i { foundString = true } } if !foundString { return false } } return true } func splitValues(value string) []string { values := strings.Split(value, ",") for _, strippedValue := range values { strippedValue = strings.ToLower(strings.TrimSpace(strippedValue)) } return values } func getDefaultHandler(attr string) func(string) bool { if defaultStyleHandlers[attr] != nil { return defaultStyleHandlers[attr] } return BaseHandler } func BaseHandler(value string) bool { return false } func AlignContentHandler(value string) bool { values := []string{"stretch", "center", "flex-start", "flex-end", "space-between", "space-around", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func AlignItemsHandler(value string) bool { values := []string{"stretch", "center", "flex-start", "flex-end", "baseline", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func AlignSelfHandler(value string) bool { values := []string{"auto", "stretch", "center", "flex-start", "flex-end", "baseline", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func AllHandler(value string) bool { values := []string{"initial", "inherit", "unset"} splitVals := splitValues(value) return in(splitVals, values) } func AnimationHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") usedFunctions := []func(string) bool{ AnimationNameHandler, AnimationDurationHandler, TimingFunctionHandler, AnimationDelayHandler, AnimationIterationCountHandler, AnimationDirectionHandler, AnimationFillModeHandler, AnimationPlayStateHandler, } return recursiveCheck(splitVals, usedFunctions) } func AnimationDelayHandler(value string) bool { reg := regexp.MustCompile(`[\-]?[0-9]+[\.]?[0-9]*[s|ms]?`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } values := []string{"initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func AnimationDirectionHandler(value string) bool { values := []string{"normal", "reverse", "alternate", "alternate-reverse", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func AnimationDurationHandler(value string) bool { reg := regexp.MustCompile(`[0-9]+[\.]?[0-9]*[s|ms]?`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } values := []string{"initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func AnimationFillModeHandler(value string) bool { values := []string{"none", "forwards", "backwards", "both", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func AnimationIterationCountHandler(value string) bool { reg := regexp.MustCompile(`[0-9]+[\.]?[0-9]*`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } values := []string{"infinite", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func AnimationNameHandler(value string) bool { reg := regexp.MustCompile(`[a-z]+`) reg.Longest() return reg.FindString(value) == value && value != "" } func AnimationPlayStateHandler(value string) bool { values := []string{"paused", "running", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func TimingFunctionHandler(value string) bool { values := []string{"linear", "ease", "ease-in", "ease-out", "ease-in-out", "step-start", "step-end", "initial", "inherit"} splitVals := splitValues(value) if in(splitVals, values) { return true } reg := regexp.MustCompile(`cubic-bezier\(([ ]*(0(.[0-9]+)?|1(.0)?),){3}[ ]*(0(.[0-9]+)?|1)\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`steps\([ ]*[0-9]+([ ]*,[ ]*(start|end)?)\)`) reg.Longest() return reg.FindString(value) == value && value != "" } func BackfaceVisibilityHandler(value string) bool { values := []string{"visible", "hidden", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func BackgroundHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") newSplitVals := []string{} for _, i := range splitVals { if len(strings.Split(i, "/")) == 2 { newSplitVals = append(newSplitVals, strings.Split(i, "/")...) } else { newSplitVals = append(newSplitVals, i) } } usedFunctions := []func(string) bool{ ColorHandler, ImageHandler, BackgroundPositionHandler, BackgroundSizeHandler, BackgroundRepeatHandler, BackgroundOriginHandler, BackgroundClipHandler, BackgroundAttachmentHandler, } return recursiveCheck(newSplitVals, usedFunctions) } func BackgroundAttachmentHandler(value string) bool { values := []string{"scroll", "fixed", "local", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func BackgroundClipHandler(value string) bool { values := []string{"border-box", "padding-box", "content-box", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func BackgroundBlendModeHandler(value string) bool { values := []string{"normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "saturation", "color", "luminosity"} splitVals := splitValues(value) return in(splitVals, values) } func ImageHandler(value string) bool { values := []string{"none", "initial", "inherit"} splitVals := splitValues(value) if in(splitVals, values) { return true } reg := regexp.MustCompile(`url\([\"\']?((https|http)[a-z0-9\.\\/_:]+[\"\']?)\)`) reg.Longest() return reg.FindString(value) == value && value != "" } func BackgroundOriginHandler(value string) bool { values := []string{"padding-box", "border-box", "content-box", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func BackgroundPositionHandler(value string) bool { splitVals := strings.Split(value, ";") values := []string{"left", "left top", "left bottom", "right", "right top", "right bottom", "right center", "center top", "center center", "center bottom", "center", "top", "bottom", "initial", "inherit"} if in(splitVals, values) { return true } reg := regexp.MustCompile(`[\-]*[0-9]+[cm|mm|in|px|pt|pc\%]* [[\-]*[0-9]+[cm|mm|in|px|pt|pc\%]*]*`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } return false } func BackgroundRepeatHandler(value string) bool { values := []string{"repeat", "repeat-x", "repeat-y", "no-repeat", "space", "round", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func BackgroundSizeHandler(value string) bool { splitVals := strings.Split(value, " ") values := []string{"auto", "cover", "contain", "initial", "inherit"} if in(splitVals, values) { return true } if len(splitVals) > 0 && LengthHandler(splitVals[0]) { if len(splitVals) < 2 || (len(splitVals) == 2 && LengthHandler(splitVals[1])) { return true } } return false } func BorderHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := multiSplit(value, " ", "/") usedFunctions := []func(string) bool{ BorderWidthHandler, BorderStyleHandler, ColorHandler, } return recursiveCheck(splitVals, usedFunctions) } func BorderSideHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") usedFunctions := []func(string) bool{ BorderSideWidthHandler, BorderSideStyleHandler, ColorHandler, } return recursiveCheck(splitVals, usedFunctions) } func BorderSideRadiusHandler(value string) bool { splitVals := strings.Split(value, " ") valid := true for _, i := range splitVals { if !LengthHandler(i) { valid = false break } } if valid { return true } splitVals = splitValues(value) values := []string{"initial", "inherit"} return in(splitVals, values) } func BorderSideStyleHandler(value string) bool { values := []string{"none", "hidden", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func BorderSideWidthHandler(value string) bool { if LengthHandler(value) { return true } splitVals := strings.Split(value, ";") values := []string{"medium", "thin", "thick", "initial", "inherit"} return in(splitVals, values) } func BorderCollapseHandler(value string) bool { values := []string{"separate", "collapse", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func BorderImageHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := multiSplit(value, " ", " / ") usedFunctions := []func(string) bool{ ImageHandler, BorderImageSliceHandler, BorderImageWidthHandler, BorderImageOutsetHandler, BorderImageRepeatHandler, } return recursiveCheck(splitVals, usedFunctions) } func BorderImageOutsetHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func BorderImageRepeatHandler(value string) bool { values := []string{"stretch", "repeat", "round", "space", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func BorderImageSliceHandler(value string) bool { values := []string{"fill", "initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") if len(splitVals) > 4 { return false } usedFunctions := []func(string) bool{ LengthHandler, } return recursiveCheck(splitVals, usedFunctions) } func BorderImageWidthHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"auto", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func BorderRadiusHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") if len(splitVals) > 4 { return false } usedFunctions := []func(string) bool{ LengthHandler, } return recursiveCheck(splitVals, usedFunctions) } func BorderSpacingHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") if len(splitVals) > 2 { return false } usedFunctions := []func(string) bool{ LengthHandler, } return recursiveCheck(splitVals, usedFunctions) } func BorderStyleHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") if len(splitVals) > 4 { return false } usedFunctions := []func(string) bool{ BorderSideStyleHandler, } return recursiveCheck(splitVals, usedFunctions) } func BorderWidthHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") if len(splitVals) > 4 { return false } usedFunctions := []func(string) bool{ BorderSideWidthHandler, } return recursiveCheck(splitVals, usedFunctions) } func SideHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"auto", "inherit", "unset"} splitVals := splitValues(value) return in(splitVals, values) } func BoxDecorationBreakHandler(value string) bool { values := []string{"slice", "clone", "initial", "initial", "inherit", "unset"} splitVals := splitValues(value) return in(splitVals, values) } func BoxShadowHandler(value string) bool { values := []string{"none", "initial", "inherit"} if in([]string{value}, values) { return true } commaSplitVals := strings.Split(value, ",") for _, val := range commaSplitVals { splitVals := strings.Split(val, " ") if len(splitVals) > 6 || len(splitVals) < 2 { return false } if !LengthHandler(splitVals[0]) { return false } if !LengthHandler(splitVals[1]) { return false } usedFunctions := []func(string) bool{ LengthHandler, ColorHandler, } if len(splitVals) > 2 && !recursiveCheck(splitVals[2:], usedFunctions) { return false } } return true } func BoxSizingHandler(value string) bool { values := []string{"slicontent-box", "border-box", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func BreakBeforeAfterHandler(value string) bool { values := []string{"auto", "avoid", "always", "all", "avoid-page", "page", "left", "right", "recto", "verso", "avoid-column", "column", "avoid-region", "region"} splitVals := splitValues(value) return in(splitVals, values) } func BreakInsideHandler(value string) bool { values := []string{"auto", "avoid", "avoid-page", "avoid-column", "avoid-region"} splitVals := splitValues(value) return in(splitVals, values) } func CaptionSideHandler(value string) bool { values := []string{"top", "bottom", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func CaretColorHandler(value string) bool { splitVals := splitValues(value) if in(splitVals, colorValues) { return true } reg := regexp.MustCompile(`#[0-9abcdef]{6}`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`rgb\(([ ]*((([0-9]{1,2}|100)\%)|(([01]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))),){2}([ ]*((([0-9]{1,2}|100)\%)|(([01]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))))\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`rgba\(([ ]*((([0-9]{1,2}|100)\%)|(([01]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))),){3}[ ]*(1(\.0)?|0|(0\.[0-9]+))\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`hsl\([ ]*([012]?[0-9]{1,2}|3[0-5][0-9]|360),[ ]*([0-9]{0,2}|100)\%,[ ]*([0-9]{0,2}|100)\%\)`) if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`hsla\(([ ]*[012]?[0-9]{1,2}|3[0-5][0-9]|360),[ ]*([0-9]{0,2}|100)\%,[ ]*([0-9]{0,2}|100)\%,[ ]*(1|1\.0|0|(0\.[0-9]+))\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } return false } func ClearHandler(value string) bool { values := []string{"none", "left", "right", "both", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func ClipHandler(value string) bool { reg := regexp.MustCompile(`rect\([0-9]+px,[ ]*[0-9]+px,[ ]*[0-9]+px,[ ]*[0-9]+px\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } values := []string{"auto", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func ColorHandler(value string) bool { splitVals := splitValues(value) if in(splitVals, colorValues) { return true } reg := regexp.MustCompile(`#[0-9abcdef]{6}`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`rgb\(([ ]*((([0-9]{1,2}|100)\%)|(([01]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))),){2}([ ]*((([0-9]{1,2}|100)\%)|(([01]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))))\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`rgba\(([ ]*((([0-9]{1,2}|100)\%)|(([01]?[0-9]{1,2})|(2[0-4][0-9])|(25[0-5]))),){3}[ ]*(1(\.0)?|0|(0\.[0-9]+))\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`hsl\([ ]*([012]?[0-9]{1,2}|3[0-5][0-9]|360),[ ]*([0-9]{0,2}|100)\%,[ ]*([0-9]{0,2}|100)\%\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`hsla\(([ ]*[012]?[0-9]{1,2}|3[0-5][0-9]|360),[ ]*([0-9]{0,2}|100)\%,[ ]*([0-9]{0,2}|100)\%,[ ]*(1|1\.0|0|(0\.[0-9]+))\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } return false } func ColumnCountHandler(value string) bool { reg := regexp.MustCompile(`[0-9]+`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } values := []string{"auto", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func ColumnFillHandler(value string) bool { values := []string{"balance", "auto", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func ColumnGapHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"normal", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func ColumnRuleHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") usedFunctions := []func(string) bool{ ColumnRuleWidthHandler, BorderSideStyleHandler, ColorHandler, } return recursiveCheck(splitVals, usedFunctions) } func ColumnRuleWidthHandler(value string) bool { if LengthHandler(value) { return true } splitVals := strings.Split(value, ";") values := []string{"medium", "thin", "thick", "initial", "inherit"} return in(splitVals, values) } func ColumnSpanHandler(value string) bool { values := []string{"none", "all", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func ColumnWidthHandler(value string) bool { if LengthHandler(value) { return true } splitVals := strings.Split(value, ";") values := []string{"auto", "initial", "inherit"} return in(splitVals, values) } func ColumnsHandler(value string) bool { values := []string{"auto", "initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") usedFunctions := []func(string) bool{ ColumnWidthHandler, ColumnCountHandler, } return recursiveCheck(splitVals, usedFunctions) } func CursorHandler(value string) bool { values := []string{"alias", "all-scroll", "auto", "cell", "context-menu", "col-resize", "copy", "crosshair", "default", "e-resize", "ew-resize", "grab", "grabbing", "help", "move", "n-resize", "ne-resize", "nesw-resize", "ns-resize", "nw-resize", "nwse-resize", "no-drop", "none", "not-allowed", "pointer", "progress", "row-resize", "s-resize", "se-resize", "sw-resize", "text", "vertical-text", "w-resize", "wait", "zoom-in", "zoom-out", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func DirectionHandler(value string) bool { values := []string{"ltr", "rtl", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func DisplayHandler(value string) bool { values := []string{"inline", "block", "contents", "flex", "grid", "inline-block", "inline-flex", "inline-grid", "inline-table", "list-item", "run-in", "table", "table-caption", "table-column-group", "table-header-group", "table-footer-group", "table-row-group", "table-cell", "table-column", "table-row", "none", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func EmptyCellsHandler(value string) bool { values := []string{"show", "hide", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func FilterHandler(value string) bool { values := []string{"none", "initial", "inherit"} splitVals := splitValues(value) if in(splitVals, values) { return true } reg := regexp.MustCompile(`blur\([0-9]+px\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`(brightness|contrast)\([0-9]+\%\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`drop-shadow\(([-]?[0-9]+px) ([-]?[0-9]+px)( [-]?[0-9]+px)?( ([-]?[0-9]+px))?`) reg.Longest() colorValue := strings.TrimSuffix(string(reg.ReplaceAll([]byte(value), []byte{})), ")") if ColorHandler(colorValue) { return true } reg = regexp.MustCompile(`grayscale\(([0-9]{1,2}|100)%\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`hue-rotate\(([12]?[0-9]{1,2}|3[0-5][0-9]|360)?\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`invert\(([0-9]{1,2}|100)%\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`opacity\(([0-9]{1,2}|100)%\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`saturate\([0-9]+%\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`sepia\(([0-9]{1,2}|100)%\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } //Not allowing URLs return false } func FlexHandler(value string) bool { values := []string{"auto", "initial", "initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") usedFunctions := []func(string) bool{ FlexGrowHandler, FlexBasisHandler, } return recursiveCheck(splitVals, usedFunctions) } func FlexBasisHandler(value string) bool { if LengthHandler(value) { return true } splitVals := strings.Split(value, ";") values := []string{"auto", "initial", "inherit"} return in(splitVals, values) } func FlexDirectionHandler(value string) bool { values := []string{"row", "row-reverse", "column", "column-reverse", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func FlexFlowHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") usedFunctions := []func(string) bool{ FlexDirectionHandler, FlexWrapHandler, } return recursiveCheck(splitVals, usedFunctions) } func FlexGrowHandler(value string) bool { reg := regexp.MustCompile(`[0-9\.]+`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } splitVals := strings.Split(value, ";") values := []string{"initial", "inherit"} return in(splitVals, values) } func FlexWrapHandler(value string) bool { values := []string{"nowrap", "wrap", "wrap-reverse", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func FloatHandler(value string) bool { values := []string{"none", "left", "right", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func FontHandler(value string) bool { values := []string{"caption", "icon", "menu", "message-box", "small-caption", "status-bar", "initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") newSplitVals := []string{} for _, i := range splitVals { if len(strings.Split(i, "/")) == 2 { newSplitVals = append(newSplitVals, strings.Split(i, "/")...) } else { newSplitVals = append(newSplitVals, i) } } usedFunctions := []func(string) bool{ FontStyleHandler, FontVariantHandler, FontWeightHandler, FontSizeHandler, FontFamilyHandler, } return recursiveCheck(newSplitVals, usedFunctions) } func FontFamilyHandler(value string) bool { values := []string{"initial", "inherit"} splitVals := splitValues(value) if in(splitVals, values) { return true } reg := regexp.MustCompile(`('[a-z \-]+'|[a-z \-]+)`) reg.Longest() for _, i := range splitVals { i = strings.TrimSpace(i) if reg.FindString(i) != i { return false } } return true } func FontKerningHandler(value string) bool { values := []string{"auto", "normal", "none"} splitVals := splitValues(value) return in(splitVals, values) } func FontLanguageOverrideHandler(value string) bool { reg := regexp.MustCompile(`[a-z]+`) reg.Longest() return reg.FindString(value) == value && value != "" } func FontSizeHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"medium", "xx-small", "x-small", "small", "large", "x-large", "xx-large", "smaller", "larger", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func FontSizeAdjustHandler(value string) bool { reg := regexp.MustCompile(`[0-9]+[\.]?[0-9]*`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } values := []string{"auto", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func FontStretchHandler(value string) bool { values := []string{"ultra-condensed", "extra-condensed", "condensed", "semi-condensed", "normal", "semi-expanded", "expanded", "extra-expanded", "ultra-expanded", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func FontStyleHandler(value string) bool { values := []string{"normal", "italic", "oblique", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func FontSynthesisHandler(value string) bool { values := []string{"none", "style", "weight"} splitVals := splitValues(value) return in(splitVals, values) } func FontVariantCapsHandler(value string) bool { values := []string{"normal", "small-caps", "all-small-caps", "petite-caps", "all-petite-caps", "unicase", "titling-caps"} splitVals := splitValues(value) return in(splitVals, values) } func FontVariantHandler(value string) bool { values := []string{"normal", "small-caps", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func FontVariantPositionHandler(value string) bool { values := []string{"normal", "sub", "super"} splitVals := splitValues(value) return in(splitVals, values) } func FontWeightHandler(value string) bool { values := []string{"normal", "bold", "bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func GridHandler(value string) bool { values := []string{"none", "initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") newSplitVals := []string{} for _, i := range splitVals { if i != "/" { newSplitVals = append(newSplitVals, i) } } usedFunctions := []func(string) bool{ GridTemplateRowsHandler, GridTemplateColumnsHandler, GridTemplateAreasHandler, GridAutoColumnsHandler, GridAutoFlowHandler, } return recursiveCheck(newSplitVals, usedFunctions) } func GridAreaHandler(value string) bool { values := []string{"none", "initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " / ") usedFunctions := []func(string) bool{ GridAxisStartEndHandler, } return recursiveCheck(splitVals, usedFunctions) } func GridAutoColumnsHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"auto", "max-content", "min-content", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func GridAutoFlowHandler(value string) bool { values := []string{"row", "column", "dense", "row dense", "column dense"} splitVals := splitValues(value) return in(splitVals, values) } func GridColumnHandler(value string) bool { values := []string{"none", "initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " / ") if len(splitVals) > 2 { return false } usedFunctions := []func(string) bool{ GridAxisStartEndHandler, } return recursiveCheck(splitVals, usedFunctions) } func GridColumnGapHandler(value string) bool { return LengthHandler(value) } func LengthHandler(value string) bool { reg := regexp.MustCompile(`[\-]?[0-9]+[\.]?[0-9]*(%|cm|mm|in|px|pt|pc|em|ex|ch|rem|vw|vh|vmin|vmax|deg|rad|turn)?`) reg.Longest() return reg.FindString(value) == value && value != "" } func LineBreakHandler(value string) bool { values := []string{"auto", "loose", "normal", "strict"} splitVals := splitValues(value) return in(splitVals, values) } func GridAxisStartEndHandler(value string) bool { reg := regexp.MustCompile(`[0-9]+`) if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`span [0-9]+`) if reg.FindString(value) == value && value != "" { return true } values := []string{"auto"} splitVals := splitValues(value) return in(splitVals, values) } func GridGapHandler(value string) bool { splitVals := strings.Split(value, " ") if len(splitVals) > 2 { return false } usedFunctions := []func(string) bool{ GridColumnGapHandler, } return recursiveCheck(splitVals, usedFunctions) } func GridRowHandler(value string) bool { splitVals := strings.Split(value, " / ") if len(splitVals) > 2 { return false } usedFunctions := []func(string) bool{ GridAxisStartEndHandler, } return recursiveCheck(splitVals, usedFunctions) } func GridTemplateHandler(value string) bool { values := []string{"none", "initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " / ") if len(splitVals) > 2 { return false } usedFunctions := []func(string) bool{ GridTemplateColumnsHandler, GridTemplateRowsHandler, } return recursiveCheck(splitVals, usedFunctions) } func GridTemplateAreasHandler(value string) bool { values := []string{"none"} if in([]string{value}, values) { return true } reg := regexp.MustCompile(`['"]?[a-z ]+['"]?`) reg.Longest() return reg.FindString(value) == value && value != "" } func GridTemplateColumnsHandler(value string) bool { splitVals := strings.Split(value, " ") values := []string{"none", "auto", "max-content", "min-content", "initial", "inherit"} for _, val := range splitVals { if LengthHandler(val) { continue } valArr := []string{val} if !in(valArr, values) { return false } } return true } func GridTemplateRowsHandler(value string) bool { splitVals := strings.Split(value, " ") values := []string{"none", "auto", "max-content", "min-content"} for _, val := range splitVals { if LengthHandler(val) { continue } valArr := []string{val} if !in(valArr, values) { return false } } return true } func HangingPunctuationHandler(value string) bool { values := []string{"none", "first", "last", "allow-end", "force-end", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func HeightHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"auto", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func HyphensHandler(value string) bool { values := []string{"none", "manual", "auto", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func ImageRenderingHandler(value string) bool { values := []string{"auto", "smooth", "high-quality", "crisp-edges", "pixelated"} splitVals := splitValues(value) return in(splitVals, values) } func IsolationHandler(value string) bool { values := []string{"auto", "isolate", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func JustifyContentHandler(value string) bool { values := []string{"flex-start", "flex-end", "center", "space-between", "space-around", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func LetterSpacingHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"normal", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func LineHeightHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"normal", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func ListStyleHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") usedFunctions := []func(string) bool{ ListStyleTypeHandler, ListStylePositionHandler, ImageHandler, } return recursiveCheck(splitVals, usedFunctions) } func ListStylePositionHandler(value string) bool { values := []string{"inside", "outside", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func ListStyleTypeHandler(value string) bool { values := []string{"disc", "armenian", "circle", "cjk-ideographic", "decimal", "decimal-leading-zero", "georgian", "hebrew", "hiragana", "hiragana-iroha", "katakana", "katakana-iroha", "lower-alpha", "lower-greek", "lower-latin", "lower-roman", "none", "square", "upper-alpha", "upper-greek", "upper-latin", "upper-roman", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func MarginHandler(value string) bool { values := []string{"auto", "initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") usedFunctions := []func(string) bool{ MarginSideHandler, } return recursiveCheck(splitVals, usedFunctions) } func MarginSideHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"auto", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func MaxHeightWidthHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"none", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func MinHeightWidthHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func MixBlendModeHandler(value string) bool { values := []string{"normal", "multiply", "screen", "overlay", "darken", "lighten", "color-dodge", "color-burn", "difference", "exclusion", "hue", "saturation", "color", "luminosity"} splitVals := splitValues(value) return in(splitVals, values) } func ObjectFitHandler(value string) bool { values := []string{"fill", "contain", "cover", "none", "scale-down", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func ObjectPositionHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") if len(splitVals) > 2 { return false } usedFunctions := []func(string) bool{ LengthHandler, } return recursiveCheck(splitVals, usedFunctions) } func OpacityHandler(value string) bool { reg := regexp.MustCompile("(0[.]?[0-9]*)|(1.0)") reg.Longest() if reg.FindString(value) == value && value != "" { return true } values := []string{"initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func OrderHandler(value string) bool { reg := regexp.MustCompile("[0-9]+") reg.Longest() if reg.FindString(value) == value && value != "" { return true } values := []string{"initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func OutlineHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") usedFunctions := []func(string) bool{ ColorHandler, OutlineWidthHandler, OutlineStyleHandler, } return recursiveCheck(splitVals, usedFunctions) } func OutlineOffsetHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func OutlineStyleHandler(value string) bool { values := []string{"none", "hidden", "dotted", "dashed", "solid", "double", "groove", "ridge", "inset", "outset", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func OutlineWidthHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"medium", "thin", "thick", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func OverflowHandler(value string) bool { values := []string{"visible", "hidden", "scroll", "auto", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func OverflowXYHandler(value string) bool { values := []string{"visible", "hidden", "scroll", "auto", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func OverflowWrapHandler(value string) bool { values := []string{"normal", "break-word", "anywhere"} splitVals := splitValues(value) return in(splitVals, values) } func OrphansHandler(value string) bool { reg := regexp.MustCompile(`[0-9]+`) reg.Longest() return reg.FindString(value) == value && value != "" } func PaddingHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") if len(splitVals) > 4 { return false } usedFunctions := []func(string) bool{ PaddingSideHandler, } return recursiveCheck(splitVals, usedFunctions) } func PaddingSideHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func PageBreakBeforeAfterHandler(value string) bool { values := []string{"auto", "always", "avoid", "left", "right", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func PageBreakInsideHandler(value string) bool { values := []string{"auto", "avoid", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func PerspectiveHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"none", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func PerspectiveOriginHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") xValues := []string{"left", "center", "right"} yValues := []string{"top", "center", "bottom"} if len(splitVals) > 1 { if !in([]string{splitVals[0]}, xValues) && !LengthHandler(splitVals[0]) { return false } return in([]string{splitVals[1]}, yValues) || LengthHandler(splitVals[1]) } else if len(splitVals) == 1 { return in(splitVals, xValues) || in(splitVals, yValues) || LengthHandler(splitVals[0]) } return false } func PointerEventsHandler(value string) bool { values := []string{"auto", "none", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func PositionHandler(value string) bool { values := []string{"static", "absolute", "fixed", "relative", "sticky", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func QuotesHandler(value string) bool { values := []string{"none", "initial", "inherit"} splitVals := splitValues(value) if in(splitVals, values) { return true } reg := regexp.MustCompile(`([ ]*["'][\x{0022}\x{0027}\x{2039}\x{2039}\x{203A}\x{00AB}\x{00BB}\x{2018}\x{2019}\x{201C}-\x{201E}]["'] ["'][\x{0022}\x{0027}\x{2039}\x{2039}\x{203A}\x{00AB}\x{00BB}\x{2018}\x{2019}\x{201C}-\x{201E}]["'])+`) reg.Longest() return reg.FindString(value) == value && value != "" } func ResizeHandler(value string) bool { values := []string{"none", "both", "horizontal", "vertical", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func ScrollBehaviorHandler(value string) bool { values := []string{"auto", "smooth", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func TabSizeHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func TableLayoutHandler(value string) bool { values := []string{"auto", "fixed", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func TextAlignHandler(value string) bool { values := []string{"left", "right", "center", "justify", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func TextAlignLastHandler(value string) bool { values := []string{"auto", "left", "right", "center", "justify", "start", "end", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func TextCombineUprightHandler(value string) bool { values := []string{"none", "all"} splitVals := splitValues(value) if in(splitVals, values) { return true } reg := regexp.MustCompile(`digits [2-4]`) reg.Longest() return reg.FindString(value) == value && value != "" } func TextDecorationHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") usedFunctions := []func(string) bool{ TextDecorationStyleHandler, ColorHandler, TextDecorationLineHandler, } return recursiveCheck(splitVals, usedFunctions) } func TextDecorationLineHandler(value string) bool { values := []string{"none", "underline", "overline", "line-through", "initial", "inherit"} splitVals := strings.Split(value, " ") return in(splitVals, values) } func TextDecorationStyleHandler(value string) bool { values := []string{"solid", "double", "dotted", "dashed", "wavy", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func TextIndentHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func TextJustifyHandler(value string) bool { values := []string{"auto", "inter-word", "inter-character", "none", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func TextOverflowHandler(value string) bool { reg := regexp.MustCompile("[\"'][a-z]+[\"']") reg.Longest() if reg.FindString(value) == value && value != "" { return true } values := []string{"clip", "ellipsis", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func TextOrientationHandler(value string) bool { values := []string{"mixed", "upright", "sideways", "sideways-right"} splitVals := splitValues(value) return in(splitVals, values) } func TextShadowHandler(value string) bool { values := []string{"none", "initial", "inherit"} if in([]string{value}, values) { return true } commaSplitVals := strings.Split(value, ",") for _, val := range commaSplitVals { splitVals := strings.Split(val, " ") if len(splitVals) > 6 || len(splitVals) < 2 { return false } if !LengthHandler(splitVals[0]) { return false } if !LengthHandler(splitVals[1]) { return false } usedFunctions := []func(string) bool{ LengthHandler, ColorHandler, } if len(splitVals) > 2 && !recursiveCheck(splitVals[2:], usedFunctions) { return false } } return true } func TextTransformHandler(value string) bool { values := []string{"none", "capitalize", "uppercase", "lowercase", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func TransformHandler(value string) bool { values := []string{"none", "initial", "inherit"} if in([]string{value}, values) { return true } reg := regexp.MustCompile(`matrix\(([ ]*[0-9]+[\.]?[0-9]*,){5}([ ]*[0-9]+[\.]?[0-9]*)\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`matrix3d\(([ ]*[0-9]+[\.]?[0-9]*,){15}([ ]*[0-9]+[\.]?[0-9]*)\)`) if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`(translate|translate3d|translatex|translatey|translatez|scale|scale3d|scalex|scaley|scalez)\(`) reg.Longest() subValue := string(reg.ReplaceAll([]byte(value), []byte{})) trimValue := strings.Split(strings.TrimSuffix(subValue, ")"), ",") valid := true for _, i := range trimValue { if !LengthHandler(strings.TrimSpace(i)) { valid = false break } } if valid && trimValue != nil { return true } reg = regexp.MustCompile(`rotate(x|y|z)?\(([12]?|3[0-5][0-9]|360)\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`rotate3d\(([ ]?(1(\.0)?|0\.[0-9]+),){3}([12]?|3[0-5][0-9]|360)\)`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } reg = regexp.MustCompile(`skew(x|y)?\(`) reg.Longest() subValue = string(reg.ReplaceAll([]byte(value), []byte{})) subValue = strings.TrimSuffix(subValue, ")") trimValue = strings.Split(subValue, ",") valid = true for _, i := range trimValue { if !LengthHandler(strings.TrimSpace(i)) { valid = false break } } if valid { return true } reg = regexp.MustCompile(`perspective\(`) reg.Longest() subValue = string(reg.ReplaceAll([]byte(value), []byte{})) subValue = strings.TrimSuffix(subValue, ")") return LengthHandler(subValue) } func TransformOriginHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") xValues := []string{"left", "center", "right"} yValues := []string{"top", "center", "bottom"} if len(splitVals) > 2 { if !in([]string{splitVals[0]}, xValues) && !LengthHandler(splitVals[0]) { return false } if !in([]string{splitVals[1]}, yValues) && !LengthHandler(splitVals[1]) { return false } return LengthHandler(splitVals[2]) } else if len(splitVals) > 1 { if !in([]string{splitVals[0]}, xValues) && !LengthHandler(splitVals[0]) { return false } return in([]string{splitVals[1]}, yValues) || LengthHandler(splitVals[1]) } else if len(splitVals) == 1 { return in(splitVals, xValues) || in(splitVals, yValues) || LengthHandler(splitVals[0]) } return false } func TransformStyleHandler(value string) bool { values := []string{"flat", "preserve-3d", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func TransitionHandler(value string) bool { values := []string{"initial", "inherit"} if in([]string{value}, values) { return true } splitVals := strings.Split(value, " ") usedFunctions := []func(string) bool{ TransitionPropertyHandler, TransitionDurationHandler, TimingFunctionHandler, TransitionDelayHandler, ColorHandler, } return recursiveCheck(splitVals, usedFunctions) } func TransitionDelayHandler(value string) bool { reg := regexp.MustCompile("[0-9]+[.]?[0-9]*(s|ms)?") reg.Longest() if reg.FindString(value) == value && value != "" { return true } values := []string{"initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func TransitionDurationHandler(value string) bool { reg := regexp.MustCompile("[0-9]+[.]?[0-9]*(s|ms)?") reg.Longest() if reg.FindString(value) == value && value != "" { return true } values := []string{"initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func TransitionPropertyHandler(value string) bool { reg := regexp.MustCompile("([a-zA-Z]+,[ ]?)*[a-zA-Z]+") reg.Longest() if reg.FindString(value) == value && value != "" { return true } values := []string{"none", "all", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func UnicodeBidiHandler(value string) bool { values := []string{"normal", "embed", "bidi-override", "isolate", "isolate-override", "plaintext", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func UserSelectHandler(value string) bool { values := []string{"auto", "none", "text", "all"} splitVals := splitValues(value) return in(splitVals, values) } func VerticalAlignHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"baseline", "sub", "super", "top", "text-top", "middle", "bottom", "text-bottom", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func VisiblityHandler(value string) bool { values := []string{"visible", "hidden", "collapse", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func WhiteSpaceHandler(value string) bool { values := []string{"normal", "nowrap", "pre", "pre-line", "pre-wrap", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func WidthHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"auto", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func WordSpacingHandler(value string) bool { if LengthHandler(value) { return true } values := []string{"normal", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func WordBreakHandler(value string) bool { values := []string{"normal", "break-all", "keep-all", "break-word", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func WordWrapHandler(value string) bool { values := []string{"normal", "break-word", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) } func WritingModeHandler(value string) bool { values := []string{"horizontal-tb", "vertical-rl", "vertical-lr"} splitVals := splitValues(value) return in(splitVals, values) } func ZIndexHandler(value string) bool { reg := regexp.MustCompile(`[\-]?[0-9]+`) reg.Longest() if reg.FindString(value) == value && value != "" { return true } values := []string{"auto", "initial", "inherit"} splitVals := splitValues(value) return in(splitVals, values) }