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

     1  // Copyright 2021 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package context
     5  
     6  import (
     7  	gocontext "context"
     8  	"fmt"
     9  	"net/http"
    10  
    11  	"code.gitea.io/gitea/models/organization"
    12  	packages_model "code.gitea.io/gitea/models/packages"
    13  	"code.gitea.io/gitea/models/perm"
    14  	"code.gitea.io/gitea/models/unit"
    15  	user_model "code.gitea.io/gitea/models/user"
    16  	"code.gitea.io/gitea/modules/setting"
    17  	"code.gitea.io/gitea/modules/structs"
    18  	"code.gitea.io/gitea/modules/templates"
    19  )
    20  
    21  // Package contains owner, access mode and optional the package descriptor
    22  type Package struct {
    23  	Owner      *user_model.User
    24  	AccessMode perm.AccessMode
    25  	Descriptor *packages_model.PackageDescriptor
    26  }
    27  
    28  // PackageAssignment returns a middleware to handle Context.Package assignment
    29  func PackageAssignment() func(ctx *Context) {
    30  	return func(ctx *Context) {
    31  		packageAssignment(ctx, func(status int, title string, obj interface{}) {
    32  			err, ok := obj.(error)
    33  			if !ok {
    34  				err = fmt.Errorf("%s", obj)
    35  			}
    36  			if status == http.StatusNotFound {
    37  				ctx.NotFound(title, err)
    38  			} else {
    39  				ctx.ServerError(title, err)
    40  			}
    41  		})
    42  	}
    43  }
    44  
    45  // PackageAssignmentAPI returns a middleware to handle Context.Package assignment
    46  func PackageAssignmentAPI() func(ctx *APIContext) {
    47  	return func(ctx *APIContext) {
    48  		packageAssignment(ctx.Context, ctx.Error)
    49  	}
    50  }
    51  
    52  func packageAssignment(ctx *Context, errCb func(int, string, interface{})) {
    53  	ctx.Package = &Package{
    54  		Owner: ctx.ContextUser,
    55  	}
    56  
    57  	var err error
    58  	ctx.Package.AccessMode, err = determineAccessMode(ctx)
    59  	if err != nil {
    60  		errCb(http.StatusInternalServerError, "determineAccessMode", err)
    61  		return
    62  	}
    63  
    64  	packageType := ctx.Params("type")
    65  	name := ctx.Params("name")
    66  	version := ctx.Params("version")
    67  	if packageType != "" && name != "" && version != "" {
    68  		pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.Type(packageType), name, version)
    69  		if err != nil {
    70  			if err == packages_model.ErrPackageNotExist {
    71  				errCb(http.StatusNotFound, "GetVersionByNameAndVersion", err)
    72  			} else {
    73  				errCb(http.StatusInternalServerError, "GetVersionByNameAndVersion", err)
    74  			}
    75  			return
    76  		}
    77  
    78  		ctx.Package.Descriptor, err = packages_model.GetPackageDescriptor(ctx, pv)
    79  		if err != nil {
    80  			errCb(http.StatusInternalServerError, "GetPackageDescriptor", err)
    81  			return
    82  		}
    83  	}
    84  }
    85  
    86  func determineAccessMode(ctx *Context) (perm.AccessMode, error) {
    87  	if setting.Service.RequireSignInView && ctx.Doer == nil {
    88  		return perm.AccessModeNone, nil
    89  	}
    90  
    91  	if ctx.Doer != nil && !ctx.Doer.IsGhost() && (!ctx.Doer.IsActive || ctx.Doer.ProhibitLogin) {
    92  		return perm.AccessModeNone, nil
    93  	}
    94  
    95  	accessMode := perm.AccessModeNone
    96  	if ctx.Package.Owner.IsOrganization() {
    97  		org := organization.OrgFromUser(ctx.Package.Owner)
    98  
    99  		// 1. Get user max authorize level for the org (may be none, if user is not member of the org)
   100  		if ctx.Doer != nil {
   101  			var err error
   102  			accessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID)
   103  			if err != nil {
   104  				return accessMode, err
   105  			}
   106  			// If access mode is less than write check every team for more permissions
   107  			if accessMode < perm.AccessModeWrite {
   108  				teams, err := organization.GetUserOrgTeams(ctx, org.ID, ctx.Doer.ID)
   109  				if err != nil {
   110  					return accessMode, err
   111  				}
   112  				for _, t := range teams {
   113  					perm := t.UnitAccessMode(ctx, unit.TypePackages)
   114  					if accessMode < perm {
   115  						accessMode = perm
   116  					}
   117  				}
   118  			}
   119  		}
   120  		// 2. If authorize level is none, check if org is visible to user
   121  		if accessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) {
   122  			accessMode = perm.AccessModeRead
   123  		}
   124  	} else {
   125  		if ctx.Doer != nil && !ctx.Doer.IsGhost() {
   126  			// 1. Check if user is package owner
   127  			if ctx.Doer.ID == ctx.Package.Owner.ID {
   128  				accessMode = perm.AccessModeOwner
   129  			} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic || ctx.Package.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited
   130  				accessMode = perm.AccessModeRead
   131  			}
   132  		} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public
   133  			accessMode = perm.AccessModeRead
   134  		}
   135  	}
   136  
   137  	return accessMode, nil
   138  }
   139  
   140  // PackageContexter initializes a package context for a request.
   141  func PackageContexter(ctx gocontext.Context) func(next http.Handler) http.Handler {
   142  	_, rnd := templates.HTMLRenderer(ctx)
   143  	return func(next http.Handler) http.Handler {
   144  		return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
   145  			ctx := Context{
   146  				Resp:   NewResponse(resp),
   147  				Data:   map[string]interface{}{},
   148  				Render: rnd,
   149  			}
   150  			defer ctx.Close()
   151  
   152  			ctx.Req = WithContext(req, &ctx)
   153  
   154  			next.ServeHTTP(ctx.Resp, ctx.Req)
   155  		})
   156  	}
   157  }