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
This commit is contained in:
Lunny Xiao 2018-11-28 19:26:14 +08:00 committed by GitHub
parent 0222623be9
commit eabbddcd98
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
80 changed files with 1360 additions and 774 deletions

View file

@ -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) {