diff options
author | Denis Denisov <denji@users.noreply.github.com> | 2017-02-21 17:02:10 +0200 |
---|---|---|
committer | Lunny Xiao <xiaolunwen@gmail.com> | 2017-02-21 23:02:10 +0800 |
commit | fd941db246e66244ec81f43d74b8358c06173fd6 (patch) | |
tree | be563ff04f3b809b2d11489447086d5251e9b55a /routers/repo/http.go | |
parent | fe5ff8e4b2b3c951fa85572f3760ee2a396247ac (diff) | |
download | gitea-fd941db246e66244ec81f43d74b8358c06173fd6.tar.gz gitea-fd941db246e66244ec81f43d74b8358c06173fd6.zip |
Protected branches system (#339)
* Protected branches system
* Moved default branch to branches section (`:org/:reponame/settings/branches`).
* Initial support Protected Branch.
- Admin does not restrict
- Owner not to limit
- To write permission restrictions
* reformat tmpl
* finished the UI and add/delete protected branch response
* remove unused comment
* indent all the template files and remove ru translations since we use crowdin
* fix the push bug
Diffstat (limited to 'routers/repo/http.go')
-rw-r--r-- | routers/repo/http.go | 97 |
1 files changed, 86 insertions, 11 deletions
diff --git a/routers/repo/http.go b/routers/repo/http.go index 695e758cdb..780babd40d 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -42,10 +42,20 @@ func HTTP(ctx *context.Context) { } else if service == "git-upload-pack" || strings.HasSuffix(ctx.Req.URL.Path, "git-upload-pack") { isPull = true + } else if service == "git-upload-archive" || + strings.HasSuffix(ctx.Req.URL.Path, "git-upload-archive") { + isPull = true } else { isPull = (ctx.Req.Method == "GET") } + var accessMode models.AccessMode + if isPull { + accessMode = models.AccessModeRead + } else { + accessMode = models.AccessModeWrite + } + isWiki := false if strings.HasSuffix(reponame, ".wiki") { isWiki = true @@ -146,17 +156,12 @@ func HTTP(ctx *context.Context) { } if !isPublicPull { - var tp = models.AccessModeWrite - if isPull { - tp = models.AccessModeRead - } - - has, err := models.HasAccess(authUser, repo, tp) + has, err := models.HasAccess(authUser, repo, accessMode) if err != nil { ctx.Handle(http.StatusInternalServerError, "HasAccess", err) return } else if !has { - if tp == models.AccessModeRead { + if accessMode == models.AccessModeRead { has, err = models.HasAccess(authUser, repo, models.AccessModeWrite) if err != nil { ctx.Handle(http.StatusInternalServerError, "HasAccess2", err) @@ -232,9 +237,20 @@ func HTTP(ctx *context.Context) { } } + params := make(map[string]string) + + if askAuth { + params[models.ProtectedBranchUserID] = fmt.Sprintf("%d", authUser.ID) + if err == nil { + params[models.ProtectedBranchAccessMode] = accessMode.String() + } + params[models.ProtectedBranchRepoID] = fmt.Sprintf("%d", repo.ID) + } + HTTPBackend(ctx, &serviceConfig{ UploadPack: true, ReceivePack: true, + Params: params, OnSucceed: callback, })(ctx.Resp, ctx.Req.Request) @@ -244,6 +260,7 @@ func HTTP(ctx *context.Context) { type serviceConfig struct { UploadPack bool ReceivePack bool + Params map[string]string OnSucceed func(rpc string, input []byte) } @@ -261,6 +278,42 @@ func (h *serviceHandler) setHeaderNoCache() { h.w.Header().Set("Cache-Control", "no-cache, max-age=0, must-revalidate") } +func (h *serviceHandler) getBranch(input []byte) string { + var lastLine int64 + var branchName string + for { + head := input[lastLine : lastLine+2] + if head[0] == '0' && head[1] == '0' { + size, err := strconv.ParseInt(string(input[lastLine+2:lastLine+4]), 16, 32) + if err != nil { + log.Error(4, "%v", err) + return branchName + } + + if size == 0 { + //fmt.Println(string(input[lastLine:])) + break + } + + line := input[lastLine : lastLine+size] + idx := bytes.IndexRune(line, '\000') + if idx > -1 { + line = line[:idx] + } + + fields := strings.Fields(string(line)) + if len(fields) >= 3 { + refFullName := fields[2] + branchName = strings.TrimPrefix(refFullName, git.BranchPrefix) + } + lastLine = lastLine + size + } else { + break + } + } + return branchName +} + func (h *serviceHandler) setHeaderCacheForever() { now := time.Now().Unix() expires := now + 31536000 @@ -358,13 +411,15 @@ func serviceRPC(h serviceHandler, service string) { h.w.WriteHeader(http.StatusUnauthorized) return } + h.w.Header().Set("Content-Type", fmt.Sprintf("application/x-git-%s-result", service)) var ( - reqBody = h.r.Body - input []byte - br io.Reader - err error + reqBody = h.r.Body + input []byte + br io.Reader + err error + branchName string ) // Handle GZIP. @@ -385,11 +440,31 @@ func serviceRPC(h serviceHandler, service string) { return } + branchName = h.getBranch(input) br = bytes.NewReader(input) } else { br = reqBody } + // check protected branch + repoID, _ := strconv.ParseInt(h.cfg.Params[models.ProtectedBranchRepoID], 10, 64) + accessMode := models.ParseAccessMode(h.cfg.Params[models.ProtectedBranchAccessMode]) + // skip admin or owner AccessMode + if accessMode == models.AccessModeWrite { + protectBranch, err := models.GetProtectedBranchBy(repoID, branchName) + if err != nil { + log.GitLogger.Error(2, "fail to get protected branch information: %v", err) + h.w.WriteHeader(http.StatusInternalServerError) + return + } + + if protectBranch != nil { + log.GitLogger.Error(2, "protected branches can not be pushed to") + h.w.WriteHeader(http.StatusForbidden) + return + } + } + cmd := exec.Command("git", service, "--stateless-rpc", h.dir) cmd.Dir = h.dir cmd.Stdout = h.w |