Fix push-to-create (#9772) (#9797)

* Fix push-to-create

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Check URL path and service

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Send dummy payload on receive-pack GET

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* The space was actually a NUL byte

Signed-off-by: jolheiser <john.olheiser@gmail.com>

* Use real bare repo instead of manufactured payload

Signed-off-by: jolheiser <john.olheiser@gmail.com>

Co-authored-by: zeripath <art27@cantab.net>
This commit is contained in:
John Olheiser 2020-01-15 23:40:37 -06:00 committed by Lauris BH
parent c8bb0ecf52
commit 3521177a34
1 changed files with 58 additions and 1 deletions

View File

@ -10,6 +10,7 @@ import (
"compress/gzip" "compress/gzip"
gocontext "context" gocontext "context"
"fmt" "fmt"
"io/ioutil"
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
@ -17,6 +18,7 @@ import (
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"sync"
"time" "time"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
@ -65,11 +67,12 @@ func HTTP(ctx *context.Context) {
return return
} }
var isPull bool var isPull, receivePack bool
service := ctx.Query("service") service := ctx.Query("service")
if service == "git-receive-pack" || if service == "git-receive-pack" ||
strings.HasSuffix(ctx.Req.URL.Path, "git-receive-pack") { strings.HasSuffix(ctx.Req.URL.Path, "git-receive-pack") {
isPull = false isPull = false
receivePack = true
} else if service == "git-upload-pack" || } else if service == "git-upload-pack" ||
strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") { strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") {
isPull = true isPull = true
@ -282,6 +285,11 @@ func HTTP(ctx *context.Context) {
} }
if !repoExist { if !repoExist {
if !receivePack {
ctx.HandleText(http.StatusNotFound, "Repository not found")
return
}
if owner.IsOrganization() && !setting.Repository.EnablePushCreateOrg { if owner.IsOrganization() && !setting.Repository.EnablePushCreateOrg {
ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for organizations.") ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for organizations.")
return return
@ -290,6 +298,13 @@ func HTTP(ctx *context.Context) {
ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for users.") ctx.HandleText(http.StatusForbidden, "Push to create is not enabled for users.")
return 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) repo, err = repo_service.PushCreateRepo(authUser, owner, reponame)
if err != nil { if err != nil {
log.Error("pushCreateRepo: %v", err) log.Error("pushCreateRepo: %v", err)
@ -352,6 +367,48 @@ func HTTP(ctx *context.Context) {
ctx.NotFound("Smart Git HTTP", nil) 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 { type serviceConfig struct {
UploadPack bool UploadPack bool
ReceivePack bool ReceivePack bool