2022-03-30 17:42:47 +09:00
// Copyright 2021 The Gitea Authors. All rights reserved.
2022-11-28 03:20:29 +09:00
// SPDX-License-Identifier: MIT
2022-03-30 17:42:47 +09:00
package context
import (
2022-08-28 18:43:25 +09:00
gocontext "context"
2022-03-30 17:42:47 +09: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 22:04:03 +09:00
"code.gitea.io/gitea/models/unit"
2022-03-30 17:42:47 +09:00
user_model "code.gitea.io/gitea/models/user"
2022-09-21 22:01:18 +09:00
"code.gitea.io/gitea/modules/setting"
2022-05-20 00:56:45 +09:00
"code.gitea.io/gitea/modules/structs"
2022-08-28 18:43:25 +09:00
"code.gitea.io/gitea/modules/templates"
2022-03-30 17:42:47 +09: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
}
// PackageAssignment returns a middleware to handle Context.Package assignment
func PackageAssignment ( ) func ( ctx * Context ) {
return func ( ctx * Context ) {
packageAssignment ( ctx , func ( status int , title string , obj interface { } ) {
err , ok := obj . ( error )
if ! ok {
err = fmt . Errorf ( "%s" , obj )
}
if status == http . StatusNotFound {
ctx . NotFound ( title , err )
} else {
ctx . ServerError ( title , err )
}
} )
}
}
// PackageAssignmentAPI returns a middleware to handle Context.Package assignment
func PackageAssignmentAPI ( ) func ( ctx * APIContext ) {
return func ( ctx * APIContext ) {
packageAssignment ( ctx . Context , ctx . Error )
}
}
func packageAssignment ( ctx * Context , errCb func ( int , string , interface { } ) ) {
ctx . Package = & Package {
Owner : ctx . ContextUser ,
}
2022-09-21 22:01:18 +09:00
var err error
ctx . Package . AccessMode , err = determineAccessMode ( ctx )
if err != nil {
errCb ( http . StatusInternalServerError , "determineAccessMode" , err )
return
}
packageType := ctx . Params ( "type" )
name := ctx . Params ( "name" )
version := ctx . Params ( "version" )
if packageType != "" && name != "" && version != "" {
pv , err := packages_model . GetVersionByNameAndVersion ( ctx , ctx . Package . Owner . ID , packages_model . Type ( packageType ) , name , version )
if err != nil {
if err == packages_model . ErrPackageNotExist {
errCb ( http . StatusNotFound , "GetVersionByNameAndVersion" , err )
} else {
errCb ( http . StatusInternalServerError , "GetVersionByNameAndVersion" , err )
}
return
}
ctx . Package . Descriptor , err = packages_model . GetPackageDescriptor ( ctx , pv )
if err != nil {
errCb ( http . StatusInternalServerError , "GetPackageDescriptor" , err )
return
}
}
}
func determineAccessMode ( ctx * Context ) ( perm . AccessMode , error ) {
if setting . Service . RequireSignInView && ctx . Doer == nil {
2022-10-25 04:23:25 +09:00
return perm . AccessModeNone , nil
2022-09-21 22:01:18 +09:00
}
2022-10-25 04:23:25 +09:00
if ctx . Doer != nil && ! ctx . Doer . IsGhost ( ) && ( ! ctx . Doer . IsActive || ctx . Doer . ProhibitLogin ) {
return perm . AccessModeNone , nil
}
accessMode := perm . AccessModeNone
2022-05-20 00:56:45 +09:00
if ctx . Package . Owner . IsOrganization ( ) {
2022-07-28 22:04:03 +09:00
org := organization . OrgFromUser ( ctx . Package . Owner )
2022-05-20 00:56:45 +09:00
// 1. Get user max authorize level for the org (may be none, if user is not member of the org)
if ctx . Doer != nil {
var err error
2022-09-21 22:01:18 +09:00
accessMode , err = org . GetOrgUserMaxAuthorizeLevel ( ctx . Doer . ID )
2022-05-20 00:56:45 +09:00
if err != nil {
2022-09-21 22:01:18 +09:00
return accessMode , err
2022-05-20 00:56:45 +09:00
}
2022-07-28 22:04:03 +09:00
// If access mode is less than write check every team for more permissions
2022-09-21 22:01:18 +09:00
if accessMode < perm . AccessModeWrite {
2022-07-28 22:04:03 +09:00
teams , err := organization . GetUserOrgTeams ( ctx , org . ID , ctx . Doer . ID )
if err != nil {
2022-09-21 22:01:18 +09:00
return accessMode , err
2022-07-28 22:04:03 +09:00
}
for _ , t := range teams {
perm := t . UnitAccessModeCtx ( ctx , unit . TypePackages )
2022-09-21 22:01:18 +09:00
if accessMode < perm {
accessMode = perm
2022-07-28 22:04:03 +09:00
}
}
}
2022-05-20 00:56:45 +09:00
}
// 2. If authorize level is none, check if org is visible to user
2022-09-21 22:01:18 +09:00
if accessMode == perm . AccessModeNone && organization . HasOrgOrUserVisible ( ctx , ctx . Package . Owner , ctx . Doer ) {
accessMode = perm . AccessModeRead
2022-05-20 00:56:45 +09:00
}
2022-03-30 17:42:47 +09:00
} else {
2022-05-20 00:56:45 +09:00
if ctx . Doer != nil && ! ctx . Doer . IsGhost ( ) {
// 1. Check if user is package owner
if ctx . Doer . ID == ctx . Package . Owner . ID {
2022-09-21 22:01:18 +09:00
accessMode = perm . AccessModeOwner
2022-05-20 00:56:45 +09:00
} else if ctx . Package . Owner . Visibility == structs . VisibleTypePublic || ctx . Package . Owner . Visibility == structs . VisibleTypeLimited { // 2. Check if package owner is public or limited
2022-09-21 22:01:18 +09:00
accessMode = perm . AccessModeRead
2022-03-30 17:42:47 +09:00
}
2022-05-20 00:56:45 +09:00
} else if ctx . Package . Owner . Visibility == structs . VisibleTypePublic { // 3. Check if package owner is public
2022-09-21 22:01:18 +09:00
accessMode = perm . AccessModeRead
2022-03-30 17:42:47 +09:00
}
}
2022-09-21 22:01:18 +09:00
return accessMode , nil
2022-03-30 17:42:47 +09:00
}
// PackageContexter initializes a package context for a request.
2022-08-28 18:43:25 +09:00
func PackageContexter ( ctx gocontext . Context ) func ( next http . Handler ) http . Handler {
_ , rnd := templates . HTMLRenderer ( ctx )
2022-03-30 17:42:47 +09:00
return func ( next http . Handler ) http . Handler {
return http . HandlerFunc ( func ( resp http . ResponseWriter , req * http . Request ) {
ctx := Context {
2022-08-28 18:43:25 +09:00
Resp : NewResponse ( resp ) ,
Data : map [ string ] interface { } { } ,
Render : rnd ,
2022-03-30 17:42:47 +09:00
}
2022-05-05 23:13:23 +09:00
defer ctx . Close ( )
2022-03-30 17:42:47 +09:00
ctx . Req = WithContext ( req , & ctx )
next . ServeHTTP ( ctx . Resp , ctx . Req )
} )
}
}