godev/cmd/telemetrygodev: validate dates  in /charts/... endpoint

General security hardening:

Don't try looking up arbitrary values, only actual dates.

Change-Id: Ibe395b312c3335fdd19f3a310f8f83b46a6a6964
Reviewed-on: https://go-review.googlesource.com/c/telemetry/+/848191
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
Auto-Submit: Damien Neil <dneil@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/godev/cmd/telemetrygodev/main.go b/godev/cmd/telemetrygodev/main.go
index 8794075..b8ebf38 100644
--- a/godev/cmd/telemetrygodev/main.go
+++ b/godev/cmd/telemetrygodev/main.go
@@ -218,6 +218,9 @@
 func handleChart(render renderer, chartBucket storage.BucketHandle) content.HandlerFunc {
 	return func(w http.ResponseWriter, r *http.Request) error {
 		date := r.PathValue("date") // may be a range -- 2025-05-20_2025-05-27
+		if !validChartDate(date) {
+			return content.Error(fmt.Errorf("invalid chart date: %q", date), http.StatusBadRequest)
+		}
 		page := chartPage{Date: date}
 		var err error
 		objName := date + ".json"
@@ -232,6 +235,19 @@
 	}
 }
 
+func validChartDate(date string) bool {
+	start, end, aggregate := strings.Cut(date, "_")
+	if _, err := time.Parse(telemetry.DateOnly, start); err != nil {
+		return false
+	}
+	if aggregate {
+		if _, err := time.Parse(telemetry.DateOnly, end); err != nil {
+			return false
+		}
+	}
+	return true
+}
+
 type dataPage struct {
 	Dates []string
 }
diff --git a/godev/cmd/telemetrygodev/main_test.go b/godev/cmd/telemetrygodev/main_test.go
index 769fb7a..c1fd134 100644
--- a/godev/cmd/telemetrygodev/main_test.go
+++ b/godev/cmd/telemetrygodev/main_test.go
@@ -109,6 +109,10 @@
 		{"GET", "/", "", 200, []string{"Go Telemetry"}},
 		{"GET", "/privacy", "", 200, []string{"Privacy Policy"}},
 		{"GET", "/config", "", 200, []string{"Chart Config"}},
+		{"GET", "/charts/2023-01-01", "", 404, nil},
+		{"GET", "/charts/2023-01-01_2023-01-07", "", 404, nil},
+		{"GET", "/charts/invalid", "", 400, nil},
+		{"GET", "/charts/..%2Fconfig", "", 400, nil},
 		{
 			"POST",
 			"/upload/2023-01-01/123.json",