From 176e7fb5d54aff955eef863f62cc232eaf8eb590 Mon Sep 17 00:00:00 2001 From: John Olheiser <42128690+jolheiser@users.noreply.github.com> Date: Wed, 15 Jan 2020 20:40:13 -0600 Subject: [PATCH] Fix push-to-create (#9772) * Fix push-to-create Signed-off-by: jolheiser * Check URL path and service Signed-off-by: jolheiser * Send dummy payload on receive-pack GET Signed-off-by: jolheiser * The space was actually a NUL byte Signed-off-by: jolheiser * Use real bare repo instead of manufactured payload Signed-off-by: jolheiser --- routers/repo/http.go | 59 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/routers/repo/http.go b/routers/repo/http.go index b97feed51d9..d0a2b289b71 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -10,6 +10,7 @@ import ( "compress/gzip" gocontext "context" "fmt" + "io/ioutil" "net/http" "os" "os/exec" @@ -17,6 +18,7 @@ import ( "regexp" "strconv" "strings" + "sync" "time" "code.gitea.io/gitea/models" @@ -65,11 +67,12 @@ func HTTP(ctx *context.Context) { return } - var isPull bool + var isPull, receivePack bool service := ctx.Query("service") if service == "git-receive-pack" || strings.HasSuffix(ctx.Req.URL.Path, "git-receive-pack") { isPull = false + receivePack = true } else if service == "git-upload-pack" || strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") { isPull = true @@ -282,6 +285,11 @@ func HTTP(ctx *context.Context) { } if !repoExist { + if !receivePack { + ctx.HandleText(http.StatusNotFound, "Repository not found") + return + } + if owner.IsOrganization() && !setting.Repository.EnablePushCreateOrg { ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for organizations.") return @@ -290,6 +298,13 @@ func HTTP(ctx *context.Context) { ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for users.") return } + + // Return dummy payload if GET receive-pack + if ctx.Req.Method == http.MethodGet { + dummyInfoRefs(ctx) + return + } + repo, err = repo_service.PushCreateRepo(authUser, owner, reponame) if err != nil { log.Error("pushCreateRepo: %v", err) @@ -352,6 +367,48 @@ func HTTP(ctx *context.Context) { ctx.NotFound("Smart Git HTTP", nil) } +var ( + infoRefsCache []byte + infoRefsOnce sync.Once +) + +func dummyInfoRefs(ctx *context.Context) { + infoRefsOnce.Do(func() { + tmpDir, err := ioutil.TempDir(os.TempDir(), "gitea-info-refs-cache") + if err != nil { + log.Error("Failed to create temp dir for git-receive-pack cache: %v", err) + return + } + + defer func() { + if err := os.RemoveAll(tmpDir); err != nil { + log.Error("RemoveAll: %v", err) + } + }() + + if err := git.InitRepository(tmpDir, true); err != nil { + log.Error("Failed to init bare repo for git-receive-pack cache: %v", err) + return + } + + refs, err := git.NewCommand("receive-pack", "--stateless-rpc", "--advertise-refs", ".").RunInDirBytes(tmpDir) + if err != nil { + log.Error(fmt.Sprintf("%v - %s", err, string(refs))) + } + + log.Debug("populating infoRefsCache: \n%s", string(refs)) + infoRefsCache = refs + }) + + ctx.Header().Set("Expires", "Fri, 01 Jan 1980 00:00:00 GMT") + ctx.Header().Set("Pragma", "no-cache") + ctx.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate") + ctx.Header().Set("Content-Type", "application/x-git-receive-pack-advertisement") + _, _ = ctx.Write(packetWrite("# service=git-receive-pack\n")) + _, _ = ctx.Write([]byte("0000")) + _, _ = ctx.Write(infoRefsCache) +} + type serviceConfig struct { UploadPack bool ReceivePack bool