Correctly handle submodule view and avoid throwing 500 error (#34121)

Auto-redirect for in-site links, and show 404 for external links
(to avoid open redirect or phishing)
This commit is contained in:
wxiaoguang 2025-04-06 17:38:08 +08:00 committed by GitHub
parent a62ed19da6
commit e94f8d56f1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 59 additions and 0 deletions

View File

@ -20,6 +20,8 @@ import (
unit_model "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
giturl "code.gitea.io/gitea/modules/git/url"
"code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/log"
repo_module "code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
@ -302,8 +304,33 @@ func handleRepoEmptyOrBroken(ctx *context.Context) {
ctx.Redirect(link)
}
func handleRepoViewSubmodule(ctx *context.Context, submodule *git.SubModule) {
submoduleRepoURL, err := giturl.ParseRepositoryURL(ctx, submodule.URL)
if err != nil {
HandleGitError(ctx, "prepareToRenderDirOrFile: ParseRepositoryURL", err)
return
}
submoduleURL := giturl.MakeRepositoryWebLink(submoduleRepoURL)
if httplib.IsCurrentGiteaSiteURL(ctx, submoduleURL) {
ctx.RedirectToCurrentSite(submoduleURL)
} else {
// don't auto-redirect to external URL, to avoid open redirect or phishing
ctx.Data["NotFoundPrompt"] = submoduleURL
ctx.NotFound(nil)
}
}
func prepareToRenderDirOrFile(entry *git.TreeEntry) func(ctx *context.Context) {
return func(ctx *context.Context) {
if entry.IsSubModule() {
submodule, err := ctx.Repo.Commit.GetSubModule(entry.Name())
if err != nil {
HandleGitError(ctx, "prepareToRenderDirOrFile: GetSubModule", err)
return
}
handleRepoViewSubmodule(ctx, submodule)
return
}
if entry.IsDir() {
prepareToRenderDirectory(ctx)
} else {

View File

@ -0,0 +1,32 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package repo
import (
"net/http"
"testing"
"code.gitea.io/gitea/models/unittest"
git_module "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/contexttest"
"github.com/stretchr/testify/assert"
)
func TestViewHomeSubmoduleRedirect(t *testing.T) {
unittest.PrepareTestEnv(t)
ctx, _ := contexttest.MockContext(t, "/user2/repo1/src/branch/master/test-submodule")
submodule := &git_module.SubModule{Path: "test-submodule", URL: setting.AppURL + "user2/repo-other.git"}
handleRepoViewSubmodule(ctx, submodule)
assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
assert.Equal(t, "/user2/repo-other", ctx.Resp.Header().Get("Location"))
ctx, _ = contexttest.MockContext(t, "/user2/repo1/src/branch/master/test-submodule")
submodule = &git_module.SubModule{Path: "test-submodule", URL: "https://other/user2/repo-other.git"}
handleRepoViewSubmodule(ctx, submodule)
// do not auto-redirect for external URLs, to avoid open redirect or phishing
assert.Equal(t, http.StatusNotFound, ctx.Resp.WrittenStatus())
}