Skip to content

Commit 719bde3

Browse files
committed
fix
1 parent 3ee39db commit 719bde3

File tree

4 files changed

+51
-31
lines changed

4 files changed

+51
-31
lines changed

modules/httplib/url.go

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,32 @@ import (
88
"strings"
99

1010
"code.gitea.io/gitea/modules/setting"
11+
"code.gitea.io/gitea/modules/util"
1112
)
1213

13-
// IsRiskyRedirectURL returns true if the URL is considered risky for redirects
14-
func IsRiskyRedirectURL(s string) bool {
14+
func isRelativeURL(u *url.URL) bool {
15+
return u.Scheme == "" && u.Host == ""
16+
}
17+
18+
// IsRelativeURL detects if a URL is relative (no scheme or host)
19+
func IsRelativeURL(s string) bool {
1520
// Unfortunately browsers consider a redirect Location with preceding "//", "\\", "/\" and "\/" as meaning redirect to "http(s)://REST_OF_PATH"
1621
// Therefore we should ignore these redirect locations to prevent open redirects
1722
if len(s) > 1 && (s[0] == '/' || s[0] == '\\') && (s[1] == '/' || s[1] == '\\') {
18-
return true
23+
return false
1924
}
20-
2125
u, err := url.Parse(s)
22-
if err != nil || ((u.Scheme != "" || u.Host != "") && !strings.HasPrefix(strings.ToLower(s), strings.ToLower(setting.AppURL))) {
26+
return err == nil && isRelativeURL(u)
27+
}
28+
29+
func IsCurrentGiteaSiteURL(s string) bool {
30+
if IsRelativeURL(s) {
2331
return true
2432
}
25-
26-
return false
33+
u, err := url.Parse(s)
34+
if err != nil {
35+
return false
36+
}
37+
u.Path = util.PathJoinRelX(u.Path)
38+
return strings.HasPrefix(strings.ToLower(u.String()+"/"), strings.ToLower(setting.AppURL))
2739
}

modules/httplib/url_test.go

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,40 @@ import (
77
"testing"
88

99
"code.gitea.io/gitea/modules/setting"
10+
"code.gitea.io/gitea/modules/test"
1011

1112
"github.com/stretchr/testify/assert"
1213
)
1314

14-
func TestIsRiskyRedirectURL(t *testing.T) {
15-
setting.AppURL = "http://localhost:3000/"
16-
tests := []struct {
17-
input string
18-
want bool
19-
}{
20-
{"", false},
21-
{"foo", false},
22-
{"/", false},
23-
{"/foo?k=%20#abc", false},
24-
25-
{"//", true},
26-
{"\\\\", true},
27-
{"/\\", true},
28-
{"\\/", true},
29-
{"mail:[email protected]", true},
30-
{"https://test.com", true},
31-
{setting.AppURL + "/foo", false},
15+
func TestIsRelativeURL(t *testing.T) {
16+
rel := []string{
17+
"",
18+
"foo",
19+
"/",
20+
"/foo?k=%20#abc",
21+
}
22+
for _, s := range rel {
23+
assert.True(t, IsRelativeURL(s), "rel = %q", s)
24+
}
25+
abs := []string{
26+
"//",
27+
"\\\\",
28+
"/\\",
29+
"\\/",
30+
31+
"https://test.com",
3232
}
33-
for _, tt := range tests {
34-
t.Run(tt.input, func(t *testing.T) {
35-
assert.Equal(t, tt.want, IsRiskyRedirectURL(tt.input))
36-
})
33+
for _, s := range abs {
34+
assert.False(t, IsRelativeURL(s), "abs = %q", s)
3735
}
3836
}
37+
38+
func TestIsCurrentGiteaSiteURL(t *testing.T) {
39+
defer test.MockVariableValue(&setting.AppURL, "http://localhost:3000/sub/")()
40+
assert.True(t, IsCurrentGiteaSiteURL("/foo"))
41+
assert.True(t, IsCurrentGiteaSiteURL("http://localhost:3000/sub"))
42+
assert.True(t, IsCurrentGiteaSiteURL("http://localhost:3000/sub/"))
43+
assert.False(t, IsCurrentGiteaSiteURL("http://localhost:3000/sub/.."))
44+
assert.False(t, IsCurrentGiteaSiteURL("http://localhost:3000/other"))
45+
assert.False(t, IsCurrentGiteaSiteURL("http://other/"))
46+
}

routers/common/redirect.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func FetchRedirectDelegate(resp http.ResponseWriter, req *http.Request) {
1717
// The typical page is "issue comment" page. The backend responds "/owner/repo/issues/1#comment-2",
1818
// then frontend needs this delegate to redirect to the new location with hash correctly.
1919
redirect := req.PostFormValue("redirect")
20-
if httplib.IsRiskyRedirectURL(redirect) {
20+
if !httplib.IsCurrentGiteaSiteURL(redirect) {
2121
resp.WriteHeader(http.StatusBadRequest)
2222
return
2323
}

services/context/context_response.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func (ctx *Context) RedirectToFirst(location ...string) {
5151
continue
5252
}
5353

54-
if httplib.IsRiskyRedirectURL(loc) {
54+
if !httplib.IsCurrentGiteaSiteURL(loc) {
5555
continue
5656
}
5757

0 commit comments

Comments
 (0)