Files

185 lines
5.7 KiB
Go
Raw Permalink Normal View History

2022-03-30 10:42:47 +02:00
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
2022-03-30 10:42:47 +02:00
package context
import (
"errors"
2022-03-30 10:42:47 +02:00
"fmt"
"net/http"
"code.gitea.io/gitea/models/organization"
packages_model "code.gitea.io/gitea/models/packages"
"code.gitea.io/gitea/models/perm"
2022-07-28 15:04:03 +02:00
"code.gitea.io/gitea/models/unit"
2022-03-30 10:42:47 +02:00
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
2022-05-19 17:56:45 +02:00
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/templates"
2022-03-30 10:42:47 +02:00
)
// Package contains owner, access mode and optional the package descriptor
type Package struct {
Owner *user_model.User
AccessMode perm.AccessMode
Descriptor *packages_model.PackageDescriptor
}
type packageAssignmentCtx struct {
*Base
Doer *user_model.User
ContextUser *user_model.User
}
2022-03-30 10:42:47 +02:00
// PackageAssignment returns a middleware to handle Context.Package assignment
func PackageAssignment() func(ctx *Context) {
return func(ctx *Context) {
2025-02-17 14:13:17 +08:00
errorFn := func(status int, obj any) {
2022-03-30 10:42:47 +02:00
err, ok := obj.(error)
if !ok {
err = fmt.Errorf("%s", obj)
}
if status == http.StatusNotFound {
2025-02-17 14:13:17 +08:00
ctx.NotFound(err)
2022-03-30 10:42:47 +02:00
} else {
2025-02-17 14:13:17 +08:00
ctx.ServerError("PackageAssignment", err)
2022-03-30 10:42:47 +02:00
}
}
paCtx := &packageAssignmentCtx{Base: ctx.Base, Doer: ctx.Doer, ContextUser: ctx.ContextUser}
ctx.Package = packageAssignment(paCtx, errorFn)
2022-03-30 10:42:47 +02:00
}
}
// PackageAssignmentAPI returns a middleware to handle Context.Package assignment
func PackageAssignmentAPI() func(ctx *APIContext) {
return func(ctx *APIContext) {
paCtx := &packageAssignmentCtx{Base: ctx.Base, Doer: ctx.Doer, ContextUser: ctx.ContextUser}
2025-02-17 14:13:17 +08:00
ctx.Package = packageAssignment(paCtx, ctx.APIError)
2022-03-30 10:42:47 +02:00
}
}
2025-02-17 14:13:17 +08:00
func packageAssignment(ctx *packageAssignmentCtx, errCb func(int, any)) *Package {
pkgOwner := ctx.ContextUser
accessMode, err := determineAccessMode(ctx.Base, pkgOwner, ctx.Doer)
if err != nil {
2025-02-17 14:13:17 +08:00
errCb(http.StatusInternalServerError, fmt.Errorf("determineAccessMode: %w", err))
return nil
}
pkg := &Package{
Owner: pkgOwner,
AccessMode: accessMode,
}
2024-06-19 06:32:45 +08:00
packageType := ctx.PathParam("type")
name := ctx.PathParam("name")
if packageType == "" || name == "" {
return pkg
}
2024-06-19 06:32:45 +08:00
version := ctx.PathParam("version")
if version != "" {
pv, err := packages_model.GetVersionByNameAndVersion(ctx, pkg.Owner.ID, packages_model.Type(packageType), name, version)
if err != nil {
if errors.Is(err, packages_model.ErrPackageNotExist) {
2025-02-17 14:13:17 +08:00
errCb(http.StatusNotFound, fmt.Errorf("GetVersionByNameAndVersion: %w", err))
} else {
2025-02-17 14:13:17 +08:00
errCb(http.StatusInternalServerError, fmt.Errorf("GetVersionByNameAndVersion: %w", err))
}
return pkg
}
pkg.Descriptor, err = packages_model.GetPackageDescriptor(ctx, pv)
if err != nil {
2025-02-17 14:13:17 +08:00
errCb(http.StatusInternalServerError, fmt.Errorf("GetPackageDescriptor: %w", err))
return pkg
}
} else {
p, err := packages_model.GetPackageByName(ctx, pkg.Owner.ID, packages_model.Type(packageType), name)
if err != nil {
if errors.Is(err, packages_model.ErrPackageNotExist) {
errCb(http.StatusNotFound, fmt.Errorf("GetPackageByName: %w", err))
} else {
errCb(http.StatusInternalServerError, fmt.Errorf("GetPackageByName: %w", err))
}
return pkg
}
pkg.Descriptor = &packages_model.PackageDescriptor{
Package: p,
Owner: pkg.Owner,
}
}
return pkg
}
func determineAccessMode(ctx *Base, pkgOwner, doer *user_model.User) (perm.AccessMode, error) {
if setting.Service.RequireSignInViewStrict && (doer == nil || doer.IsGhost()) {
return perm.AccessModeNone, nil
}
if doer != nil && !doer.IsGhost() && (!doer.IsActive || doer.ProhibitLogin) {
return perm.AccessModeNone, nil
}
// TODO: ActionUser permission check
accessMode := perm.AccessModeNone
if pkgOwner.IsOrganization() {
org := organization.OrgFromUser(pkgOwner)
2022-07-28 15:04:03 +02:00
if doer != nil && !doer.IsGhost() {
// 1. If user is logged in, check all team packages permissions
var err error
accessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx, doer.ID)
2022-05-19 17:56:45 +02:00
if err != nil {
return accessMode, err
2022-05-19 17:56:45 +02:00
}
// If access mode is less than write check every team for more permissions
// The minimum possible access mode is read for org members
if accessMode < perm.AccessModeWrite {
teams, err := organization.GetUserOrgTeams(ctx, org.ID, doer.ID)
if err != nil {
return accessMode, err
}
for _, t := range teams {
perm := t.UnitAccessMode(ctx, unit.TypePackages)
if accessMode < perm {
accessMode = perm
}
2022-07-28 15:04:03 +02:00
}
}
}
if accessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, pkgOwner, doer) {
// 2. If user is unauthorized or no org member, check if org is visible
accessMode = perm.AccessModeRead
2022-05-19 17:56:45 +02:00
}
2022-03-30 10:42:47 +02:00
} else {
if doer != nil && !doer.IsGhost() {
2022-05-19 17:56:45 +02:00
// 1. Check if user is package owner
if doer.ID == pkgOwner.ID {
accessMode = perm.AccessModeOwner
} else if pkgOwner.Visibility == structs.VisibleTypePublic || pkgOwner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited
accessMode = perm.AccessModeRead
2022-03-30 10:42:47 +02:00
}
} else if pkgOwner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public
accessMode = perm.AccessModeRead
2022-03-30 10:42:47 +02:00
}
}
return accessMode, nil
2022-03-30 10:42:47 +02:00
}
// PackageContexter initializes a package context for a request.
func PackageContexter() func(next http.Handler) http.Handler {
2026-01-24 13:11:49 +08:00
renderer := templates.PageRenderer()
2022-03-30 10:42:47 +02:00
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) {
2024-12-24 11:43:57 +08:00
base := NewBaseContext(resp, req)
// FIXME: web Context is still needed when rendering 500 page in a package handler
// It should be refactored to use new error handling mechanisms
ctx := NewWebContext(base, renderer, nil)
2022-03-30 10:42:47 +02:00
next.ServeHTTP(ctx.Resp, ctx.Req)
})
}
}