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 }