From d2bd1589fedd4baa371d5c8d9a1872d9a2cf3cba Mon Sep 17 00:00:00 2001 From: TowyTowy <85077986+TowyTowy@users.noreply.github.com> Date: Sun, 12 Jul 2026 15:38:34 +0200 Subject: [PATCH] fix(util): reject invalid characters between time-estimate units (#38416) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What / why `TimeEstimateParse` (used by the issue time-estimate form) only checked that the first token starts at the beginning of the string and the last token ends at its end, but never checked the gaps between consecutive tokens. Non-whitespace garbage embedded between two valid units was silently dropped and the string accepted with a wrong value instead of being reported as invalid. Examples that were wrongly accepted before this change: - `1h 2x 3m` → 3780s (parsed as 1h3m) - `1h_2m` → 3720s - `1h,1m` → 3660s All three now return an "invalid time string" error, while valid inputs such as `1h 1m 1s` and `1h1m1s` keep working. ### How Reject any non-whitespace content between two matched units. --------- Signed-off-by: TowyTowy Signed-off-by: wxiaoguang Co-authored-by: wxiaoguang --- modules/util/time_str.go | 7 +++++++ modules/util/time_str_test.go | 3 +++ 2 files changed, 10 insertions(+) diff --git a/modules/util/time_str.go b/modules/util/time_str.go index 81b132c3db3..c498e6ebe13 100644 --- a/modules/util/time_str.go +++ b/modules/util/time_str.go @@ -40,6 +40,7 @@ var timeStrGlobalVars = sync.OnceValue(func() *timeStrGlobalVarsType { }) func TimeEstimateParse(timeStr string) (int64, error) { + timeStr = strings.TrimSpace(timeStr) if timeStr == "" { return 0, nil } @@ -51,7 +52,13 @@ func TimeEstimateParse(timeStr string) (int64, error) { if matches[0][0] != 0 || matches[len(matches)-1][1] != len(timeStr) { return 0, fmt.Errorf("invalid time string: %s", timeStr) } + prevEnd := 0 for _, match := range matches { + // only whitespace may separate two units, otherwise the string contains invalid content like "1h x 2m" + if strings.TrimSpace(timeStr[prevEnd:match[0]]) != "" { + return 0, fmt.Errorf("invalid time string: %s", timeStr) + } + prevEnd = match[1] amount, err := strconv.ParseInt(timeStr[match[2]:match[3]], 10, 64) if err != nil { return 0, fmt.Errorf("invalid time string: %v", err) diff --git a/modules/util/time_str_test.go b/modules/util/time_str_test.go index 8d1de51c8e6..4efe902bee5 100644 --- a/modules/util/time_str_test.go +++ b/modules/util/time_str_test.go @@ -22,6 +22,9 @@ func TestTimeStr(t *testing.T) { {"1s", 1, false}, {"1h 1m 1s", 3600 + 60 + 1, false}, {"1d1x", 0, true}, + {"1h 2x 3m", 0, true}, + {"1h_2m", 0, true}, + {"1h,1m", 0, true}, } for _, test := range tests { t.Run(test.input, func(t *testing.T) {