summaryrefslogtreecommitdiffstats
path: root/services/context/permission.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel@debian.org>2024-10-18 20:33:49 +0200
committerDaniel Baumann <daniel@debian.org>2024-12-12 23:57:56 +0100
commite68b9d00a6e05b3a941f63ffb696f91e554ac5ec (patch)
tree97775d6c13b0f416af55314eb6a89ef792474615 /services/context/permission.go
parentInitial commit. (diff)
downloadforgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.tar.xz
forgejo-e68b9d00a6e05b3a941f63ffb696f91e554ac5ec.zip
Adding upstream version 9.0.3.
Signed-off-by: Daniel Baumann <daniel@debian.org>
Diffstat (limited to '')
-rw-r--r--services/context/permission.go149
1 files changed, 149 insertions, 0 deletions
diff --git a/services/context/permission.go b/services/context/permission.go
new file mode 100644
index 0000000..14a9801
--- /dev/null
+++ b/services/context/permission.go
@@ -0,0 +1,149 @@
+// Copyright 2018 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package context
+
+import (
+ "net/http"
+
+ auth_model "code.gitea.io/gitea/models/auth"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unit"
+ "code.gitea.io/gitea/modules/log"
+)
+
+// RequireRepoAdmin returns a middleware for requiring repository admin permission
+func RequireRepoAdmin() func(ctx *Context) {
+ return func(ctx *Context) {
+ if !ctx.IsSigned || !ctx.Repo.IsAdmin() {
+ ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ return
+ }
+ }
+}
+
+// RequireRepoWriter returns a middleware for requiring repository write to the specify unitType
+func RequireRepoWriter(unitType unit.Type) func(ctx *Context) {
+ return func(ctx *Context) {
+ if !ctx.Repo.CanWrite(unitType) {
+ ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ return
+ }
+ }
+}
+
+// CanEnableEditor checks if the user is allowed to write to the branch of the repo
+func CanEnableEditor() func(ctx *Context) {
+ return func(ctx *Context) {
+ if !ctx.Repo.CanWriteToBranch(ctx, ctx.Doer, ctx.Repo.BranchName) {
+ ctx.NotFound("CanWriteToBranch denies permission", nil)
+ return
+ }
+ }
+}
+
+// RequireRepoWriterOr returns a middleware for requiring repository write to one of the unit permission
+func RequireRepoWriterOr(unitTypes ...unit.Type) func(ctx *Context) {
+ return func(ctx *Context) {
+ for _, unitType := range unitTypes {
+ if ctx.Repo.CanWrite(unitType) {
+ return
+ }
+ }
+ ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ }
+}
+
+// RequireRepoReader returns a middleware for requiring repository read to the specify unitType
+func RequireRepoReader(unitType unit.Type) func(ctx *Context) {
+ return func(ctx *Context) {
+ if !ctx.Repo.CanRead(unitType) {
+ if log.IsTrace() {
+ if ctx.IsSigned {
+ log.Trace("Permission Denied: User %-v cannot read %-v in Repo %-v\n"+
+ "User in Repo has Permissions: %-+v",
+ ctx.Doer,
+ unitType,
+ ctx.Repo.Repository,
+ ctx.Repo.Permission)
+ } else {
+ log.Trace("Permission Denied: Anonymous user cannot read %-v in Repo %-v\n"+
+ "Anonymous user in Repo has Permissions: %-+v",
+ unitType,
+ ctx.Repo.Repository,
+ ctx.Repo.Permission)
+ }
+ }
+ ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ return
+ }
+ }
+}
+
+// RequireRepoReaderOr returns a middleware for requiring repository write to one of the unit permission
+func RequireRepoReaderOr(unitTypes ...unit.Type) func(ctx *Context) {
+ return func(ctx *Context) {
+ for _, unitType := range unitTypes {
+ if ctx.Repo.CanRead(unitType) {
+ return
+ }
+ }
+ if log.IsTrace() {
+ var format string
+ var args []any
+ if ctx.IsSigned {
+ format = "Permission Denied: User %-v cannot read ["
+ args = append(args, ctx.Doer)
+ } else {
+ format = "Permission Denied: Anonymous user cannot read ["
+ }
+ for _, unit := range unitTypes {
+ format += "%-v, "
+ args = append(args, unit)
+ }
+
+ format = format[:len(format)-2] + "] in Repo %-v\n" +
+ "User in Repo has Permissions: %-+v"
+ args = append(args, ctx.Repo.Repository, ctx.Repo.Permission)
+ log.Trace(format, args...)
+ }
+ ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ }
+}
+
+// CheckRepoScopedToken check whether personal access token has repo scope
+func CheckRepoScopedToken(ctx *Context, repo *repo_model.Repository, level auth_model.AccessTokenScopeLevel) {
+ if !ctx.IsBasicAuth || ctx.Data["IsApiToken"] != true {
+ return
+ }
+
+ scope, ok := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope)
+ if ok { // it's a personal access token but not oauth2 token
+ var scopeMatched bool
+
+ requiredScopes := auth_model.GetRequiredScopes(level, auth_model.AccessTokenScopeCategoryRepository)
+
+ // check if scope only applies to public resources
+ publicOnly, err := scope.PublicOnly()
+ if err != nil {
+ ctx.ServerError("HasScope", err)
+ return
+ }
+
+ if publicOnly && repo.IsPrivate {
+ ctx.Error(http.StatusForbidden)
+ return
+ }
+
+ scopeMatched, err = scope.HasScope(requiredScopes...)
+ if err != nil {
+ ctx.ServerError("HasScope", err)
+ return
+ }
+
+ if !scopeMatched {
+ ctx.Error(http.StatusForbidden)
+ return
+ }
+ }
+}