]> source.dussan.org Git - gitea.git/commitdiff
Make gitea serv use api/internal (#4886)
authorAntoine GIRARD <sapk@users.noreply.github.com>
Tue, 30 Oct 2018 06:20:13 +0000 (07:20 +0100)
committerLunny Xiao <xiaolunwen@gmail.com>
Tue, 30 Oct 2018 06:20:13 +0000 (14:20 +0800)
* Start to move to internal/private

* Add GetPublicKeyByID

* Add HasDeployKey

* Add private.UpdateDeployKeyUpdated

* Add private.GetUserByKeyID

* Add private.AccessLevel

* Add private.CheckUnitUser

* Fix mistakes I made

* Some cleaning + moving code to separate files

* Fix error handling

* Remove useless error handling for setup

* lint: fix comment on exported func

* fix copyright header

* Fix order of args

cmd/serv.go
modules/private/branch.go
modules/private/internal.go
modules/private/key.go [new file with mode: 0644]
routers/private/internal.go
routers/private/key.go [new file with mode: 0644]

index b532b95494e501021733d33f5d0e0f49f9a1c61a..ca042e2b2b70d1d9b3def44c9191016a8d9068d4 100644 (file)
@@ -19,7 +19,6 @@ import (
        "code.gitea.io/gitea/modules/pprof"
        "code.gitea.io/gitea/modules/private"
        "code.gitea.io/gitea/modules/setting"
-       "code.gitea.io/gitea/modules/util"
 
        "github.com/Unknwon/com"
        "github.com/dgrijalva/jwt-go"
@@ -49,20 +48,9 @@ var CmdServ = cli.Command{
        },
 }
 
-func setup(logPath string) error {
+func setup(logPath string) {
        setting.NewContext()
        log.NewGitLogger(filepath.Join(setting.LogRootPath, logPath))
-       models.LoadConfigs()
-
-       if setting.UseSQLite3 || setting.UseTiDB {
-               workPath := setting.AppWorkPath
-               if err := os.Chdir(workPath); err != nil {
-                       log.GitLogger.Fatal(4, "Failed to change directory %s: %v", workPath, err)
-               }
-       }
-
-       setting.NewXORMLogService(true)
-       return models.SetEngine()
 }
 
 func parseCmd(cmd string) (string, string) {
@@ -101,10 +89,7 @@ func runServ(c *cli.Context) error {
        if c.IsSet("config") {
                setting.CustomConf = c.String("config")
        }
-
-       if err := setup("serv.log"); err != nil {
-               fail("System init failed", fmt.Sprintf("setup: %v", err))
-       }
+       setup("serv.log")
 
        if setting.SSH.Disabled {
                println("Gitea: SSH has been disabled")
@@ -175,9 +160,9 @@ func runServ(c *cli.Context) error {
        }
        os.Setenv(models.EnvRepoName, reponame)
 
-       repo, err := models.GetRepositoryByOwnerAndName(username, reponame)
+       repo, err := private.GetRepositoryByOwnerAndName(username, reponame)
        if err != nil {
-               if models.IsErrRepoNotExist(err) {
+               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)
@@ -214,7 +199,7 @@ func runServ(c *cli.Context) error {
                        fail("Key ID format error", "Invalid key argument: %s", c.Args()[0])
                }
 
-               key, err := models.GetPublicKeyByID(com.StrTo(keys[1]).MustInt64())
+               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)
                }
@@ -225,23 +210,22 @@ func runServ(c *cli.Context) error {
                        if key.Mode < requestedMode {
                                fail("Key permission denied", "Cannot push with deployment key: %d", key.ID)
                        }
+
                        // Check if this deploy key belongs to current repository.
-                       if !models.HasDeployKey(key.ID, repo.ID) {
+                       has, err := private.HasDeployKey(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 !has {
                                fail("Key access denied", "Deploy key access denied: [key_id: %d, repo_id: %d]", key.ID, repo.ID)
                        }
 
                        // Update deploy key activity.
-                       deployKey, err := models.GetDeployKeyByRepo(key.ID, repo.ID)
-                       if err != nil {
-                               fail("Internal error", "GetDeployKey: %v", err)
-                       }
-
-                       deployKey.UpdatedUnix = util.TimeStampNow()
-                       if err = models.UpdateDeployKeyCols(deployKey, "updated_unix"); err != nil {
+                       if err = private.UpdateDeployKeyUpdated(key.ID, repo.ID); err != nil {
                                fail("Internal error", "UpdateDeployKey: %v", err)
                        }
                } else {
-                       user, err = models.GetUserByKeyID(key.ID)
+                       user, err = private.GetUserByKeyID(key.ID)
                        if err != nil {
                                fail("internal error", "Failed to get user by key ID(%d): %v", keyID, err)
                        }
@@ -252,12 +236,12 @@ func runServ(c *cli.Context) error {
                                        user.Name, repoPath)
                        }
 
-                       mode, err := models.AccessLevel(user.ID, repo)
+                       mode, err := private.AccessLevel(user.ID, repo.ID)
                        if err != nil {
                                fail("Internal error", "Failed to check access: %v", err)
-                       } else if mode < requestedMode {
+                       } else if *mode < requestedMode {
                                clientMessage := accessDenied
-                               if mode >= models.AccessModeRead {
+                               if *mode >= models.AccessModeRead {
                                        clientMessage = "You do not have sufficient authorization for this action"
                                }
                                fail(clientMessage,
@@ -265,7 +249,11 @@ func runServ(c *cli.Context) error {
                                        user.Name, requestedMode, repoPath)
                        }
 
-                       if !repo.CheckUnitUser(user.ID, user.IsAdmin, unitType) {
+                       check, err := private.CheckUnitUser(user.ID, repo.ID, user.IsAdmin, unitType)
+                       if err != nil {
+                               fail("You do not have allowed for this action", "Failed to access internal api: [user.Name: %s, repoPath: %s]", user.Name, repoPath)
+                       }
+                       if !check {
                                fail("You do not have allowed for this action",
                                        "User %s does not have allowed access to repository %s 's code",
                                        user.Name, repoPath)
@@ -325,7 +313,6 @@ func runServ(c *cli.Context) error {
        } else {
                gitcmd = exec.Command(verb, repoPath)
        }
-
        if isWiki {
                if err = repo.InitWiki(); err != nil {
                        fail("Internal error", "Failed to init wiki repo: %v", err)
index fed66d29ffb39a2c32721965b3aef4bb348f9c80..cadbf6c88c2a632788b973730d374c10e6cfef12 100644 (file)
@@ -33,7 +33,7 @@ func GetProtectedBranchBy(repoID int64, branchName string) (*models.ProtectedBra
 
        // All 2XX status codes are accepted and others will return an error
        if resp.StatusCode/100 != 2 {
-               return nil, fmt.Errorf("Failed to update public key: %s", decodeJSONError(resp).Err)
+               return nil, fmt.Errorf("Failed to get protected branch: %s", decodeJSONError(resp).Err)
        }
 
        return &branch, nil
index ac2fe56b871e7a6549b54d5b3ec8ce9cda97b0d8..f4ac1c515a4bf4e8c54b755e357b909293963c6c 100644 (file)
@@ -11,6 +11,7 @@ import (
        "net"
        "net/http"
 
+       "code.gitea.io/gitea/models"
        "code.gitea.io/gitea/modules/httplib"
        "code.gitea.io/gitea/modules/log"
        "code.gitea.io/gitea/modules/setting"
@@ -49,22 +50,66 @@ func newInternalRequest(url, method string) *httplib.Request {
        return req
 }
 
-// UpdatePublicKeyUpdated update publick key updates
-func UpdatePublicKeyUpdated(keyID int64) error {
-       // Ask for running deliver hook and test pull request tasks.
-       reqURL := setting.LocalURL + fmt.Sprintf("api/internal/ssh/%d/update", keyID)
-       log.GitLogger.Trace("UpdatePublicKeyUpdated: %s", reqURL)
+// CheckUnitUser check whether user could visit the unit of this repository
+func CheckUnitUser(userID, repoID int64, isAdmin bool, unitType models.UnitType) (bool, error) {
+       reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repositories/%d/user/%d/checkunituser?isAdmin=%t&unitType=%d", repoID, userID, isAdmin, unitType)
+       log.GitLogger.Trace("AccessLevel: %s", reqURL)
 
-       resp, err := newInternalRequest(reqURL, "POST").Response()
+       resp, err := newInternalRequest(reqURL, "GET").Response()
        if err != nil {
-               return err
+               return false, err
        }
+       defer resp.Body.Close()
+
+       if resp.StatusCode == 200 {
+               return true, nil
+       }
+       return false, nil
+}
+
+// AccessLevel returns the Access a user has to a repository. Will return NoneAccess if the
+// user does not have access.
+func AccessLevel(userID, repoID int64) (*models.AccessMode, error) {
+       reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repositories/%d/user/%d/accesslevel", repoID, userID)
+       log.GitLogger.Trace("AccessLevel: %s", reqURL)
 
+       resp, err := newInternalRequest(reqURL, "GET").Response()
+       if err != nil {
+               return nil, err
+       }
        defer resp.Body.Close()
 
-       // All 2XX status codes are accepted and others will return an error
-       if resp.StatusCode/100 != 2 {
-               return fmt.Errorf("Failed to update public key: %s", decodeJSONError(resp).Err)
+       if resp.StatusCode != 200 {
+               return nil, fmt.Errorf("Failed to get user access level: %s", decodeJSONError(resp).Err)
+       }
+
+       var a models.AccessMode
+       if err := json.NewDecoder(resp.Body).Decode(&a); err != nil {
+               return nil, err
        }
-       return nil
+
+       return &a, nil
+}
+
+// GetRepositoryByOwnerAndName returns the repository by given ownername and reponame.
+func GetRepositoryByOwnerAndName(ownerName, repoName string) (*models.Repository, error) {
+       reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repo/%s/%s", ownerName, repoName)
+       log.GitLogger.Trace("GetRepositoryByOwnerAndName: %s", reqURL)
+
+       resp, err := newInternalRequest(reqURL, "GET").Response()
+       if err != nil {
+               return nil, err
+       }
+       defer resp.Body.Close()
+
+       if resp.StatusCode != 200 {
+               return nil, fmt.Errorf("Failed to get repository: %s", decodeJSONError(resp).Err)
+       }
+
+       var repo models.Repository
+       if err := json.NewDecoder(resp.Body).Decode(&repo); err != nil {
+               return nil, err
+       }
+
+       return &repo, nil
 }
diff --git a/modules/private/key.go b/modules/private/key.go
new file mode 100644 (file)
index 0000000..86d0a73
--- /dev/null
@@ -0,0 +1,116 @@
+// 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 (
+       "encoding/json"
+       "fmt"
+
+       "code.gitea.io/gitea/models"
+       "code.gitea.io/gitea/modules/log"
+       "code.gitea.io/gitea/modules/setting"
+)
+
+// UpdateDeployKeyUpdated update deploy key updates
+func UpdateDeployKeyUpdated(keyID int64, repoID int64) error {
+       reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repositories/%d/keys/%d/update", repoID, keyID)
+       log.GitLogger.Trace("UpdateDeployKeyUpdated: %s", reqURL)
+
+       resp, err := newInternalRequest(reqURL, "POST").Response()
+       if err != nil {
+               return err
+       }
+
+       defer resp.Body.Close()
+
+       // All 2XX status codes are accepted and others will return an error
+       if resp.StatusCode/100 != 2 {
+               return fmt.Errorf("Failed to update deploy key: %s", decodeJSONError(resp).Err)
+       }
+       return nil
+}
+
+// HasDeployKey check if repo has deploy key
+func HasDeployKey(keyID, repoID int64) (bool, error) {
+       reqURL := setting.LocalURL + fmt.Sprintf("api/internal/repositories/%d/has-keys/%d", repoID, keyID)
+       log.GitLogger.Trace("HasDeployKey: %s", reqURL)
+
+       resp, err := newInternalRequest(reqURL, "GET").Response()
+       if err != nil {
+               return false, err
+       }
+       defer resp.Body.Close()
+
+       if resp.StatusCode == 200 {
+               return true, nil
+       }
+       return false, nil
+}
+
+// GetPublicKeyByID  get public ssh key by his ID
+func GetPublicKeyByID(keyID int64) (*models.PublicKey, error) {
+       reqURL := setting.LocalURL + fmt.Sprintf("api/internal/ssh/%d", keyID)
+       log.GitLogger.Trace("GetPublicKeyByID: %s", reqURL)
+
+       resp, err := newInternalRequest(reqURL, "GET").Response()
+       if err != nil {
+               return nil, err
+       }
+
+       defer resp.Body.Close()
+
+       if resp.StatusCode != 200 {
+               return nil, fmt.Errorf("Failed to get repository: %s", decodeJSONError(resp).Err)
+       }
+
+       var pKey models.PublicKey
+       if err := json.NewDecoder(resp.Body).Decode(&pKey); err != nil {
+               return nil, err
+       }
+       return &pKey, nil
+}
+
+// GetUserByKeyID get user attached to key
+func GetUserByKeyID(keyID int64) (*models.User, error) {
+       reqURL := setting.LocalURL + fmt.Sprintf("api/internal/ssh/%d/user", keyID)
+       log.GitLogger.Trace("GetUserByKeyID: %s", reqURL)
+
+       resp, err := newInternalRequest(reqURL, "GET").Response()
+       if err != nil {
+               return nil, err
+       }
+       defer resp.Body.Close()
+
+       if resp.StatusCode != 200 {
+               return nil, fmt.Errorf("Failed to get user: %s", decodeJSONError(resp).Err)
+       }
+
+       var user models.User
+       if err := json.NewDecoder(resp.Body).Decode(&user); err != nil {
+               return nil, err
+       }
+
+       return &user, nil
+}
+
+// UpdatePublicKeyUpdated update public key updates
+func UpdatePublicKeyUpdated(keyID int64) error {
+       // Ask for running deliver hook and test pull request tasks.
+       reqURL := setting.LocalURL + fmt.Sprintf("api/internal/ssh/%d/update", keyID)
+       log.GitLogger.Trace("UpdatePublicKeyUpdated: %s", reqURL)
+
+       resp, err := newInternalRequest(reqURL, "POST").Response()
+       if err != nil {
+               return err
+       }
+
+       defer resp.Body.Close()
+
+       // All 2XX status codes are accepted and others will return an error
+       if resp.StatusCode/100 != 2 {
+               return fmt.Errorf("Failed to update public key: %s", decodeJSONError(resp).Err)
+       }
+       return nil
+}
index 96021d8feb7a4bda84808fe18bd241f52e923c6f..23e0122642b37f97b7090cdc4bca13b52e42847f 100644 (file)
@@ -23,26 +23,74 @@ func CheckInternalToken(ctx *macaron.Context) {
        }
 }
 
-// UpdatePublicKey update publick key updates
-func UpdatePublicKey(ctx *macaron.Context) {
-       keyID := ctx.ParamsInt64(":id")
-       if err := models.UpdatePublicKeyUpdated(keyID); err != nil {
+//GetRepositoryByOwnerAndName chainload to models.GetRepositoryByOwnerAndName
+func GetRepositoryByOwnerAndName(ctx *macaron.Context) {
+       //TODO use repo.Get(ctx *context.APIContext) ?
+       ownerName := ctx.Params(":owner")
+       repoName := ctx.Params(":repo")
+       repo, err := models.GetRepositoryByOwnerAndName(ownerName, repoName)
+       if err != nil {
                ctx.JSON(500, map[string]interface{}{
                        "err": err.Error(),
                })
                return
        }
+       ctx.JSON(200, repo)
+}
+
+//AccessLevel chainload to models.AccessLevel
+func AccessLevel(ctx *macaron.Context) {
+       repoID := ctx.ParamsInt64(":repoid")
+       userID := ctx.ParamsInt64(":userid")
+       repo, err := models.GetRepositoryByID(repoID)
+       if err != nil {
+               ctx.JSON(500, map[string]interface{}{
+                       "err": err.Error(),
+               })
+               return
+       }
+       al, err := models.AccessLevel(userID, repo)
+       if err != nil {
+               ctx.JSON(500, map[string]interface{}{
+                       "err": err.Error(),
+               })
+               return
+       }
+       ctx.JSON(200, al)
+}
 
-       ctx.PlainText(200, []byte("success"))
+//CheckUnitUser chainload to models.CheckUnitUser
+func CheckUnitUser(ctx *macaron.Context) {
+       repoID := ctx.ParamsInt64(":repoid")
+       userID := ctx.ParamsInt64(":userid")
+       repo, err := models.GetRepositoryByID(repoID)
+       if err != nil {
+               ctx.JSON(500, map[string]interface{}{
+                       "err": err.Error(),
+               })
+               return
+       }
+       if repo.CheckUnitUser(userID, ctx.QueryBool("isAdmin"), models.UnitType(ctx.QueryInt("unitType"))) {
+               ctx.PlainText(200, []byte("success"))
+               return
+       }
+       ctx.PlainText(404, []byte("no access"))
 }
 
 // RegisterRoutes registers all internal APIs routes to web application.
 // 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/accesslevel", AccessLevel)
+               m.Get("/repositories/:repoid/user/:userid/checkunituser", CheckUnitUser)
+               m.Get("/repositories/:repoid/has-keys/:keyid", HasDeployKey)
                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)
diff --git a/routers/private/key.go b/routers/private/key.go
new file mode 100644 (file)
index 0000000..9cc1165
--- /dev/null
@@ -0,0 +1,84 @@
+// 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 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 (
+       "code.gitea.io/gitea/models"
+       "code.gitea.io/gitea/modules/util"
+
+       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) {
+       keyID := ctx.ParamsInt64(":id")
+       if err := models.UpdatePublicKeyUpdated(keyID); err != nil {
+               ctx.JSON(500, map[string]interface{}{
+                       "err": err.Error(),
+               })
+               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)
+       if err != nil {
+               ctx.JSON(500, map[string]interface{}{
+                       "err": err.Error(),
+               })
+               return
+       }
+       ctx.JSON(200, user)
+}
+
+//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"))
+}