Skip to content

Make gitea serv use api/internal #4886

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 19 commits into from
Oct 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 21 additions & 34 deletions cmd/serv.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
}
Expand All @@ -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)
}
Expand All @@ -252,20 +236,24 @@ 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,
"User %s does not have level %v access to repository %s",
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)
Expand Down Expand Up @@ -325,7 +313,6 @@ func runServ(c *cli.Context) error {
} else {
gitcmd = exec.Command(verb, repoPath)
}

if isUncyclo {
if err = repo.InitUncyclo(); err != nil {
fail("Internal error", "Failed to init wiki repo: %v", err)
Expand Down
2 changes: 1 addition & 1 deletion modules/private/branch.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
67 changes: 56 additions & 11 deletions modules/private/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}
116 changes: 116 additions & 0 deletions modules/private/key.go
Original file line number Diff line number Diff line change
@@ -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
}
Loading