From 857b1ca41a5d6919a06f234a2f252ca0810cecc3 Mon Sep 17 00:00:00 2001 From: Gergely Brautigam Date: Tue, 10 Mar 2020 20:15:57 +0100 Subject: [PATCH] Check name for invalid characters --- handlers/pipeline_test.go | 29 +++++++++++++++++++++++++++-- workers/pipeline/create_pipeline.go | 16 ++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/handlers/pipeline_test.go b/handlers/pipeline_test.go index 45ba3451..3e9ce593 100644 --- a/handlers/pipeline_test.go +++ b/handlers/pipeline_test.go @@ -779,8 +779,8 @@ func TestPipelineCheckPeriodicSchedules(t *testing.T) { }) } -func TestPipelineNameAvailable(t *testing.T) { - tmp, _ := ioutil.TempDir("", "TestPipelineNameAvailable") +func TestPipelineNameValidation(t *testing.T) { + tmp, _ := ioutil.TempDir("", "TestPipelineNameValidation") dataDir := tmp gaia.Cfg = &gaia.Config{ @@ -870,6 +870,31 @@ func TestPipelineNameAvailable(t *testing.T) { } }) + t.Run("fails for pipeline name with invalid character", func(t *testing.T) { + req := httptest.NewRequest(echo.GET, "/", nil) + req.Header.Set("Content-Type", "application/json") + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + c.SetPath("/api/" + gaia.APIVersion + "/pipeline/name") + q := req.URL.Query() + q.Add("name", "this[]isinvalid;") + req.URL.RawQuery = q.Encode() + + _ = PipelineNameAvailable(c) + + if rec.Code != http.StatusBadRequest { + t.Fatalf("expected response code %v got %v", http.StatusBadRequest, rec.Code) + } + bodyBytes, err := ioutil.ReadAll(rec.Body) + if err != nil { + t.Fatalf("cannot read response body: %s", err.Error()) + } + nameContainsInvalidCharacter := "pipeline name invalid; must match [A-z][0-9][-][_]" + if string(bodyBytes[:]) != nameContainsInvalidCharacter { + t.Fatalf("error message should be '%s' but was '%s'", nameContainsInvalidCharacter, string(bodyBytes[:])) + } + }) + t.Run("works for pipeline with different name", func(t *testing.T) { req := httptest.NewRequest(echo.GET, "/", nil) req.Header.Set("Content-Type", "application/json") diff --git a/workers/pipeline/create_pipeline.go b/workers/pipeline/create_pipeline.go index ebcd3a19..e8733e23 100644 --- a/workers/pipeline/create_pipeline.go +++ b/workers/pipeline/create_pipeline.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "strings" + "unicode" "github.com/gaia-pipeline/gaia/security" @@ -34,6 +35,9 @@ var ( // errPipelineNameInUse is thrown when a pipelines name is already in use errPipelineNameInUse = errors.New("pipeline name is already in use") + + // errPipelineNameInvalid is thrown when a pipeline's name does not match required restrictions + errPipelineNameInvalid = errors.New("pipeline name invalid; must match [A-z][0-9][-][_]") ) // CreatePipeline is the main function which executes step by step the creation @@ -166,6 +170,18 @@ func CreatePipeline(p *gaia.CreatePipeline) { // ValidatePipelineName validates a given pipeline name and // returns the correct error back. func ValidatePipelineName(pName string) error { + + validate := func(r rune) bool { + return unicode.IsDigit(r) || unicode.IsLetter(r) || unicode.IsSpace(r) || r == '-' || r == '_' + } + // Name must match ^[A-z]+|[0-9]+|[-]+|[_]+$ + // Note, this is faster than regex. + for _, c := range pName { + if !validate(c) { + return errPipelineNameInvalid + } + } + // The name could contain a path. Split it up. path := strings.Split(pName, pipelinePathSplitChar)