From 4a6ab032e710f1292bb1ecd577c0dc9900e8dcf0 Mon Sep 17 00:00:00 2001 From: melsonic Date: Wed, 16 Apr 2025 00:49:12 +0530 Subject: [PATCH 1/5] validate gradient color stops --- d2compiler/compile_test.go | 8 ++++++++ lib/color/gradient.go | 13 ++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/d2compiler/compile_test.go b/d2compiler/compile_test.go index 702295099..57568e279 100644 --- a/d2compiler/compile_test.go +++ b/d2compiler/compile_test.go @@ -3929,6 +3929,14 @@ svc_1.t2 -> b: do with B tassert.Equal(t, "d2/testdata/d2compiler/TestCompile/meow.d2", g.Layers[0].Layers[0].AST.Range.Path) }, }, + { + name: "invalid_gradient_color_stop", + text: ` + x + x.style.fill: "linear-gradient(#ggg, #000)" + `, + expErr: `d2/testdata/d2compiler/TestCompile/invalid_gradient_color_stop.d2:3:19: expected "fill" to be a valid named color ("orange"), a hex code ("#f0ff3a"), or a gradient ("linear-gradient(red, blue)")`, + }, } for _, tc := range testCases { diff --git a/lib/color/gradient.go b/lib/color/gradient.go index 51dbde637..7aae4d0f4 100644 --- a/lib/color/gradient.go +++ b/lib/color/gradient.go @@ -9,6 +9,8 @@ import ( "regexp" "strconv" "strings" + + "github.com/mazznoer/csscolorparser" ) type Gradient struct { @@ -241,10 +243,15 @@ func UniqueGradientID(cssGradient string) string { return "grad-" + hash } -var GradientRegex = regexp.MustCompile(`^(linear|radial)-gradient\((.+)\)$`) - func IsGradient(color string) bool { - return GradientRegex.MatchString(color) + gradient, err := ParseGradient(color) + for _, colorStop := range gradient.ColorStops { + _, err = csscolorparser.Parse(colorStop.Color) + if err != nil { + break + } + } + return err == nil } var URLGradientID = regexp.MustCompile(`^url\('#grad-[a-f0-9]{40}'\)$`) From 1c41fd472ed6f79b4157635abbcd8f8215b9a4f7 Mon Sep 17 00:00:00 2001 From: melsonic Date: Wed, 16 Apr 2025 01:03:23 +0530 Subject: [PATCH 2/5] update next.md --- ci/release/changelogs/next.md | 1 + 1 file changed, 1 insertion(+) diff --git a/ci/release/changelogs/next.md b/ci/release/changelogs/next.md index 4a04e7e04..8cf883cff 100644 --- a/ci/release/changelogs/next.md +++ b/ci/release/changelogs/next.md @@ -21,6 +21,7 @@ - Compiler: - `link`s can be set to root path, e.g. `/xyz`. [#2357](https://github.com/terrastruct/d2/issues/2357) - When importing a file, attempt resolving substitutions at the imported file scope first [#2482](https://github.com/terrastruct/d2/pull/2482) + - validate gradient color stops. [#2492](https://github.com/terrastruct/d2/pull/2492) - Parser: - impose max key length. It's almost certainly a mistake if an ID gets too long, e.g. missing quotes [#2465](https://github.com/terrastruct/d2/pull/2465) - Render: From 9f66199777641ced6778d944e91a2e6834b6476b Mon Sep 17 00:00:00 2001 From: melsonic Date: Wed, 16 Apr 2025 01:03:52 +0530 Subject: [PATCH 3/5] add test .exp file --- .../TestCompile/invalid_gradient_color_stop.exp.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 testdata/d2compiler/TestCompile/invalid_gradient_color_stop.exp.json diff --git a/testdata/d2compiler/TestCompile/invalid_gradient_color_stop.exp.json b/testdata/d2compiler/TestCompile/invalid_gradient_color_stop.exp.json new file mode 100644 index 000000000..49f1fffea --- /dev/null +++ b/testdata/d2compiler/TestCompile/invalid_gradient_color_stop.exp.json @@ -0,0 +1,11 @@ +{ + "graph": null, + "err": { + "errs": [ + { + "range": "d2/testdata/d2compiler/TestCompile/invalid_gradient_color_stop.d2,2:18:25-2:47:54", + "errmsg": "d2/testdata/d2compiler/TestCompile/invalid_gradient_color_stop.d2:3:19: expected \"fill\" to be a valid named color (\"orange\"), a hex code (\"#f0ff3a\"), or a gradient (\"linear-gradient(red, blue)\")" + } + ] + } +} From 909eeb00afca58a712fd0a750073fe40a2756d16 Mon Sep 17 00:00:00 2001 From: melsonic Date: Fri, 18 Apr 2025 21:22:07 +0530 Subject: [PATCH 4/5] update gradient color stop validity check --- lib/color/color.go | 14 +++++++++++++- lib/color/gradient.go | 13 +++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/color/color.go b/lib/color/color.go index 7417a2b9d..95a15520a 100644 --- a/lib/color/color.go +++ b/lib/color/color.go @@ -512,7 +512,19 @@ var NamedColors = []string{ var ColorHexRegex = regexp.MustCompile(`^#(([0-9a-fA-F]{2}){3}|([0-9a-fA-F]){3})$`) func ValidColor(color string) bool { - if !go2.Contains(NamedColors, strings.ToLower(color)) && !ColorHexRegex.MatchString(color) && !IsGradient(color) { + + if IsGradient(color) { + gradient, err := ParseGradient(color) + for _, colorStop := range gradient.ColorStops { + _, err = csscolorparser.Parse(colorStop.Color) + if err != nil { + break + } + } + return err == nil + } + + if !go2.Contains(NamedColors, strings.ToLower(color)) && !ColorHexRegex.MatchString(color) { return false } diff --git a/lib/color/gradient.go b/lib/color/gradient.go index 7aae4d0f4..51dbde637 100644 --- a/lib/color/gradient.go +++ b/lib/color/gradient.go @@ -9,8 +9,6 @@ import ( "regexp" "strconv" "strings" - - "github.com/mazznoer/csscolorparser" ) type Gradient struct { @@ -243,15 +241,10 @@ func UniqueGradientID(cssGradient string) string { return "grad-" + hash } +var GradientRegex = regexp.MustCompile(`^(linear|radial)-gradient\((.+)\)$`) + func IsGradient(color string) bool { - gradient, err := ParseGradient(color) - for _, colorStop := range gradient.ColorStops { - _, err = csscolorparser.Parse(colorStop.Color) - if err != nil { - break - } - } - return err == nil + return GradientRegex.MatchString(color) } var URLGradientID = regexp.MustCompile(`^url\('#grad-[a-f0-9]{40}'\)$`) From 01e9a44fdfd8274e49b3eb82cb61db878b2522f1 Mon Sep 17 00:00:00 2001 From: melsonic Date: Mon, 21 Apr 2025 22:38:15 +0530 Subject: [PATCH 5/5] change err check flow --- lib/color/color.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lib/color/color.go b/lib/color/color.go index 95a15520a..701cc0b3d 100644 --- a/lib/color/color.go +++ b/lib/color/color.go @@ -512,19 +512,18 @@ var NamedColors = []string{ var ColorHexRegex = regexp.MustCompile(`^#(([0-9a-fA-F]{2}){3}|([0-9a-fA-F]){3})$`) func ValidColor(color string) bool { - if IsGradient(color) { gradient, err := ParseGradient(color) + if err != nil { + return false + } for _, colorStop := range gradient.ColorStops { _, err = csscolorparser.Parse(colorStop.Color) if err != nil { - break + return false } } - return err == nil - } - - if !go2.Contains(NamedColors, strings.ToLower(color)) && !ColorHexRegex.MatchString(color) { + } else if !go2.Contains(NamedColors, strings.ToLower(color)) && !ColorHexRegex.MatchString(color) { return false }