From 47d69b7749689a7a7570ac20bdfd30d336daf7c1 Mon Sep 17 00:00:00 2001 From: Kemal Zebari <60799661+kemzeb@users.noreply.github.com> Date: Sat, 7 Jun 2025 01:25:08 -0700 Subject: [PATCH] Validate hex colors when creating/editing labels (#34623) Resolves #34618. --------- Co-authored-by: Lunny Xiao Co-authored-by: wxiaoguang --- modules/label/label.go | 14 ++- modules/test/utils.go | 10 ++ options/locale/locale_en-US.ini | 2 +- routers/web/org/org_labels.go | 36 ++++--- routers/web/repo/issue_label.go | 38 ++++---- routers/web/repo/issue_label_test.go | 94 +++++++++++++------ routers/web/shared/label/label.go | 26 +++++ .../repo/issue/labels/label_edit_modal.tmpl | 5 +- web_src/js/features/comp/LabelEdit.ts | 2 +- 9 files changed, 151 insertions(+), 76 deletions(-) create mode 100644 routers/web/shared/label/label.go diff --git a/modules/label/label.go b/modules/label/label.go index ce028aa9f3..3e68c4d26e 100644 --- a/modules/label/label.go +++ b/modules/label/label.go @@ -7,10 +7,10 @@ import ( "fmt" "regexp" "strings" -) + "sync" -// colorPattern is a regexp which can validate label color -var colorPattern = regexp.MustCompile("^#?(?:[0-9a-fA-F]{6}|[0-9a-fA-F]{3})$") + "code.gitea.io/gitea/modules/util" +) // Label represents label information loaded from template type Label struct { @@ -21,6 +21,10 @@ type Label struct { ExclusiveOrder int `yaml:"exclusive_order,omitempty"` } +var colorPattern = sync.OnceValue(func() *regexp.Regexp { + return regexp.MustCompile(`^#([\da-fA-F]{3}|[\da-fA-F]{6})$`) +}) + // NormalizeColor normalizes a color string to a 6-character hex code func NormalizeColor(color string) (string, error) { // normalize case @@ -31,8 +35,8 @@ func NormalizeColor(color string) (string, error) { color = "#" + color } - if !colorPattern.MatchString(color) { - return "", fmt.Errorf("bad color code: %s", color) + if !colorPattern().MatchString(color) { + return "", util.NewInvalidArgumentErrorf("invalid color: %s", color) } // convert 3-character shorthand into 6-character version diff --git a/modules/test/utils.go b/modules/test/utils.go index 3051d3d286..53c6a3ed52 100644 --- a/modules/test/utils.go +++ b/modules/test/utils.go @@ -17,6 +17,7 @@ import ( // RedirectURL returns the redirect URL of a http response. // It also works for JSONRedirect: `{"redirect": "..."}` +// FIXME: it should separate the logic of checking from header and JSON body func RedirectURL(resp http.ResponseWriter) string { loc := resp.Header().Get("Location") if loc != "" { @@ -34,6 +35,15 @@ func RedirectURL(resp http.ResponseWriter) string { return "" } +func ParseJSONError(buf []byte) (ret struct { + ErrorMessage string `json:"errorMessage"` + RenderFormat string `json:"renderFormat"` +}, +) { + _ = json.Unmarshal(buf, &ret) + return ret +} + func IsNormalPageCompleted(s string) bool { return strings.Contains(s, `