2022-03-30 14:12:47 +05:30
// Copyright 2021 The Gitea Authors. All rights reserved.
2022-11-27 23:50:29 +05:30
// SPDX-License-Identifier: MIT
2022-03-30 14:12:47 +05:30
package context
import (
"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 18:34:03 +05:30
"code.gitea.io/gitea/models/unit"
2022-03-30 14:12:47 +05:30
user_model "code.gitea.io/gitea/models/user"
2022-09-21 18:31:18 +05:30
"code.gitea.io/gitea/modules/setting"
2022-05-19 21:26:45 +05:30
"code.gitea.io/gitea/modules/structs"
2022-08-28 15:13:25 +05:30
"code.gitea.io/gitea/modules/templates"
2022-03-30 14:12:47 +05:30
)
// Package contains owner, access mode and optional the package descriptor
type Package struct {
Owner * user_model . User
AccessMode perm . AccessMode
Descriptor * packages_model . PackageDescriptor
}
2023-05-21 07:20:53 +05:30
type packageAssignmentCtx struct {
* Base
Doer * user_model . User
ContextUser * user_model . User
}
2022-03-30 14:12:47 +05:30
// PackageAssignment returns a middleware to handle Context.Package assignment
func PackageAssignment ( ) func ( ctx * Context ) {
return func ( ctx * Context ) {
2023-07-05 00:06:08 +05:30
errorFn := func ( status int , title string , obj any ) {
2022-03-30 14:12:47 +05:30
err , ok := obj . ( error )
if ! ok {
err = fmt . Errorf ( "%s" , obj )
}
if status == http . StatusNotFound {
ctx . NotFound ( title , err )
} else {
ctx . ServerError ( title , err )
}
2023-05-21 07:20:53 +05:30
}
paCtx := & packageAssignmentCtx { Base : ctx . Base , Doer : ctx . Doer , ContextUser : ctx . ContextUser }
ctx . Package = packageAssignment ( paCtx , errorFn )
2022-03-30 14:12:47 +05:30
}
}
// PackageAssignmentAPI returns a middleware to handle Context.Package assignment
func PackageAssignmentAPI ( ) func ( ctx * APIContext ) {
return func ( ctx * APIContext ) {
2023-05-21 07:20:53 +05:30
paCtx := & packageAssignmentCtx { Base : ctx . Base , Doer : ctx . Doer , ContextUser : ctx . ContextUser }
ctx . Package = packageAssignment ( paCtx , ctx . Error )
2022-03-30 14:12:47 +05:30
}
}
2023-07-05 00:06:08 +05:30
func packageAssignment ( ctx * packageAssignmentCtx , errCb func ( int , string , any ) ) * Package {
2023-05-21 07:20:53 +05:30
pkg := & Package {
2022-03-30 14:12:47 +05:30
Owner : ctx . ContextUser ,
}
2022-09-21 18:31:18 +05:30
var err error
2023-05-21 07:20:53 +05:30
pkg . AccessMode , err = determineAccessMode ( ctx . Base , pkg , ctx . Doer )
2022-09-21 18:31:18 +05:30
if err != nil {
errCb ( http . StatusInternalServerError , "determineAccessMode" , err )
2023-05-21 07:20:53 +05:30
return pkg
2022-09-21 18:31:18 +05:30
}
packageType := ctx . Params ( "type" )
name := ctx . Params ( "name" )
version := ctx . Params ( "version" )
if packageType != "" && name != "" && version != "" {
2023-05-21 07:20:53 +05:30
pv , err := packages_model . GetVersionByNameAndVersion ( ctx , pkg . Owner . ID , packages_model . Type ( packageType ) , name , version )
2022-09-21 18:31:18 +05:30
if err != nil {
if err == packages_model . ErrPackageNotExist {
errCb ( http . StatusNotFound , "GetVersionByNameAndVersion" , err )
} else {
errCb ( http . StatusInternalServerError , "GetVersionByNameAndVersion" , err )
}
2023-05-21 07:20:53 +05:30
return pkg
2022-09-21 18:31:18 +05:30
}
2023-05-21 07:20:53 +05:30
pkg . Descriptor , err = packages_model . GetPackageDescriptor ( ctx , pv )
2022-09-21 18:31:18 +05:30
if err != nil {
errCb ( http . StatusInternalServerError , "GetPackageDescriptor" , err )
2023-05-21 07:20:53 +05:30
return pkg
2022-09-21 18:31:18 +05:30
}
}
2023-05-21 07:20:53 +05:30
return pkg
2022-09-21 18:31:18 +05:30
}
2023-05-21 07:20:53 +05:30
func determineAccessMode ( ctx * Base , pkg * Package , doer * user_model . User ) ( perm . AccessMode , error ) {
if setting . Service . RequireSignInView && doer == nil {
2022-10-25 00:53:25 +05:30
return perm . AccessModeNone , nil
2022-09-21 18:31:18 +05:30
}
2023-05-21 07:20:53 +05:30
if doer != nil && ! doer . IsGhost ( ) && ( ! doer . IsActive || doer . ProhibitLogin ) {
2022-10-25 00:53:25 +05:30
return perm . AccessModeNone , nil
}
2023-04-06 19:48:29 +05:30
// TODO: ActionUser permission check
2022-10-25 00:53:25 +05:30
accessMode := perm . AccessModeNone
2023-05-21 07:20:53 +05:30
if pkg . Owner . IsOrganization ( ) {
org := organization . OrgFromUser ( pkg . Owner )
2022-07-28 18:34:03 +05:30
2023-05-21 07:20:53 +05:30
if doer != nil && ! doer . IsGhost ( ) {
2023-04-06 19:48:29 +05:30
// 1. If user is logged in, check all team packages permissions
2023-07-09 18:30:07 +05:30
var err error
accessMode , err = org . GetOrgUserMaxAuthorizeLevel ( doer . ID )
2022-05-19 21:26:45 +05:30
if err != nil {
2022-09-21 18:31:18 +05:30
return accessMode , err
2022-05-19 21:26:45 +05:30
}
2023-07-09 18:30:07 +05:30
// 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 18:34:03 +05:30
}
}
2023-07-09 18:30:07 +05:30
}
if accessMode == perm . AccessModeNone && organization . HasOrgOrUserVisible ( ctx , pkg . Owner , doer ) {
// 2. If user is unauthorized or no org member, check if org is visible
2022-09-21 18:31:18 +05:30
accessMode = perm . AccessModeRead
2022-05-19 21:26:45 +05:30
}
2022-03-30 14:12:47 +05:30
} else {
2023-05-21 07:20:53 +05:30
if doer != nil && ! doer . IsGhost ( ) {
2022-05-19 21:26:45 +05:30
// 1. Check if user is package owner
2023-05-21 07:20:53 +05:30
if doer . ID == pkg . Owner . ID {
2022-09-21 18:31:18 +05:30
accessMode = perm . AccessModeOwner
2023-05-21 07:20:53 +05:30
} else if pkg . Owner . Visibility == structs . VisibleTypePublic || pkg . Owner . Visibility == structs . VisibleTypeLimited { // 2. Check if package owner is public or limited
2022-09-21 18:31:18 +05:30
accessMode = perm . AccessModeRead
2022-03-30 14:12:47 +05:30
}
2023-05-21 07:20:53 +05:30
} else if pkg . Owner . Visibility == structs . VisibleTypePublic { // 3. Check if package owner is public
2022-09-21 18:31:18 +05:30
accessMode = perm . AccessModeRead
2022-03-30 14:12:47 +05:30
}
}
2022-09-21 18:31:18 +05:30
return accessMode , nil
2022-03-30 14:12:47 +05:30
}
// PackageContexter initializes a package context for a request.
2023-05-21 07:20:53 +05:30
func PackageContexter ( ) func ( next http . Handler ) http . Handler {
renderer := templates . HTMLRenderer ( )
2022-03-30 14:12:47 +05:30
return func ( next http . Handler ) http . Handler {
return http . HandlerFunc ( func ( resp http . ResponseWriter , req * http . Request ) {
2023-05-21 07:20:53 +05:30
base , baseCleanUp := NewBaseContext ( resp , req )
ctx := & Context {
Base : base ,
Render : renderer , // it is still needed when rendering 500 page in a package handler
2022-03-30 14:12:47 +05:30
}
2023-05-21 07:20:53 +05:30
defer baseCleanUp ( )
2022-03-30 14:12:47 +05:30
2023-05-23 06:59:15 +05:30
ctx . Base . AppendContextValue ( WebContextKey , ctx )
2022-03-30 14:12:47 +05:30
next . ServeHTTP ( ctx . Resp , ctx . Req )
} )
}
}