From 0a9a86b94307fe95661060cdfe36026e296dc69e Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Wed, 21 Sep 2022 15:01:18 +0200 Subject: [PATCH] Respect `REQUIRE_SIGNIN_VIEW` for packages (#20873) Fix #20863 When REQUIRE_SIGNIN_VIEW = true, even with public repositories, you can only see them after you login. The packages should not be accessed without login. Co-authored-by: Lauris BH Co-authored-by: wxiaoguang --- modules/context/package.go | 98 +++++++++++-------- .../integration/api_packages_generic_test.go | 13 +++ 2 files changed, 70 insertions(+), 41 deletions(-) diff --git a/modules/context/package.go b/modules/context/package.go index ad06f4d63..d12bdc491 100644 --- a/modules/context/package.go +++ b/modules/context/package.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/templates" ) @@ -54,47 +55,11 @@ func packageAssignment(ctx *Context, errCb func(int, string, interface{})) { Owner: ctx.ContextUser, } - if ctx.Package.Owner.IsOrganization() { - org := organization.OrgFromUser(ctx.Package.Owner) - - // 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 - ctx.Package.AccessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID) - if err != nil { - errCb(http.StatusInternalServerError, "GetOrgUserMaxAuthorizeLevel", err) - return - } - // If access mode is less than write check every team for more permissions - if ctx.Package.AccessMode < perm.AccessModeWrite { - teams, err := organization.GetUserOrgTeams(ctx, org.ID, ctx.Doer.ID) - if err != nil { - errCb(http.StatusInternalServerError, "GetUserOrgTeams", err) - return - } - for _, t := range teams { - perm := t.UnitAccessModeCtx(ctx, unit.TypePackages) - if ctx.Package.AccessMode < perm { - ctx.Package.AccessMode = perm - } - } - } - } - // 2. If authorize level is none, check if org is visible to user - if ctx.Package.AccessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) { - ctx.Package.AccessMode = perm.AccessModeRead - } - } else { - if ctx.Doer != nil && !ctx.Doer.IsGhost() { - // 1. Check if user is package owner - if ctx.Doer.ID == ctx.Package.Owner.ID { - ctx.Package.AccessMode = perm.AccessModeOwner - } else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic || ctx.Package.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited - ctx.Package.AccessMode = perm.AccessModeRead - } - } else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public - ctx.Package.AccessMode = perm.AccessModeRead - } + var err error + ctx.Package.AccessMode, err = determineAccessMode(ctx) + if err != nil { + errCb(http.StatusInternalServerError, "determineAccessMode", err) + return } packageType := ctx.Params("type") @@ -119,6 +84,57 @@ func packageAssignment(ctx *Context, errCb func(int, string, interface{})) { } } +func determineAccessMode(ctx *Context) (perm.AccessMode, error) { + accessMode := perm.AccessModeNone + + if setting.Service.RequireSignInView && ctx.Doer == nil { + return accessMode, nil + } + + if ctx.Package.Owner.IsOrganization() { + org := organization.OrgFromUser(ctx.Package.Owner) + + // 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 + accessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID) + if err != nil { + return accessMode, err + } + // If access mode is less than write check every team for more permissions + if accessMode < perm.AccessModeWrite { + teams, err := organization.GetUserOrgTeams(ctx, org.ID, ctx.Doer.ID) + if err != nil { + return accessMode, err + } + for _, t := range teams { + perm := t.UnitAccessModeCtx(ctx, unit.TypePackages) + if accessMode < perm { + accessMode = perm + } + } + } + } + // 2. If authorize level is none, check if org is visible to user + if accessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) { + accessMode = perm.AccessModeRead + } + } else { + if ctx.Doer != nil && !ctx.Doer.IsGhost() { + // 1. Check if user is package owner + if ctx.Doer.ID == ctx.Package.Owner.ID { + accessMode = perm.AccessModeOwner + } else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic || ctx.Package.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited + accessMode = perm.AccessModeRead + } + } else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public + accessMode = perm.AccessModeRead + } + } + + return accessMode, nil +} + // PackageContexter initializes a package context for a request. func PackageContexter(ctx gocontext.Context) func(next http.Handler) http.Handler { _, rnd := templates.HTMLRenderer(ctx) diff --git a/tests/integration/api_packages_generic_test.go b/tests/integration/api_packages_generic_test.go index 9fcd2cc79..4c5c0c615 100644 --- a/tests/integration/api_packages_generic_test.go +++ b/tests/integration/api_packages_generic_test.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/models/packages" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/tests" "github.com/stretchr/testify/assert" @@ -126,6 +127,18 @@ func TestPackageGeneric(t *testing.T) { req := NewRequest(t, "GET", url+"/not.found") MakeRequest(t, req, http.StatusNotFound) }) + + t.Run("RequireSignInView", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + setting.Service.RequireSignInView = true + defer func() { + setting.Service.RequireSignInView = false + }() + + req = NewRequest(t, "GET", url+"/dummy.bin") + MakeRequest(t, req, http.StatusUnauthorized) + }) }) t.Run("Delete", func(t *testing.T) {