summaryrefslogtreecommitdiffstats
path: root/cmd
diff options
context:
space:
mode:
authorzeripath <art27@cantab.net>2019-06-01 16:00:21 +0100
committerLunny Xiao <xiaolunwen@gmail.com>2019-06-01 23:00:21 +0800
commit356854fc5f8d7d1a7e4d68c9e00929e9ce8aa867 (patch)
treebc250740ffe65de5cd9ce3389e004ca7723d5643 /cmd
parent8a343dda39b187627db6ffb4c24a6e0ae615867b (diff)
downloadgitea-356854fc5f8d7d1a7e4d68c9e00929e9ce8aa867.tar.gz
gitea-356854fc5f8d7d1a7e4d68c9e00929e9ce8aa867.zip
Move serv hook functionality & drop GitLogger (#6993)
* Move hook functionality internally * Internalise serv logic * Remove old internal paths * finally remove the gitlogger * Disallow push on archived repositories * fix lint error * Update modules/private/key.go * Update routers/private/hook.go * Update routers/private/hook.go * Update routers/private/hook.go * Updated routers/private/serv.go * Fix LFS Locks over SSH * rev-list needs to be run by the hook process * fixup * Improve git test * Ensure that the lfs files are created with a different prefix * Reduce the replication in git_test.go * slight refactor * Remove unnecessary "/" * Restore ensureAnonymousClone * Restore ensureAnonymousClone * Run rev-list on server side * Try passing in the alternative directories instead * Mark test as skipped * Improve git test * Ensure that the lfs files are created with a different prefix * Reduce the replication in git_test.go * Remove unnecessary "/"
Diffstat (limited to 'cmd')
-rw-r--r--cmd/hook.go125
-rw-r--r--cmd/serv.go173
2 files changed, 85 insertions, 213 deletions
diff --git a/cmd/hook.go b/cmd/hook.go
index f8bd34c4e9..b3e900afee 100644
--- a/cmd/hook.go
+++ b/cmd/hook.go
@@ -8,15 +8,14 @@ import (
"bufio"
"bytes"
"fmt"
+ "net/http"
"os"
"strconv"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/git"
- "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/private"
- "code.gitea.io/gitea/modules/util"
"github.com/urfave/cli"
)
@@ -62,12 +61,10 @@ func runHookPreReceive(c *cli.Context) error {
setup("hooks/pre-receive.log")
// the environment setted on serv command
- repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64)
isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
username := os.Getenv(models.EnvRepoUsername)
reponame := os.Getenv(models.EnvRepoName)
- userIDStr := os.Getenv(models.EnvPusherID)
- repoPath := models.RepoPath(username, reponame)
+ userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
buf := bytes.NewBuffer(nil)
scanner := bufio.NewScanner(os.Stdin)
@@ -91,35 +88,19 @@ func runHookPreReceive(c *cli.Context) error {
// If the ref is a branch, check if it's protected
if strings.HasPrefix(refFullName, git.BranchPrefix) {
- branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
- protectBranch, err := private.GetProtectedBranchBy(repoID, branchName)
- if err != nil {
- fail("Internal error", fmt.Sprintf("retrieve protected branches information failed: %v", err))
- }
-
- if protectBranch != nil && protectBranch.IsProtected() {
- // check and deletion
- if newCommitID == git.EmptySHA {
- fail(fmt.Sprintf("branch %s is protected from deletion", branchName), "")
- }
-
- // detect force push
- if git.EmptySHA != oldCommitID {
- output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDir(repoPath)
- if err != nil {
- fail("Internal error", "Fail to detect force push: %v", err)
- } else if len(output) > 0 {
- fail(fmt.Sprintf("branch %s is protected from force push", branchName), "")
- }
- }
-
- userID, _ := strconv.ParseInt(userIDStr, 10, 64)
- canPush, err := private.CanUserPush(protectBranch.ID, userID)
- if err != nil {
- fail("Internal error", "Fail to detect user can push: %v", err)
- } else if !canPush {
- fail(fmt.Sprintf("protected branch %s can not be pushed to", branchName), "")
- }
+ statusCode, msg := private.HookPreReceive(username, reponame, private.HookOptions{
+ OldCommitID: oldCommitID,
+ NewCommitID: newCommitID,
+ RefFullName: refFullName,
+ UserID: userID,
+ GitAlternativeObjectDirectories: os.Getenv(private.GitAlternativeObjectDirectories),
+ GitObjectDirectory: os.Getenv(private.GitObjectDirectory),
+ })
+ switch statusCode {
+ case http.StatusInternalServerError:
+ fail("Internal Server Error", msg)
+ case http.StatusForbidden:
+ fail(msg, "")
}
}
}
@@ -145,7 +126,6 @@ func runHookPostReceive(c *cli.Context) error {
setup("hooks/post-receive.log")
// the environment setted on serv command
- repoID, _ := strconv.ParseInt(os.Getenv(models.ProtectedBranchRepoID), 10, 64)
repoUser := os.Getenv(models.EnvRepoUsername)
isWiki := (os.Getenv(models.EnvRepoIsWiki) == "true")
repoName := os.Getenv(models.EnvRepoName)
@@ -172,64 +152,31 @@ func runHookPostReceive(c *cli.Context) error {
newCommitID := string(fields[1])
refFullName := string(fields[2])
- // Only trigger activity updates for changes to branches or
- // tags. Updates to other refs (eg, refs/notes, refs/changes,
- // or other less-standard refs spaces are ignored since there
- // may be a very large number of them).
- if strings.HasPrefix(refFullName, git.BranchPrefix) || strings.HasPrefix(refFullName, git.TagPrefix) {
- if err := private.PushUpdate(models.PushUpdateOptions{
- RefFullName: refFullName,
- OldCommitID: oldCommitID,
- NewCommitID: newCommitID,
- PusherID: pusherID,
- PusherName: pusherName,
- RepoUserName: repoUser,
- RepoName: repoName,
- }); err != nil {
- log.GitLogger.Error("Update: %v", err)
- }
- }
-
- if newCommitID != git.EmptySHA && strings.HasPrefix(refFullName, git.BranchPrefix) {
- branch := strings.TrimPrefix(refFullName, git.BranchPrefix)
- repo, pullRequestAllowed, err := private.GetRepository(repoID)
- if err != nil {
- log.GitLogger.Error("get repo: %v", err)
- break
- }
- if !pullRequestAllowed {
- break
- }
-
- baseRepo := repo
- if repo.IsFork {
- baseRepo = repo.BaseRepo
- }
-
- if !repo.IsFork && branch == baseRepo.DefaultBranch {
- break
- }
+ res, err := private.HookPostReceive(repoUser, repoName, private.HookOptions{
+ OldCommitID: oldCommitID,
+ NewCommitID: newCommitID,
+ RefFullName: refFullName,
+ UserID: pusherID,
+ UserName: pusherName,
+ })
- pr, err := private.ActivePullRequest(baseRepo.ID, repo.ID, baseRepo.DefaultBranch, branch)
- if err != nil {
- log.GitLogger.Error("get active pr: %v", err)
- break
- }
+ if res == nil {
+ fail("Internal Server Error", err)
+ }
- fmt.Fprintln(os.Stderr, "")
- if pr == nil {
- if repo.IsFork {
- branch = fmt.Sprintf("%s:%s", repo.OwnerName, branch)
- }
- fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", branch)
- fmt.Fprintf(os.Stderr, " %s/compare/%s...%s\n", baseRepo.HTMLURL(), util.PathEscapeSegments(baseRepo.DefaultBranch), util.PathEscapeSegments(branch))
- } else {
- fmt.Fprint(os.Stderr, "Visit the existing pull request:\n")
- fmt.Fprintf(os.Stderr, " %s/pulls/%d\n", baseRepo.HTMLURL(), pr.Index)
- }
- fmt.Fprintln(os.Stderr, "")
+ if res["message"] == false {
+ continue
}
+ fmt.Fprintln(os.Stderr, "")
+ if res["create"] == true {
+ fmt.Fprintf(os.Stderr, "Create a new pull request for '%s':\n", res["branch"])
+ fmt.Fprintf(os.Stderr, " %s\n", res["url"])
+ } else {
+ fmt.Fprint(os.Stderr, "Visit the existing pull request:\n")
+ fmt.Fprintf(os.Stderr, " %s\n", res["url"])
+ }
+ fmt.Fprintln(os.Stderr, "")
}
return nil
diff --git a/cmd/serv.go b/cmd/serv.go
index a30e02e7a2..aa068d4cf6 100644
--- a/cmd/serv.go
+++ b/cmd/serv.go
@@ -8,9 +8,11 @@ package cmd
import (
"encoding/json"
"fmt"
+ "net/http"
+ "net/url"
"os"
"os/exec"
- "path/filepath"
+ "strconv"
"strings"
"time"
@@ -68,7 +70,6 @@ func setup(logPath string) {
log.DelLogger("console")
setting.NewContext()
checkLFSVersion()
- log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath))
}
func parseCmd(cmd string) (string, string) {
@@ -95,15 +96,14 @@ func fail(userMessage, logMessage string, args ...interface{}) {
if !setting.ProdMode {
fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
}
- log.GitLogger.Fatal(logMessage, args...)
return
}
- log.GitLogger.Close()
os.Exit(1)
}
func runServ(c *cli.Context) error {
+ // FIXME: This needs to internationalised
setup("serv.log")
if setting.SSH.Disabled {
@@ -116,9 +116,23 @@ func runServ(c *cli.Context) error {
return nil
}
+ keys := strings.Split(c.Args()[0], "-")
+ if len(keys) != 2 || keys[0] != "key" {
+ fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
+ }
+ keyID := com.StrTo(keys[1]).MustInt64()
+
cmd := os.Getenv("SSH_ORIGINAL_COMMAND")
if len(cmd) == 0 {
- println("Hi there, You've successfully authenticated, but Gitea does not provide shell access.")
+ key, user, err := private.ServNoCommand(keyID)
+ if err != nil {
+ fail("Internal error", "Failed to check provided key: %v", err)
+ }
+ if key.Type == models.KeyTypeDeploy {
+ println("Hi there! You've successfully authenticated with the deploy key named " + key.Name + ", but Gitea does not provide shell access.")
+ } else {
+ println("Hi there: " + user.Name + "! You've successfully authenticated with the key named " + key.Name + ", but Gitea does not provide shell access.")
+ }
println("If this is unexpected, please log in with password and setup Gitea under another user.")
return nil
}
@@ -152,41 +166,19 @@ func runServ(c *cli.Context) error {
fail("Error while trying to create PPROF_DATA_PATH", "Error while trying to create PPROF_DATA_PATH: %v", err)
}
- stopCPUProfiler := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username)
+ stopCPUProfiler, err := pprof.DumpCPUProfileForUsername(setting.PprofDataPath, username)
+ if err != nil {
+ fail("Internal Server Error", "Unable to start CPU profile: %v", err)
+ }
defer func() {
stopCPUProfiler()
- pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
+ err := pprof.DumpMemProfileForUsername(setting.PprofDataPath, username)
+ if err != nil {
+ fail("Internal Server Error", "Unable to dump Mem Profile: %v", err)
+ }
}()
}
- var (
- isWiki bool
- unitType = models.UnitTypeCode
- unitName = "code"
- )
- if strings.HasSuffix(reponame, ".wiki") {
- isWiki = true
- unitType = models.UnitTypeWiki
- unitName = "wiki"
- reponame = reponame[:len(reponame)-5]
- }
-
- os.Setenv(models.EnvRepoUsername, username)
- if isWiki {
- os.Setenv(models.EnvRepoIsWiki, "true")
- } else {
- os.Setenv(models.EnvRepoIsWiki, "false")
- }
- os.Setenv(models.EnvRepoName, reponame)
-
- repo, err := private.GetRepositoryByOwnerAndName(username, reponame)
- if err != nil {
- if strings.Contains(err.Error(), "Failed to get repository: repository does not exist") {
- fail(accessDenied, "Repository does not exist: %s/%s", username, reponame)
- }
- fail("Internal error", "Failed to get repository: %v", err)
- }
-
requestedMode, has := allowedCommands[verb]
if !has {
fail("Unknown git command", "Unknown git command %s", verb)
@@ -202,97 +194,36 @@ func runServ(c *cli.Context) error {
}
}
- // Prohibit push to mirror repositories.
- if requestedMode > models.AccessModeRead && repo.IsMirror {
- fail("mirror repository is read-only", "")
- }
-
- // Allow anonymous clone for public repositories.
- var (
- keyID int64
- user *models.User
- )
- if requestedMode == models.AccessModeWrite || repo.IsPrivate || setting.Service.RequireSignInView {
- keys := strings.Split(c.Args()[0], "-")
- if len(keys) != 2 {
- fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
- }
-
- key, err := private.GetPublicKeyByID(com.StrTo(keys[1]).MustInt64())
- if err != nil {
- fail("Invalid key ID", "Invalid key ID[%s]: %v", c.Args()[0], err)
- }
- keyID = key.ID
-
- // Check deploy key or user key.
- if key.Type == models.KeyTypeDeploy {
- // Now we have to get the deploy key for this repo
- deployKey, err := private.GetDeployKey(key.ID, repo.ID)
- if err != nil {
- fail("Key access denied", "Failed to access internal api: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
- }
-
- if deployKey == nil {
- fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
- }
-
- if deployKey.Mode < requestedMode {
- fail("Key permission denied", "Cannot push with read-only deployment key: %d to repo_id: %d", key.ID, repo.ID)
- }
-
- // Update deploy key activity.
- if err = private.UpdateDeployKeyUpdated(key.ID, repo.ID); err != nil {
- fail("Internal error", "UpdateDeployKey: %v", err)
- }
-
- // FIXME: Deploy keys aren't really the owner of the repo pushing changes
- // however we don't have good way of representing deploy keys in hook.go
- // so for now use the owner
- os.Setenv(models.EnvPusherName, username)
- os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", repo.OwnerID))
- } else {
- user, err = private.GetUserByKeyID(key.ID)
- if err != nil {
- fail("internal error", "Failed to get user by key ID(%d): %v", keyID, err)
- }
-
- if !user.IsActive || user.ProhibitLogin {
- fail("Your account is not active or has been disabled by Administrator",
- "User %s is disabled and have no access to repository %s",
- user.Name, repoPath)
- }
-
- mode, err := private.CheckUnitUser(user.ID, repo.ID, user.IsAdmin, unitType)
- if err != nil {
- fail("Internal error", "Failed to check access: %v", err)
- } else if *mode < requestedMode {
- clientMessage := accessDenied
- if *mode >= models.AccessModeRead {
- clientMessage = "You do not have sufficient authorization for this action"
- }
- fail(clientMessage,
- "User %s does not have level %v access to repository %s's "+unitName,
- user.Name, requestedMode, repoPath)
+ results, err := private.ServCommand(keyID, username, reponame, requestedMode, verb, lfsVerb)
+ if err != nil {
+ if private.IsErrServCommand(err) {
+ errServCommand := err.(private.ErrServCommand)
+ if errServCommand.StatusCode != http.StatusInternalServerError {
+ fail("Unauthorized", errServCommand.Error())
+ } else {
+ fail("Internal Server Error", errServCommand.Error())
}
-
- os.Setenv(models.EnvPusherName, user.Name)
- os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", user.ID))
}
+ fail("Internal Server Error", err.Error())
}
+ os.Setenv(models.EnvRepoIsWiki, strconv.FormatBool(results.IsWiki))
+ os.Setenv(models.EnvRepoName, results.RepoName)
+ os.Setenv(models.EnvRepoUsername, results.OwnerName)
+ os.Setenv(models.EnvPusherName, username)
+ os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10))
+ os.Setenv(models.ProtectedBranchRepoID, strconv.FormatInt(results.RepoID, 10))
//LFS token authentication
if verb == lfsAuthenticateVerb {
- url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, username, repo.Name)
+ url := fmt.Sprintf("%s%s/%s.git/info/lfs", setting.AppURL, url.PathEscape(results.OwnerName), url.PathEscape(results.RepoName))
now := time.Now()
claims := jwt.MapClaims{
- "repo": repo.ID,
+ "repo": results.RepoID,
"op": lfsVerb,
"exp": now.Add(setting.LFS.HTTPAuthExpiry).Unix(),
"nbf": now.Unix(),
- }
- if user != nil {
- claims["user"] = user.ID
+ "user": results.UserID,
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
@@ -313,7 +244,6 @@ func runServ(c *cli.Context) error {
if err != nil {
fail("Internal error", "Failed to encode LFS json response: %v", err)
}
-
return nil
}
@@ -329,13 +259,8 @@ func runServ(c *cli.Context) error {
} else {
gitcmd = exec.Command(verb, repoPath)
}
- if isWiki {
- if err = private.InitWiki(repo.ID); err != nil {
- fail("Internal error", "Failed to init wiki repo: %v", err)
- }
- }
- os.Setenv(models.ProtectedBranchRepoID, fmt.Sprintf("%d", repo.ID))
+ os.Setenv(models.ProtectedBranchRepoID, fmt.Sprintf("%d", results.RepoID))
gitcmd.Dir = setting.RepoRootPath
gitcmd.Stdout = os.Stdout
@@ -346,9 +271,9 @@ func runServ(c *cli.Context) error {
}
// Update user key activity.
- if keyID > 0 {
- if err = private.UpdatePublicKeyUpdated(keyID); err != nil {
- fail("Internal error", "UpdatePublicKey: %v", err)
+ if results.KeyID > 0 {
+ if err = private.UpdatePublicKeyInRepo(results.KeyID, results.RepoID); err != nil {
+ fail("Internal error", "UpdatePublicKeyInRepo: %v", err)
}
}