mirror of
https://github.com/go-gitea/gitea.git
synced 2026-09-08 22:13:26 +09:00
fix(packages): restrict limited owner package access (#39043)
Apply restricted-viewer visibility rules when resolving package access. --------- Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
@@ -126,6 +126,10 @@ func IsBlobAccessibleForUser(ctx context.Context, blobID int64, user *user_model
|
|||||||
if user.IsAdmin {
|
if user.IsAdmin {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
ownerVisibilities := []structs.VisibleType{structs.VisibleTypePublic}
|
||||||
|
if !user.IsRestricted {
|
||||||
|
ownerVisibilities = append(ownerVisibilities, structs.VisibleTypeLimited)
|
||||||
|
}
|
||||||
|
|
||||||
maxTeamAuthorize := builder.
|
maxTeamAuthorize := builder.
|
||||||
Select("max(team.authorize)").
|
Select("max(team.authorize)").
|
||||||
@@ -144,7 +148,7 @@ func IsBlobAccessibleForUser(ctx context.Context, blobID int64, user *user_model
|
|||||||
// owner = user
|
// owner = user
|
||||||
builder.Eq{"`user`.id": user.ID}.
|
builder.Eq{"`user`.id": user.ID}.
|
||||||
// user can see owner
|
// user can see owner
|
||||||
Or(builder.Eq{"`user`.visibility": structs.VisibleTypePublic}.Or(builder.Eq{"`user`.visibility": structs.VisibleTypeLimited})).
|
Or(builder.In("`user`.visibility", ownerVisibilities)).
|
||||||
// owner is an organization and user has access to it
|
// owner is an organization and user has access to it
|
||||||
Or(builder.Eq{"`user`.type": user_model.UserTypeOrganization}.
|
Or(builder.Eq{"`user`.type": user_model.UserTypeOrganization}.
|
||||||
And(builder.Lte{strconv.Itoa(int(perm.AccessModeRead)): maxTeamAuthorize}.Or(builder.Lte{strconv.Itoa(int(perm.AccessModeRead)): maxTeamUnitAccessMode}))),
|
And(builder.Lte{strconv.Itoa(int(perm.AccessModeRead)): maxTeamAuthorize}.Or(builder.Lte{strconv.Itoa(int(perm.AccessModeRead)): maxTeamUnitAccessMode}))),
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gitea.dev/models/unittest"
|
"gitea.dev/models/unittest"
|
||||||
|
user_model "gitea.dev/models/user"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -49,3 +50,25 @@ func TestGetOrInsertBlobConcurrent(t *testing.T) {
|
|||||||
}
|
}
|
||||||
assert.Equal(t, numGoroutines-1, existedCount)
|
assert.Equal(t, numGoroutines-1, existedCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIsBlobAccessibleForRestrictedUser(t *testing.T) {
|
||||||
|
require.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 33})
|
||||||
|
pkg, err := TryInsertPackage(t.Context(), &Package{OwnerID: owner.ID, Type: TypeContainer, Name: "limited", LowerName: "limited"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
version, err := GetOrInsertVersion(t.Context(), &PackageVersion{PackageID: pkg.ID, Version: "1", LowerVersion: "1"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
blob, _, err := GetOrInsertBlob(t.Context(), &PackageBlob{Size: 1, HashMD5: "md5", HashSHA1: "sha1", HashSHA256: "sha256", HashSHA512: "sha512"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = TryInsertFile(t.Context(), &PackageFile{VersionID: version.ID, BlobID: blob.ID, Name: "blob", LowerName: "blob"})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
accessible, err := IsBlobAccessibleForUser(t.Context(), blob.ID, unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}))
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.True(t, accessible)
|
||||||
|
|
||||||
|
accessible, err = IsBlobAccessibleForUser(t.Context(), blob.ID, unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}))
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.False(t, accessible)
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import (
|
|||||||
"gitea.dev/models/unit"
|
"gitea.dev/models/unit"
|
||||||
user_model "gitea.dev/models/user"
|
user_model "gitea.dev/models/user"
|
||||||
"gitea.dev/modules/setting"
|
"gitea.dev/modules/setting"
|
||||||
"gitea.dev/modules/structs"
|
|
||||||
"gitea.dev/modules/templates"
|
"gitea.dev/modules/templates"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -155,10 +154,10 @@ func determineAccessMode(ctx *Base, pkgOwner, doer *user_model.User) (perm.Acces
|
|||||||
// 1. Check if user is package owner
|
// 1. Check if user is package owner
|
||||||
if doer.ID == pkgOwner.ID {
|
if doer.ID == pkgOwner.ID {
|
||||||
accessMode = perm.AccessModeOwner
|
accessMode = perm.AccessModeOwner
|
||||||
} else if pkgOwner.Visibility == structs.VisibleTypePublic || pkgOwner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited
|
} else if pkgOwner.Visibility.IsPublic() || (pkgOwner.Visibility.IsLimited() && !doer.IsRestricted) { // 2. Check if package owner is visible to the doer
|
||||||
accessMode = perm.AccessModeRead
|
accessMode = perm.AccessModeRead
|
||||||
}
|
}
|
||||||
} else if pkgOwner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public
|
} else if pkgOwner.Visibility.IsPublic() { // 3. Check if package owner is public
|
||||||
accessMode = perm.AccessModeRead
|
accessMode = perm.AccessModeRead
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2026 The Gitea Authors. All rights reserved.
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
package context
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gitea.dev/models/perm"
|
||||||
|
"gitea.dev/models/user"
|
||||||
|
"gitea.dev/modules/structs"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestDeterminePackageAccessModeForLimitedOwner(t *testing.T) {
|
||||||
|
owner := &user.User{ID: 1, Visibility: structs.VisibleTypeLimited}
|
||||||
|
|
||||||
|
accessMode, err := determineAccessMode(&Base{}, owner, &user.User{ID: 2, IsActive: true})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, perm.AccessModeRead, accessMode)
|
||||||
|
|
||||||
|
accessMode, err = determineAccessMode(&Base{}, owner, &user.User{ID: 3, IsActive: true, IsRestricted: true})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, perm.AccessModeNone, accessMode)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user