You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

package.go 5.1KB

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