Skip to content

Commit da05799

Browse files
lunny6543
andauthored
Fix http path bug (#16117)
* Fix http path bug * Add missed request * add tests Co-authored-by: 6543 <[email protected]>
1 parent 1bfb0a2 commit da05799

File tree

3 files changed

+131
-0
lines changed

3 files changed

+131
-0
lines changed

integrations/git_smart_http_test.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// Copyright 2021 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package integrations
6+
7+
import (
8+
"io/ioutil"
9+
"net/http"
10+
"net/url"
11+
"testing"
12+
13+
"github.com/stretchr/testify/assert"
14+
)
15+
16+
func TestGitSmartHTTP(t *testing.T) {
17+
onGiteaRun(t, testGitSmartHTTP)
18+
}
19+
20+
func testGitSmartHTTP(t *testing.T, u *url.URL) {
21+
var kases = []struct {
22+
p string
23+
code int
24+
}{
25+
{
26+
p: "user2/repo1/info/refs",
27+
code: 200,
28+
},
29+
{
30+
p: "user2/repo1/HEAD",
31+
code: 200,
32+
},
33+
{
34+
p: "user2/repo1/objects/info/alternates",
35+
code: 404,
36+
},
37+
{
38+
p: "user2/repo1/objects/info/http-alternates",
39+
code: 404,
40+
},
41+
{
42+
p: "user2/repo1/../../custom/conf/app.ini",
43+
code: 404,
44+
},
45+
{
46+
p: "user2/repo1/objects/info/../../../../custom/conf/app.ini",
47+
code: 404,
48+
},
49+
{
50+
p: `user2/repo1/objects/info/..\..\..\..\custom\conf\app.ini`,
51+
code: 400,
52+
},
53+
}
54+
55+
for _, kase := range kases {
56+
t.Run(kase.p, func(t *testing.T) {
57+
p := u.String() + kase.p
58+
req, err := http.NewRequest("GET", p, nil)
59+
assert.NoError(t, err)
60+
req.SetBasicAuth("user2", userPassword)
61+
resp, err := http.DefaultClient.Do(req)
62+
assert.NoError(t, err)
63+
defer resp.Body.Close()
64+
assert.EqualValues(t, kase.code, resp.StatusCode)
65+
_, err = ioutil.ReadAll(resp.Body)
66+
assert.NoError(t, err)
67+
})
68+
}
69+
}

routers/web/repo/http.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,26 @@ func (h *serviceHandler) setHeaderCacheForever() {
366366
h.w.Header().Set("Cache-Control", "public, max-age=31536000")
367367
}
368368

369+
func containsParentDirectorySeparator(v string) bool {
370+
if !strings.Contains(v, "..") {
371+
return false
372+
}
373+
for _, ent := range strings.FieldsFunc(v, isSlashRune) {
374+
if ent == ".." {
375+
return true
376+
}
377+
}
378+
return false
379+
}
380+
381+
func isSlashRune(r rune) bool { return r == '/' || r == '\\' }
382+
369383
func (h *serviceHandler) sendFile(contentType, file string) {
384+
if containsParentDirectorySeparator(file) {
385+
log.Error("request file path contains invalid path: %v", file)
386+
h.w.WriteHeader(http.StatusBadRequest)
387+
return
388+
}
370389
reqFile := path.Join(h.dir, file)
371390

372391
fi, err := os.Stat(reqFile)

routers/web/repo/http_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2021 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package repo
6+
7+
import (
8+
"testing"
9+
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestContainsParentDirectorySeparator(t *testing.T) {
14+
tests := []struct {
15+
v string
16+
b bool
17+
}{
18+
{
19+
v: `user2/repo1/info/refs`,
20+
b: false,
21+
},
22+
{
23+
v: `user2/repo1/HEAD`,
24+
b: false,
25+
},
26+
{
27+
v: `user2/repo1/some.../strange_file...mp3`,
28+
b: false,
29+
},
30+
{
31+
v: `user2/repo1/../../custom/conf/app.ini`,
32+
b: true,
33+
},
34+
{
35+
v: `user2/repo1/objects/info/..\..\..\..\custom\conf\app.ini`,
36+
b: true,
37+
},
38+
}
39+
40+
for i := range tests {
41+
assert.EqualValues(t, tests[i].b, containsParentDirectorySeparator(tests[i].v))
42+
}
43+
}

0 commit comments

Comments
 (0)