]> source.dussan.org Git - gitea.git/commitdiff
Fix http path bug (#16117)
authorLunny Xiao <xiaolunwen@gmail.com>
Wed, 9 Jun 2021 12:53:12 +0000 (20:53 +0800)
committerGitHub <noreply@github.com>
Wed, 9 Jun 2021 12:53:12 +0000 (14:53 +0200)
* Fix http path bug

* Add missed request

* add tests

Co-authored-by: 6543 <6543@obermui.de>
integrations/git_smart_http_test.go [new file with mode: 0644]
routers/web/repo/http.go
routers/web/repo/http_test.go [new file with mode: 0644]

diff --git a/integrations/git_smart_http_test.go b/integrations/git_smart_http_test.go
new file mode 100644 (file)
index 0000000..9a4e368
--- /dev/null
@@ -0,0 +1,69 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package integrations
+
+import (
+       "io/ioutil"
+       "net/http"
+       "net/url"
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+)
+
+func TestGitSmartHTTP(t *testing.T) {
+       onGiteaRun(t, testGitSmartHTTP)
+}
+
+func testGitSmartHTTP(t *testing.T, u *url.URL) {
+       var kases = []struct {
+               p    string
+               code int
+       }{
+               {
+                       p:    "user2/repo1/info/refs",
+                       code: 200,
+               },
+               {
+                       p:    "user2/repo1/HEAD",
+                       code: 200,
+               },
+               {
+                       p:    "user2/repo1/objects/info/alternates",
+                       code: 404,
+               },
+               {
+                       p:    "user2/repo1/objects/info/http-alternates",
+                       code: 404,
+               },
+               {
+                       p:    "user2/repo1/../../custom/conf/app.ini",
+                       code: 404,
+               },
+               {
+                       p:    "user2/repo1/objects/info/../../../../custom/conf/app.ini",
+                       code: 404,
+               },
+               {
+                       p:    `user2/repo1/objects/info/..\..\..\..\custom\conf\app.ini`,
+                       code: 400,
+               },
+       }
+
+       for _, kase := range kases {
+               t.Run(kase.p, func(t *testing.T) {
+                       p := u.String() + kase.p
+                       req, err := http.NewRequest("GET", p, nil)
+                       assert.NoError(t, err)
+                       req.SetBasicAuth("user2", userPassword)
+                       resp, err := http.DefaultClient.Do(req)
+                       assert.NoError(t, err)
+                       defer resp.Body.Close()
+                       assert.EqualValues(t, kase.code, resp.StatusCode)
+                       _, err = ioutil.ReadAll(resp.Body)
+                       assert.NoError(t, err)
+               })
+       }
+}
index 30d382b8ef18d5fa0f3fc53ed4d89fb04be3cd26..649d6d1eb1a35c3fd36332f6f2cfcc048e1cf39b 100644 (file)
@@ -366,7 +366,26 @@ func (h *serviceHandler) setHeaderCacheForever() {
        h.w.Header().Set("Cache-Control", "public, max-age=31536000")
 }
 
+func containsParentDirectorySeparator(v string) bool {
+       if !strings.Contains(v, "..") {
+               return false
+       }
+       for _, ent := range strings.FieldsFunc(v, isSlashRune) {
+               if ent == ".." {
+                       return true
+               }
+       }
+       return false
+}
+
+func isSlashRune(r rune) bool { return r == '/' || r == '\\' }
+
 func (h *serviceHandler) sendFile(contentType, file string) {
+       if containsParentDirectorySeparator(file) {
+               log.Error("request file path contains invalid path: %v", file)
+               h.w.WriteHeader(http.StatusBadRequest)
+               return
+       }
        reqFile := path.Join(h.dir, file)
 
        fi, err := os.Stat(reqFile)
diff --git a/routers/web/repo/http_test.go b/routers/web/repo/http_test.go
new file mode 100644 (file)
index 0000000..58ac1c0
--- /dev/null
@@ -0,0 +1,43 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package repo
+
+import (
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+)
+
+func TestContainsParentDirectorySeparator(t *testing.T) {
+       tests := []struct {
+               v string
+               b bool
+       }{
+               {
+                       v: `user2/repo1/info/refs`,
+                       b: false,
+               },
+               {
+                       v: `user2/repo1/HEAD`,
+                       b: false,
+               },
+               {
+                       v: `user2/repo1/some.../strange_file...mp3`,
+                       b: false,
+               },
+               {
+                       v: `user2/repo1/../../custom/conf/app.ini`,
+                       b: true,
+               },
+               {
+                       v: `user2/repo1/objects/info/..\..\..\..\custom\conf\app.ini`,
+                       b: true,
+               },
+       }
+
+       for i := range tests {
+               assert.EqualValues(t, tests[i].b, containsParentDirectorySeparator(tests[i].v))
+       }
+}