From 80f22ab0d8ac8aa24fc559eb1b80bee16f1c0b8d Mon Sep 17 00:00:00 2001 From: Gusted Date: Sat, 30 Mar 2024 14:30:41 +0100 Subject: [PATCH] [BUG] Don't color dot literal color names - Colordots are generated for colors in inline code, such as `red`, `rgb(255, 0, 124)`, `#ffaabb` and `hsl(124, 52%, 50%)`. However this shouldn't be doon for literal color names as these can be too common assiocated with non-color related stuff _and matches the behavior of some other forge_. - Move the regexes from bluemonday to Forgejo and do the checking ourselves. - Adds unit tests. - Resolves https://codeberg.org/Codeberg/Community/issues/1510 --- modules/markup/markdown/color_util.go | 19 ++++++++ modules/markup/markdown/color_util_test.go | 50 ++++++++++++++++++++++ modules/markup/markdown/goldmark.go | 3 +- 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 modules/markup/markdown/color_util.go create mode 100644 modules/markup/markdown/color_util_test.go diff --git a/modules/markup/markdown/color_util.go b/modules/markup/markdown/color_util.go new file mode 100644 index 0000000000..355fef3fc0 --- /dev/null +++ b/modules/markup/markdown/color_util.go @@ -0,0 +1,19 @@ +// Copyright 2024 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package markdown + +import "regexp" + +var ( + hexRGB = regexp.MustCompile(`^#([0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$`) + hsl = regexp.MustCompile(`^hsl\([ ]*([012]?[0-9]{1,2}|3[0-5][0-9]|360),[ ]*([0-9]{0,2}|100)\%,[ ]*([0-9]{0,2}|100)\%\)$`) + hsla = 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]+))\)$`) + rgb = 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]))))\)$`) + rgba = 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]+))\)$`) +) + +// matchColor return if color is in the form of hex RGB, HSL(A) or RGB(A). +func matchColor(color string) bool { + return hexRGB.MatchString(color) || rgb.MatchString(color) || rgba.MatchString(color) || hsl.MatchString(color) || hsla.MatchString(color) +} diff --git a/modules/markup/markdown/color_util_test.go b/modules/markup/markdown/color_util_test.go new file mode 100644 index 0000000000..c6e0555a35 --- /dev/null +++ b/modules/markup/markdown/color_util_test.go @@ -0,0 +1,50 @@ +// Copyright 2024 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package markdown + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMatchColor(t *testing.T) { + testCases := []struct { + input string + expected bool + }{ + {"#ddeeffa0", true}, + {"#ddeefe", true}, + {"#abcdef", true}, + {"#abcdeg", false}, + {"#abcdefg0", false}, + {"black", false}, + {"violet", false}, + {"rgb(255, 255, 255)", true}, + {"rgb(0, 0, 0)", true}, + {"rgb(256, 0, 0)", false}, + {"rgb(0, 256, 0)", false}, + {"rgb(0, 0, 256)", false}, + {"rgb(0, 0, 0, 1)", false}, + {"rgba(0, 0, 0)", false}, + {"rgba(0, 255, 0, 1)", true}, + {"rgba(32, 255, 12, 0.55)", true}, + {"rgba(32, 256, 12, 0.55)", false}, + {"hsl(0, 0%, 0%)", true}, + {"hsl(360, 100%, 100%)", true}, + {"hsl(361, 100%, 50%)", false}, + {"hsl(360, 101%, 50%)", false}, + {"hsl(360, 100%, 101%)", false}, + {"hsl(0, 0%, 0%, 0)", false}, + {"hsla(0, 0%, 0%)", false}, + {"hsla(0, 0%, 0%, 0)", true}, + {"hsla(0, 0%, 0%, 1)", true}, + {"hsla(0, 0%, 0%, 0.5)", true}, + {"hsla(0, 0%, 0%, 1.5)", false}, + } + for _, testCase := range testCases { + actual := matchColor(testCase.input) + assert.Equal(t, testCase.expected, actual) + } +} diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index 7ada8b5548..5a481a31fd 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -16,7 +16,6 @@ import ( "code.gitea.io/gitea/modules/setting" giteautil "code.gitea.io/gitea/modules/util" - "github.com/microcosm-cc/bluemonday/css" "github.com/yuin/goldmark/ast" east "github.com/yuin/goldmark/extension/ast" "github.com/yuin/goldmark/parser" @@ -199,7 +198,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa } case *ast.CodeSpan: colorContent := n.Text(reader.Source()) - if css.ColorHandler(strings.ToLower(string(colorContent))) { + if matchColor(strings.ToLower(string(colorContent))) { v.AppendChild(v, NewColorPreview(colorContent)) } }