diff options
author | zeripath <art27@cantab.net> | 2019-06-01 16:00:21 +0100 |
---|---|---|
committer | Lunny Xiao <xiaolunwen@gmail.com> | 2019-06-01 23:00:21 +0800 |
commit | 356854fc5f8d7d1a7e4d68c9e00929e9ce8aa867 (patch) | |
tree | bc250740ffe65de5cd9ce3389e004ca7723d5643 /routers/private | |
parent | 8a343dda39b187627db6ffb4c24a6e0ae615867b (diff) | |
download | gitea-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 'routers/private')
-rw-r--r-- | routers/private/branch.go | 52 | ||||
-rw-r--r-- | routers/private/hook.go | 209 | ||||
-rw-r--r-- | routers/private/internal.go | 19 | ||||
-rw-r--r-- | routers/private/key.go | 78 | ||||
-rw-r--r-- | routers/private/push_update.go | 47 | ||||
-rw-r--r-- | routers/private/repository.go | 83 | ||||
-rw-r--r-- | routers/private/serv.go | 286 | ||||
-rw-r--r-- | routers/private/wiki.go | 34 |
8 files changed, 511 insertions, 297 deletions
diff --git a/routers/private/branch.go b/routers/private/branch.go deleted file mode 100644 index 448c61f1db..0000000000 --- a/routers/private/branch.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package private - -import ( - "code.gitea.io/gitea/models" - - macaron "gopkg.in/macaron.v1" -) - -// GetProtectedBranchBy get protected branch information -func GetProtectedBranchBy(ctx *macaron.Context) { - repoID := ctx.ParamsInt64(":id") - branchName := ctx.Params("*") - protectBranch, err := models.GetProtectedBranchBy(repoID, branchName) - if err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } else if protectBranch != nil { - ctx.JSON(200, protectBranch) - } else { - ctx.JSON(200, &models.ProtectedBranch{ - ID: 0, - }) - } -} - -// CanUserPush returns if user push -func CanUserPush(ctx *macaron.Context) { - pbID := ctx.ParamsInt64(":pbid") - userID := ctx.ParamsInt64(":userid") - - protectBranch, err := models.GetProtectedBranchByID(pbID) - if err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } else if protectBranch != nil { - ctx.JSON(200, map[string]interface{}{ - "can_push": protectBranch.CanUserPush(userID), - }) - } else { - ctx.JSON(200, map[string]interface{}{ - "can_push": false, - }) - } -} diff --git a/routers/private/hook.go b/routers/private/hook.go new file mode 100644 index 0000000000..700c8bf332 --- /dev/null +++ b/routers/private/hook.go @@ -0,0 +1,209 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead. +package private + +import ( + "fmt" + "net/http" + "os" + "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" + + macaron "gopkg.in/macaron.v1" +) + +// HookPreReceive checks whether a individual commit is acceptable +func HookPreReceive(ctx *macaron.Context) { + ownerName := ctx.Params(":owner") + repoName := ctx.Params(":repo") + oldCommitID := ctx.QueryTrim("old") + newCommitID := ctx.QueryTrim("new") + refFullName := ctx.QueryTrim("ref") + userID := ctx.QueryInt64("userID") + gitObjectDirectory := ctx.QueryTrim("gitObjectDirectory") + gitAlternativeObjectDirectories := ctx.QueryTrim("gitAlternativeObjectDirectories") + + branchName := strings.TrimPrefix(refFullName, git.BranchPrefix) + repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName) + if err != nil { + log.Error("Unable to get repository: %s/%s Error: %v", ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": err.Error(), + }) + return + } + repo.OwnerName = ownerName + protectBranch, err := models.GetProtectedBranchBy(repo.ID, branchName) + if err != nil { + log.Error("Unable to get protected branch: %s in %-v Error: %v", branchName, repo, err) + ctx.JSON(500, map[string]interface{}{ + "err": err.Error(), + }) + return + } + if protectBranch != nil && protectBranch.IsProtected() { + // check and deletion + if newCommitID == git.EmptySHA { + log.Warn("Forbidden: Branch: %s in %-v is protected from deletion", branchName, repo) + ctx.JSON(http.StatusForbidden, map[string]interface{}{ + "err": fmt.Sprintf("branch %s is protected from deletion", branchName), + }) + return + } + + // detect force push + if git.EmptySHA != oldCommitID { + env := append(os.Environ(), + private.GitAlternativeObjectDirectories+"="+gitAlternativeObjectDirectories, + private.GitObjectDirectory+"="+gitObjectDirectory, + private.GitQuarantinePath+"="+gitObjectDirectory, + ) + + output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDirWithEnv(repo.RepoPath(), env) + if err != nil { + log.Error("Unable to detect force push between: %s and %s in %-v Error: %v", oldCommitID, newCommitID, repo, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": fmt.Sprintf("Fail to detect force push: %v", err), + }) + return + } else if len(output) > 0 { + log.Warn("Forbidden: Branch: %s in %-v is protected from force push", branchName, repo) + ctx.JSON(http.StatusForbidden, map[string]interface{}{ + "err": fmt.Sprintf("branch %s is protected from force push", branchName), + }) + return + + } + } + + if !protectBranch.CanUserPush(userID) { + log.Warn("Forbidden: User %d cannot push to protected branch: %s in %-v", userID, branchName, repo) + ctx.JSON(http.StatusForbidden, map[string]interface{}{ + "err": fmt.Sprintf("protected branch %s can not be pushed to", branchName), + }) + return + } + } + ctx.PlainText(http.StatusOK, []byte("ok")) +} + +// HookPostReceive updates services and users +func HookPostReceive(ctx *macaron.Context) { + ownerName := ctx.Params(":owner") + repoName := ctx.Params(":repo") + oldCommitID := ctx.Query("old") + newCommitID := ctx.Query("new") + refFullName := ctx.Query("ref") + userID := ctx.QueryInt64("userID") + userName := ctx.Query("username") + + branch := refFullName + if strings.HasPrefix(refFullName, git.BranchPrefix) { + branch = strings.TrimPrefix(refFullName, git.BranchPrefix) + } else if strings.HasPrefix(refFullName, git.TagPrefix) { + branch = strings.TrimPrefix(refFullName, git.TagPrefix) + } + + // 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 := models.PushUpdate(branch, models.PushUpdateOptions{ + RefFullName: refFullName, + OldCommitID: oldCommitID, + NewCommitID: newCommitID, + PusherID: userID, + PusherName: userName, + RepoUserName: ownerName, + RepoName: repoName, + }); err != nil { + log.Error("Failed to Update: %s/%s Branch: %s Error: %v", ownerName, repoName, branch, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": fmt.Sprintf("Failed to Update: %s/%s Branch: %s Error: %v", ownerName, repoName, branch, err), + }) + return + } + } + + if newCommitID != git.EmptySHA && strings.HasPrefix(refFullName, git.BranchPrefix) { + repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName) + if err != nil { + log.Error("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": fmt.Sprintf("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err), + }) + return + } + repo.OwnerName = ownerName + + pullRequestAllowed := repo.AllowsPulls() + if !pullRequestAllowed { + ctx.JSON(http.StatusOK, map[string]interface{}{ + "message": false, + }) + return + } + + baseRepo := repo + if repo.IsFork { + if err := repo.GetBaseRepo(); err != nil { + log.Error("Failed to get Base Repository of Forked repository: %-v Error: %v", repo, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": fmt.Sprintf("Failed to get Base Repository of Forked repository: %-v Error: %v", repo, err), + }) + return + } + baseRepo = repo.BaseRepo + } + + if !repo.IsFork && branch == baseRepo.DefaultBranch { + ctx.JSON(http.StatusOK, map[string]interface{}{ + "message": false, + }) + return + } + + pr, err := models.GetUnmergedPullRequest(repo.ID, baseRepo.ID, branch, baseRepo.DefaultBranch) + if err != nil && !models.IsErrPullRequestNotExist(err) { + log.Error("Failed to get active PR in: %-v Branch: %s to: %-v Branch: %s Error: %v", repo, branch, baseRepo, baseRepo.DefaultBranch, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": fmt.Sprintf( + "Failed to get active PR in: %-v Branch: %s to: %-v Branch: %s Error: %v", repo, branch, baseRepo, baseRepo.DefaultBranch, err), + }) + return + } + + if pr == nil { + if repo.IsFork { + branch = fmt.Sprintf("%s:%s", repo.OwnerName, branch) + } + ctx.JSON(http.StatusOK, map[string]interface{}{ + "message": true, + "create": true, + "branch": branch, + "url": fmt.Sprintf("%s/compare/%s...%s", baseRepo.HTMLURL(), util.PathEscapeSegments(baseRepo.DefaultBranch), util.PathEscapeSegments(branch)), + }) + } else { + ctx.JSON(http.StatusOK, map[string]interface{}{ + "message": true, + "create": false, + "branch": branch, + "url": fmt.Sprintf("%s/pulls/%d", baseRepo.HTMLURL(), pr.Index), + }) + } + return + } + ctx.JSON(http.StatusOK, map[string]interface{}{ + "message": false, + }) + return +} diff --git a/routers/private/internal.go b/routers/private/internal.go index ee6e1274c3..11cea8b4b9 100644 --- a/routers/private/internal.go +++ b/routers/private/internal.go @@ -76,19 +76,10 @@ func CheckUnitUser(ctx *macaron.Context) { // These APIs will be invoked by internal commands for example `gitea serv` and etc. func RegisterRoutes(m *macaron.Macaron) { m.Group("/", func() { - m.Get("/ssh/:id", GetPublicKeyByID) - m.Get("/ssh/:id/user", GetUserByKeyID) - m.Post("/ssh/:id/update", UpdatePublicKey) - m.Post("/repositories/:repoid/keys/:keyid/update", UpdateDeployKey) - m.Get("/repositories/:repoid/user/:userid/checkunituser", CheckUnitUser) - m.Get("/repositories/:repoid/has-keys/:keyid", HasDeployKey) - m.Get("/repositories/:repoid/keys/:keyid", GetDeployKey) - m.Get("/repositories/:repoid/wiki/init", InitWiki) - m.Post("/push/update", PushUpdate) - m.Get("/protectedbranch/:pbid/:userid", CanUserPush) - m.Get("/repo/:owner/:repo", GetRepositoryByOwnerAndName) - m.Get("/branch/:id/*", GetProtectedBranchBy) - m.Get("/repository/:rid", GetRepository) - m.Get("/active-pull-request", GetActivePullRequest) + m.Post("/ssh/:id/update/:repoid", UpdatePublicKeyInRepo) + m.Get("/hook/pre-receive/:owner/:repo", HookPreReceive) + m.Get("/hook/post-receive/:owner/:repo", HookPostReceive) + m.Get("/serv/none/:keyid", ServNoCommand) + m.Get("/serv/command/:keyid/:owner/:repo", ServCommand) }, CheckInternalToken) } diff --git a/routers/private/key.go b/routers/private/key.go index ee22f6ac48..f7212ec892 100644 --- a/routers/private/key.go +++ b/routers/private/key.go @@ -12,30 +12,10 @@ import ( macaron "gopkg.in/macaron.v1" ) -// UpdateDeployKey update deploy key updates -func UpdateDeployKey(ctx *macaron.Context) { - repoID := ctx.ParamsInt64(":repoid") - keyID := ctx.ParamsInt64(":keyid") - deployKey, err := models.GetDeployKeyByRepo(keyID, repoID) - if err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } - deployKey.UpdatedUnix = util.TimeStampNow() - if err = models.UpdateDeployKeyCols(deployKey, "updated_unix"); err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } - ctx.PlainText(200, []byte("success")) -} - -// UpdatePublicKey update publick key updates -func UpdatePublicKey(ctx *macaron.Context) { +// UpdatePublicKeyInRepo update public key and deploy key updates +func UpdatePublicKeyInRepo(ctx *macaron.Context) { keyID := ctx.ParamsInt64(":id") + repoID := ctx.ParamsInt64(":repoid") if err := models.UpdatePublicKeyUpdated(keyID); err != nil { ctx.JSON(500, map[string]interface{}{ "err": err.Error(), @@ -43,60 +23,24 @@ func UpdatePublicKey(ctx *macaron.Context) { return } - ctx.PlainText(200, []byte("success")) -} - -//GetPublicKeyByID chainload to models.GetPublicKeyByID -func GetPublicKeyByID(ctx *macaron.Context) { - keyID := ctx.ParamsInt64(":id") - key, err := models.GetPublicKeyByID(keyID) - if err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } - ctx.JSON(200, key) -} - -//GetUserByKeyID chainload to models.GetUserByKeyID -func GetUserByKeyID(ctx *macaron.Context) { - keyID := ctx.ParamsInt64(":id") - user, err := models.GetUserByKeyID(keyID) + deployKey, err := models.GetDeployKeyByRepo(keyID, repoID) if err != nil { + if models.IsErrDeployKeyNotExist(err) { + ctx.PlainText(200, []byte("success")) + return + } ctx.JSON(500, map[string]interface{}{ "err": err.Error(), }) return } - ctx.JSON(200, user) -} - -//GetDeployKey chainload to models.GetDeployKey -func GetDeployKey(ctx *macaron.Context) { - repoID := ctx.ParamsInt64(":repoid") - keyID := ctx.ParamsInt64(":keyid") - dKey, err := models.GetDeployKeyByRepo(keyID, repoID) - if err != nil { - if models.IsErrDeployKeyNotExist(err) { - ctx.JSON(404, []byte("not found")) - return - } + deployKey.UpdatedUnix = util.TimeStampNow() + if err = models.UpdateDeployKeyCols(deployKey, "updated_unix"); err != nil { ctx.JSON(500, map[string]interface{}{ "err": err.Error(), }) return } - ctx.JSON(200, dKey) -} -//HasDeployKey chainload to models.HasDeployKey -func HasDeployKey(ctx *macaron.Context) { - repoID := ctx.ParamsInt64(":repoid") - keyID := ctx.ParamsInt64(":keyid") - if models.HasDeployKey(keyID, repoID) { - ctx.PlainText(200, []byte("success")) - return - } - ctx.PlainText(404, []byte("not found")) + ctx.PlainText(200, []byte("success")) } diff --git a/routers/private/push_update.go b/routers/private/push_update.go deleted file mode 100644 index 5c42f066ee..0000000000 --- a/routers/private/push_update.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package private - -import ( - "encoding/json" - "strings" - - "code.gitea.io/gitea/models" - "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/log" - - macaron "gopkg.in/macaron.v1" -) - -// PushUpdate update public key updates -func PushUpdate(ctx *macaron.Context) { - var opt models.PushUpdateOptions - if err := json.NewDecoder(ctx.Req.Request.Body).Decode(&opt); err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } - - branch := strings.TrimPrefix(opt.RefFullName, git.BranchPrefix) - if len(branch) == 0 || opt.PusherID <= 0 { - ctx.Error(404) - log.Trace("PushUpdate: branch or secret is empty, or pusher ID is not valid") - return - } - - err := models.PushUpdate(branch, opt) - if err != nil { - if models.IsErrUserNotExist(err) { - ctx.Error(404) - } else { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - } - return - } - ctx.Status(202) -} diff --git a/routers/private/repository.go b/routers/private/repository.go deleted file mode 100644 index 9f451bcf1d..0000000000 --- a/routers/private/repository.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2018 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package private - -import ( - "net/http" - - "code.gitea.io/gitea/models" - - macaron "gopkg.in/macaron.v1" -) - -// GetRepository return the default branch of a repository -func GetRepository(ctx *macaron.Context) { - repoID := ctx.ParamsInt64(":rid") - repository, err := models.GetRepositoryByID(repoID) - repository.MustOwnerName() - allowPulls := repository.AllowsPulls() - // put it back to nil because json unmarshal can't unmarshal it - repository.Units = nil - - if err != nil { - ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ - "err": err.Error(), - }) - return - } - - if repository.IsFork { - repository.GetBaseRepo() - if err != nil { - ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ - "err": err.Error(), - }) - return - } - repository.BaseRepo.MustOwnerName() - allowPulls = repository.BaseRepo.AllowsPulls() - // put it back to nil because json unmarshal can't unmarshal it - repository.BaseRepo.Units = nil - } - - ctx.JSON(http.StatusOK, struct { - Repository *models.Repository - AllowPullRequest bool - }{ - Repository: repository, - AllowPullRequest: allowPulls, - }) -} - -// GetActivePullRequest return an active pull request when it exists or an empty object -func GetActivePullRequest(ctx *macaron.Context) { - baseRepoID := ctx.QueryInt64("baseRepoID") - headRepoID := ctx.QueryInt64("headRepoID") - baseBranch := ctx.QueryTrim("baseBranch") - if len(baseBranch) == 0 { - ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ - "err": "QueryTrim failed", - }) - return - } - - headBranch := ctx.QueryTrim("headBranch") - if len(headBranch) == 0 { - ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ - "err": "QueryTrim failed", - }) - return - } - - pr, err := models.GetUnmergedPullRequest(headRepoID, baseRepoID, headBranch, baseBranch) - if err != nil && !models.IsErrPullRequestNotExist(err) { - ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ - "err": err.Error(), - }) - return - } - - ctx.JSON(http.StatusOK, pr) -} diff --git a/routers/private/serv.go b/routers/private/serv.go new file mode 100644 index 0000000000..68e4361e56 --- /dev/null +++ b/routers/private/serv.go @@ -0,0 +1,286 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +// Package private includes all internal routes. The package name internal is ideal but Golang is not allowed, so we use private as package name instead. +package private + +import ( + "fmt" + "net/http" + "strings" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/setting" + + macaron "gopkg.in/macaron.v1" +) + +// ServNoCommand returns information about the provided keyid +func ServNoCommand(ctx *macaron.Context) { + keyID := ctx.ParamsInt64(":keyid") + if keyID <= 0 { + ctx.JSON(http.StatusBadRequest, map[string]interface{}{ + "err": fmt.Sprintf("Bad key id: %d", keyID), + }) + } + results := private.KeyAndOwner{} + + key, err := models.GetPublicKeyByID(keyID) + if err != nil { + if models.IsErrKeyNotExist(err) { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "err": fmt.Sprintf("Cannot find key: %d", keyID), + }) + return + } + log.Error("Unable to get public key: %d Error: %v", keyID, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": err.Error(), + }) + return + } + results.Key = key + + if key.Type == models.KeyTypeUser { + user, err := models.GetUserByID(key.OwnerID) + if err != nil { + if models.IsErrUserNotExist(err) { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "err": fmt.Sprintf("Cannot find owner with id: %d for key: %d", key.OwnerID, keyID), + }) + return + } + log.Error("Unable to get owner with id: %d for public key: %d Error: %v", key.OwnerID, keyID, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "err": err.Error(), + }) + return + } + results.Owner = user + } + ctx.JSON(http.StatusOK, &results) + return +} + +// ServCommand returns information about the provided keyid +func ServCommand(ctx *macaron.Context) { + // Although we provide the verbs we don't need them at present they're just for logging purposes + keyID := ctx.ParamsInt64(":keyid") + ownerName := ctx.Params(":owner") + repoName := ctx.Params(":repo") + mode := models.AccessMode(ctx.QueryInt("mode")) + + // Set the basic parts of the results to return + results := private.ServCommandResults{ + RepoName: repoName, + OwnerName: ownerName, + KeyID: keyID, + } + + // Now because we're not translating things properly let's just default some Engish strings here + modeString := "read" + if mode > models.AccessModeRead { + modeString = "write to" + } + + // The default unit we're trying to look at is code + unitType := models.UnitTypeCode + + // Unless we're a wiki... + if strings.HasSuffix(repoName, ".wiki") { + // in which case we need to look at the wiki + unitType = models.UnitTypeWiki + // And we'd better munge the reponame and tell downstream we're looking at a wiki + results.IsWiki = true + results.RepoName = repoName[:len(repoName)-5] + } + + // Now get the Repository and set the results section + repo, err := models.GetRepositoryByOwnerAndName(results.OwnerName, results.RepoName) + if err != nil { + if models.IsErrRepoNotExist(err) { + ctx.JSON(http.StatusNotFound, map[string]interface{}{ + "results": results, + "type": "ErrRepoNotExist", + "err": fmt.Sprintf("Cannot find repository %s/%s", results.OwnerName, results.RepoName), + }) + return + } + log.Error("Unable to get repository: %s/%s Error: %v", results.OwnerName, results.RepoName, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "results": results, + "type": "InternalServerError", + "err": fmt.Sprintf("Unable to get repository: %s/%s %v", results.OwnerName, results.RepoName, err), + }) + return + } + repo.OwnerName = ownerName + results.RepoID = repo.ID + + // We can shortcut at this point if the repo is a mirror + if mode > models.AccessModeRead && repo.IsMirror { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "results": results, + "type": "ErrMirrorReadOnly", + "err": fmt.Sprintf("Mirror Repository %s/%s is read-only", results.OwnerName, results.RepoName), + }) + return + } + + // Get the Public Key represented by the keyID + key, err := models.GetPublicKeyByID(keyID) + if err != nil { + if models.IsErrKeyNotExist(err) { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "results": results, + "type": "ErrKeyNotExist", + "err": fmt.Sprintf("Cannot find key: %d", keyID), + }) + return + } + log.Error("Unable to get public key: %d Error: %v", keyID, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "results": results, + "type": "InternalServerError", + "err": fmt.Sprintf("Unable to get key: %d Error: %v", keyID, err), + }) + return + } + results.KeyName = key.Name + results.KeyID = key.ID + results.UserID = key.OwnerID + + // Deploy Keys have ownerID set to 0 therefore we can't use the owner + // So now we need to check if the key is a deploy key + // We'll keep hold of the deploy key here for permissions checking + var deployKey *models.DeployKey + var user *models.User + if key.Type == models.KeyTypeDeploy { + results.IsDeployKey = true + + var err error + deployKey, err = models.GetDeployKeyByRepo(key.ID, repo.ID) + if err != nil { + if models.IsErrDeployKeyNotExist(err) { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "results": results, + "type": "ErrDeployKeyNotExist", + "err": fmt.Sprintf("Public (Deploy) Key: %d:%s is not authorized to %s %s/%s.", key.ID, key.Name, modeString, results.OwnerName, results.RepoName), + }) + return + } + log.Error("Unable to get deploy for public (deploy) key: %d in %-v Error: %v", key.ID, repo, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "results": results, + "type": "InternalServerError", + "err": fmt.Sprintf("Unable to get Deploy Key for Public Key: %d:%s in %s/%s.", key.ID, key.Name, results.OwnerName, results.RepoName), + }) + return + } + results.KeyName = deployKey.Name + + // 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 of the repository + results.UserName = results.OwnerName + results.UserID = repo.OwnerID + } else { + // Get the user represented by the Key + var err error + user, err = models.GetUserByID(key.OwnerID) + if err != nil { + if models.IsErrUserNotExist(err) { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "results": results, + "type": "ErrUserNotExist", + "err": fmt.Sprintf("Public Key: %d:%s owner %d does not exist.", key.ID, key.Name, key.OwnerID), + }) + return + } + log.Error("Unable to get owner: %d for public key: %d:%s Error: %v", key.OwnerID, key.ID, key.Name, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "results": results, + "type": "InternalServerError", + "err": fmt.Sprintf("Unable to get Owner: %d for Deploy Key: %d:%s in %s/%s.", key.OwnerID, key.ID, key.Name, ownerName, repoName), + }) + return + } + results.UserName = user.Name + } + + // Don't allow pushing if the repo is archived + if mode > models.AccessModeRead && repo.IsArchived { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "results": results, + "type": "ErrRepoIsArchived", + "err": fmt.Sprintf("Repo: %s/%s is archived.", results.OwnerName, results.RepoName), + }) + return + } + + // Permissions checking: + if mode > models.AccessModeRead || repo.IsPrivate || setting.Service.RequireSignInView { + if key.Type == models.KeyTypeDeploy { + if deployKey.Mode < mode { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "results": results, + "type": "ErrUnauthorized", + "err": fmt.Sprintf("Deploy Key: %d:%s is not authorized to %s %s/%s.", key.ID, key.Name, modeString, results.OwnerName, results.RepoName), + }) + return + } + } else { + perm, err := models.GetUserRepoPermission(repo, user) + if err != nil { + log.Error("Unable to get permissions for %-v with key %d in %-v Error: %v", user, key.ID, repo, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "results": results, + "type": "InternalServerError", + "err": fmt.Sprintf("Unable to get permissions for user %d:%s with key %d in %s/%s Error: %v", user.ID, user.Name, key.ID, results.OwnerName, results.RepoName, err), + }) + return + } + + userMode := perm.UnitAccessMode(unitType) + + if userMode < mode { + ctx.JSON(http.StatusUnauthorized, map[string]interface{}{ + "results": results, + "type": "ErrUnauthorized", + "err": fmt.Sprintf("User: %d:%s with Key: %d:%s is not authorized to %s %s/%s.", user.ID, user.Name, key.ID, key.Name, modeString, ownerName, repoName), + }) + return + } + } + } + + // Finally if we're trying to touch the wiki we should init it + if results.IsWiki { + if err = repo.InitWiki(); err != nil { + log.Error("Failed to initialize the wiki in %-v Error: %v", repo, err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "results": results, + "type": "InternalServerError", + "err": fmt.Sprintf("Failed to initialize the wiki in %s/%s Error: %v", ownerName, repoName, err), + }) + return + } + } + log.Debug("Serv Results:\nIsWiki: %t\nIsDeployKey: %t\nKeyID: %d\tKeyName: %s\nUserName: %s\nUserID: %d\nOwnerName: %s\nRepoName: %s\nRepoID: %d", + results.IsWiki, + results.IsDeployKey, + results.KeyID, + results.KeyName, + results.UserName, + results.UserID, + results.OwnerName, + results.RepoName, + results.RepoID) + + ctx.JSON(http.StatusOK, results) + // We will update the keys in a different call. + return +} diff --git a/routers/private/wiki.go b/routers/private/wiki.go deleted file mode 100644 index 33bcbaf17e..0000000000 --- a/routers/private/wiki.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package private - -import ( - "code.gitea.io/gitea/models" - - macaron "gopkg.in/macaron.v1" -) - -// InitWiki initilizes wiki via repo id -func InitWiki(ctx *macaron.Context) { - repoID := ctx.ParamsInt64("repoid") - - repo, err := models.GetRepositoryByID(repoID) - if err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } - - err = repo.InitWiki() - if err != nil { - ctx.JSON(500, map[string]interface{}{ - "err": err.Error(), - }) - return - } - - ctx.Status(202) -} |