code.gitea.io/gitea@v1.19.3/modules/context/permission.go (about)

     1  // Copyright 2018 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package context
     5  
     6  import (
     7  	"net/http"
     8  
     9  	auth_model "code.gitea.io/gitea/models/auth"
    10  	repo_model "code.gitea.io/gitea/models/repo"
    11  	"code.gitea.io/gitea/models/unit"
    12  	"code.gitea.io/gitea/modules/log"
    13  )
    14  
    15  // RequireRepoAdmin returns a middleware for requiring repository admin permission
    16  func RequireRepoAdmin() func(ctx *Context) {
    17  	return func(ctx *Context) {
    18  		if !ctx.IsSigned || !ctx.Repo.IsAdmin() {
    19  			ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
    20  			return
    21  		}
    22  	}
    23  }
    24  
    25  // RequireRepoWriter returns a middleware for requiring repository write to the specify unitType
    26  func RequireRepoWriter(unitType unit.Type) func(ctx *Context) {
    27  	return func(ctx *Context) {
    28  		if !ctx.Repo.CanWrite(unitType) {
    29  			ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
    30  			return
    31  		}
    32  	}
    33  }
    34  
    35  // CanEnableEditor checks if the user is allowed to write to the branch of the repo
    36  func CanEnableEditor() func(ctx *Context) {
    37  	return func(ctx *Context) {
    38  		if !ctx.Repo.CanWriteToBranch(ctx.Doer, ctx.Repo.BranchName) {
    39  			ctx.NotFound("CanWriteToBranch denies permission", nil)
    40  			return
    41  		}
    42  	}
    43  }
    44  
    45  // RequireRepoWriterOr returns a middleware for requiring repository write to one of the unit permission
    46  func RequireRepoWriterOr(unitTypes ...unit.Type) func(ctx *Context) {
    47  	return func(ctx *Context) {
    48  		for _, unitType := range unitTypes {
    49  			if ctx.Repo.CanWrite(unitType) {
    50  				return
    51  			}
    52  		}
    53  		ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
    54  	}
    55  }
    56  
    57  // RequireRepoReader returns a middleware for requiring repository read to the specify unitType
    58  func RequireRepoReader(unitType unit.Type) func(ctx *Context) {
    59  	return func(ctx *Context) {
    60  		if !ctx.Repo.CanRead(unitType) {
    61  			if log.IsTrace() {
    62  				if ctx.IsSigned {
    63  					log.Trace("Permission Denied: User %-v cannot read %-v in Repo %-v\n"+
    64  						"User in Repo has Permissions: %-+v",
    65  						ctx.Doer,
    66  						unitType,
    67  						ctx.Repo.Repository,
    68  						ctx.Repo.Permission)
    69  				} else {
    70  					log.Trace("Permission Denied: Anonymous user cannot read %-v in Repo %-v\n"+
    71  						"Anonymous user in Repo has Permissions: %-+v",
    72  						unitType,
    73  						ctx.Repo.Repository,
    74  						ctx.Repo.Permission)
    75  				}
    76  			}
    77  			ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
    78  			return
    79  		}
    80  	}
    81  }
    82  
    83  // RequireRepoReaderOr returns a middleware for requiring repository write to one of the unit permission
    84  func RequireRepoReaderOr(unitTypes ...unit.Type) func(ctx *Context) {
    85  	return func(ctx *Context) {
    86  		for _, unitType := range unitTypes {
    87  			if ctx.Repo.CanRead(unitType) {
    88  				return
    89  			}
    90  		}
    91  		if log.IsTrace() {
    92  			var format string
    93  			var args []interface{}
    94  			if ctx.IsSigned {
    95  				format = "Permission Denied: User %-v cannot read ["
    96  				args = append(args, ctx.Doer)
    97  			} else {
    98  				format = "Permission Denied: Anonymous user cannot read ["
    99  			}
   100  			for _, unit := range unitTypes {
   101  				format += "%-v, "
   102  				args = append(args, unit)
   103  			}
   104  
   105  			format = format[:len(format)-2] + "] in Repo %-v\n" +
   106  				"User in Repo has Permissions: %-+v"
   107  			args = append(args, ctx.Repo.Repository, ctx.Repo.Permission)
   108  			log.Trace(format, args...)
   109  		}
   110  		ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
   111  	}
   112  }
   113  
   114  // RequireRepoScopedToken check whether personal access token has repo scope
   115  func CheckRepoScopedToken(ctx *Context, repo *repo_model.Repository) {
   116  	if !ctx.IsBasicAuth || ctx.Data["IsApiToken"] != true {
   117  		return
   118  	}
   119  
   120  	var err error
   121  	scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope)
   122  	if ok { // it's a personal access token but not oauth2 token
   123  		var scopeMatched bool
   124  		scopeMatched, err = scope.HasScope(auth_model.AccessTokenScopeRepo)
   125  		if err != nil {
   126  			ctx.ServerError("HasScope", err)
   127  			return
   128  		}
   129  		if !scopeMatched && !repo.IsPrivate {
   130  			scopeMatched, err = scope.HasScope(auth_model.AccessTokenScopePublicRepo)
   131  			if err != nil {
   132  				ctx.ServerError("HasScope", err)
   133  				return
   134  			}
   135  		}
   136  		if !scopeMatched {
   137  			ctx.Error(http.StatusForbidden)
   138  			return
   139  		}
   140  	}
   141  }