diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2018-11-28 19:26:14 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-28 19:26:14 +0800 |
commit | eabbddcd98717ef20d8475e819f403c50f4a9787 (patch) | |
tree | efc525e7ec60d56d3bec72019febfa088a128b89 /modules/context | |
parent | 0222623be9fa4a56d870213f77b92139cefc2518 (diff) | |
download | gitea-eabbddcd98717ef20d8475e819f403c50f4a9787.tar.gz gitea-eabbddcd98717ef20d8475e819f403c50f4a9787.zip |
Restrict permission check on repositories and fix some problems (#5314)
* fix units permission problems
* fix some bugs and merge LoadUnits to repoAssignment
* refactor permission struct and add some copyright heads
* remove unused codes
* fix routes units check
* improve permission check
* add unit tests for permission
* fix typo
* fix tests
* fix some routes
* fix api permission check
* improve permission check
* fix some permission check
* fix tests
* fix tests
* improve some permission check
* fix some permission check
* refactor AccessLevel
* fix bug
* fix tests
* fix tests
* fix tests
* fix AccessLevel
* rename CanAccess
* fix tests
* fix comment
* fix bug
* add missing unit for test repos
* fix bug
* rename some functions
* fix routes check
Diffstat (limited to 'modules/context')
-rw-r--r-- | modules/context/permission.go | 64 | ||||
-rw-r--r-- | modules/context/repo.go | 123 |
2 files changed, 80 insertions, 107 deletions
diff --git a/modules/context/permission.go b/modules/context/permission.go new file mode 100644 index 0000000000..70f8695300 --- /dev/null +++ b/modules/context/permission.go @@ -0,0 +1,64 @@ +// 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 context + +import ( + "code.gitea.io/gitea/models" + macaron "gopkg.in/macaron.v1" +) + +// RequireRepoAdmin returns a macaron middleware for requiring repository admin permission +func RequireRepoAdmin() macaron.Handler { + return func(ctx *Context) { + if !ctx.IsSigned || !ctx.Repo.IsAdmin() { + ctx.NotFound(ctx.Req.RequestURI, nil) + return + } + } +} + +// RequireRepoWriter returns a macaron middleware for requiring repository write to the specify unitType +func RequireRepoWriter(unitType models.UnitType) macaron.Handler { + return func(ctx *Context) { + if !ctx.Repo.CanWrite(unitType) { + ctx.NotFound(ctx.Req.RequestURI, nil) + return + } + } +} + +// RequireRepoWriterOr returns a macaron middleware for requiring repository write to one of the unit permission +func RequireRepoWriterOr(unitTypes ...models.UnitType) macaron.Handler { + return func(ctx *Context) { + for _, unitType := range unitTypes { + if ctx.Repo.CanWrite(unitType) { + return + } + } + ctx.NotFound(ctx.Req.RequestURI, nil) + } +} + +// RequireRepoReader returns a macaron middleware for requiring repository read to the specify unitType +func RequireRepoReader(unitType models.UnitType) macaron.Handler { + return func(ctx *Context) { + if !ctx.Repo.CanRead(unitType) { + ctx.NotFound(ctx.Req.RequestURI, nil) + return + } + } +} + +// RequireRepoReaderOr returns a macaron middleware for requiring repository write to one of the unit permission +func RequireRepoReaderOr(unitTypes ...models.UnitType) macaron.Handler { + return func(ctx *Context) { + for _, unitType := range unitTypes { + if ctx.Repo.CanRead(unitType) { + return + } + } + ctx.NotFound(ctx.Req.RequestURI, nil) + } +} diff --git a/modules/context/repo.go b/modules/context/repo.go index be08bc4c77..55d607a28a 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -32,7 +32,7 @@ type PullRequest struct { // Repository contains information to operate a repository type Repository struct { - AccessMode models.AccessMode + models.Permission IsWatching bool IsViewBranch bool IsViewTag bool @@ -54,34 +54,14 @@ type Repository struct { PullRequest *PullRequest } -// IsOwner returns true if current user is the owner of repository. -func (r *Repository) IsOwner() bool { - return r.AccessMode >= models.AccessModeOwner -} - -// IsAdmin returns true if current user has admin or higher access of repository. -func (r *Repository) IsAdmin() bool { - return r.AccessMode >= models.AccessModeAdmin -} - -// IsWriter returns true if current user has write or higher access of repository. -func (r *Repository) IsWriter() bool { - return r.AccessMode >= models.AccessModeWrite -} - -// HasAccess returns true if the current user has at least read access for this repository -func (r *Repository) HasAccess() bool { - return r.AccessMode >= models.AccessModeRead -} - // CanEnableEditor returns true if repository is editable and user has proper access level. func (r *Repository) CanEnableEditor() bool { - return r.Repository.CanEnableEditor() && r.IsViewBranch && r.IsWriter() + return r.Permission.CanWrite(models.UnitTypeCode) && r.Repository.CanEnableEditor() && r.IsViewBranch } // CanCreateBranch returns true if repository is editable and user has proper access level. func (r *Repository) CanCreateBranch() bool { - return r.Repository.CanCreateBranch() && r.IsWriter() + return r.Permission.CanWrite(models.UnitTypeCode) && r.Repository.CanCreateBranch() } // CanCommitToBranch returns true if repository is editable and user has proper access level @@ -101,12 +81,12 @@ func (r *Repository) CanUseTimetracker(issue *models.Issue, user *models.User) b // 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this? isAssigned, _ := models.IsUserAssignedToIssue(issue, user) return r.Repository.IsTimetrackerEnabled() && (!r.Repository.AllowOnlyContributorsToTrackTime() || - r.IsWriter() || issue.IsPoster(user.ID) || isAssigned) + r.Permission.CanWrite(models.UnitTypeIssues) || issue.IsPoster(user.ID) || isAssigned) } // CanCreateIssueDependencies returns whether or not a user can create dependencies. func (r *Repository) CanCreateIssueDependencies(user *models.User) bool { - return r.Repository.IsDependenciesEnabled() && r.IsWriter() + return r.Permission.CanWrite(models.UnitTypeIssues) && r.Repository.IsDependenciesEnabled() } // GetCommitsCount returns cached commit count for current view @@ -221,24 +201,15 @@ func RedirectToRepo(ctx *Context, redirectRepoID int64) { } func repoAssignment(ctx *Context, repo *models.Repository) { - // Admin has super access. - if ctx.IsSigned && ctx.User.IsAdmin { - ctx.Repo.AccessMode = models.AccessModeOwner - } else { - var userID int64 - if ctx.User != nil { - userID = ctx.User.ID - } - mode, err := models.AccessLevel(userID, repo) - if err != nil { - ctx.ServerError("AccessLevel", err) - return - } - ctx.Repo.AccessMode = mode + var err error + ctx.Repo.Permission, err = models.GetUserRepoPermission(repo, ctx.User) + if err != nil { + ctx.ServerError("GetUserRepoPermission", err) + return } // Check access. - if ctx.Repo.AccessMode == models.AccessModeNone { + if ctx.Repo.Permission.AccessMode == models.AccessModeNone { if ctx.Query("go-get") == "1" { EarlyResponseForGoGetMeta(ctx) return @@ -247,6 +218,7 @@ func repoAssignment(ctx *Context, repo *models.Repository) { return } ctx.Data["HasAccess"] = true + ctx.Data["Permission"] = &ctx.Repo.Permission if repo.IsMirror { var err error @@ -281,10 +253,6 @@ func RepoIDAssignment() macaron.Handler { return } - if err = repo.GetOwner(); err != nil { - ctx.ServerError("GetOwner", err) - return - } repoAssignment(ctx, repo) } } @@ -381,7 +349,9 @@ func RepoAssignment() macaron.Handler { ctx.Data["Owner"] = ctx.Repo.Repository.Owner ctx.Data["IsRepositoryOwner"] = ctx.Repo.IsOwner() ctx.Data["IsRepositoryAdmin"] = ctx.Repo.IsAdmin() - ctx.Data["IsRepositoryWriter"] = ctx.Repo.IsWriter() + ctx.Data["CanWriteCode"] = ctx.Repo.CanWrite(models.UnitTypeCode) + ctx.Data["CanWriteIssues"] = ctx.Repo.CanWrite(models.UnitTypeIssues) + ctx.Data["CanWritePulls"] = ctx.Repo.CanWrite(models.UnitTypePullRequests) if ctx.Data["CanSignedUserFork"], err = ctx.Repo.Repository.CanUserFork(ctx.User); err != nil { ctx.ServerError("CanUserFork", err) @@ -435,7 +405,7 @@ func RepoAssignment() macaron.Handler { } // People who have push access or have forked repository can propose a new pull request. - if ctx.Repo.IsWriter() || (ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID)) { + if ctx.Repo.CanWrite(models.UnitTypeCode) || (ctx.IsSigned && ctx.User.HasForkedRepo(ctx.Repo.Repository.ID)) { // Pull request is allowed if this is a fork repository // and base repository accepts pull requests. if repo.BaseRepo != nil && repo.BaseRepo.AllowsPulls() { @@ -453,9 +423,6 @@ func RepoAssignment() macaron.Handler { ctx.Repo.PullRequest.HeadInfo = ctx.Repo.BranchName } } - - // Reset repo units as otherwise user specific units wont be loaded later - ctx.Repo.Repository.Units = nil } ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest @@ -661,64 +628,6 @@ func RepoRefByType(refType RepoRefType) macaron.Handler { } } -// RequireRepoAdmin returns a macaron middleware for requiring repository admin permission -func RequireRepoAdmin() macaron.Handler { - return func(ctx *Context) { - if !ctx.IsSigned || (!ctx.Repo.IsAdmin() && !ctx.User.IsAdmin) { - ctx.NotFound(ctx.Req.RequestURI, nil) - return - } - } -} - -// RequireRepoWriter returns a macaron middleware for requiring repository write permission -func RequireRepoWriter() macaron.Handler { - return func(ctx *Context) { - if !ctx.IsSigned || (!ctx.Repo.IsWriter() && !ctx.User.IsAdmin) { - ctx.NotFound(ctx.Req.RequestURI, nil) - return - } - } -} - -// LoadRepoUnits loads repsitory's units, it should be called after repository and user loaded -func LoadRepoUnits() macaron.Handler { - return func(ctx *Context) { - var isAdmin bool - if ctx.User != nil && ctx.User.IsAdmin { - isAdmin = true - } - - var userID int64 - if ctx.User != nil { - userID = ctx.User.ID - } - err := ctx.Repo.Repository.LoadUnitsByUserID(userID, isAdmin) - if err != nil { - ctx.ServerError("LoadUnitsByUserID", err) - return - } - } -} - -// CheckUnit will check whether unit type is enabled -func CheckUnit(unitType models.UnitType) macaron.Handler { - return func(ctx *Context) { - if !ctx.Repo.Repository.UnitEnabled(unitType) { - ctx.NotFound("CheckUnit", fmt.Errorf("%s: %v", ctx.Tr("units.error.unit_not_allowed"), unitType)) - } - } -} - -// CheckAnyUnit will check whether any of the unit types are enabled -func CheckAnyUnit(unitTypes ...models.UnitType) macaron.Handler { - return func(ctx *Context) { - if !ctx.Repo.Repository.AnyUnitEnabled(unitTypes...) { - ctx.NotFound("CheckAnyUnit", fmt.Errorf("%s: %v", ctx.Tr("units.error.unit_not_allowed"), unitTypes)) - } - } -} - // GitHookService checks if repository Git hooks service has been enabled. func GitHookService() macaron.Handler { return func(ctx *Context) { |