Skip to content

Commit 15d97c9

Browse files
authored
Merge branch 'main' into webhook-bark
2 parents f60be8c + 3917d27 commit 15d97c9

File tree

6 files changed

+116
-18
lines changed

6 files changed

+116
-18
lines changed

models/organization/org.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,10 @@ func HasOrgOrUserVisible(ctx context.Context, orgOrUser, user *user_model.User)
429429
return true
430430
}
431431

432+
if !setting.Service.RequireSignInViewStrict && orgOrUser.Visibility == structs.VisibleTypePublic {
433+
return true
434+
}
435+
432436
if (orgOrUser.Visibility == structs.VisibleTypePrivate || user.IsRestricted) && !OrgFromUser(orgOrUser).hasMemberWithUserID(ctx, user.ID) {
433437
return false
434438
}

models/organization/org_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import (
1313
repo_model "code.gitea.io/gitea/models/repo"
1414
"code.gitea.io/gitea/models/unittest"
1515
user_model "code.gitea.io/gitea/models/user"
16+
"code.gitea.io/gitea/modules/setting"
1617
"code.gitea.io/gitea/modules/structs"
18+
"code.gitea.io/gitea/modules/test"
1719

1820
"github.com/stretchr/testify/assert"
1921
"github.com/stretchr/testify/require"
@@ -382,6 +384,12 @@ func TestHasOrgVisibleTypePublic(t *testing.T) {
382384
assert.True(t, test1) // owner of org
383385
assert.True(t, test2) // user not a part of org
384386
assert.True(t, test3) // logged out user
387+
388+
restrictedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29, IsRestricted: true})
389+
require.True(t, restrictedUser.IsRestricted)
390+
assert.True(t, organization.HasOrgOrUserVisible(t.Context(), org.AsUser(), restrictedUser))
391+
defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)()
392+
assert.False(t, organization.HasOrgOrUserVisible(t.Context(), org.AsUser(), restrictedUser))
385393
}
386394

387395
func TestHasOrgVisibleTypeLimited(t *testing.T) {

models/perm/access/access.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import (
1313
"code.gitea.io/gitea/models/perm"
1414
repo_model "code.gitea.io/gitea/models/repo"
1515
user_model "code.gitea.io/gitea/models/user"
16+
"code.gitea.io/gitea/modules/setting"
17+
"code.gitea.io/gitea/modules/structs"
1618

1719
"xorm.io/builder"
1820
)
@@ -41,7 +43,12 @@ func accessLevel(ctx context.Context, user *user_model.User, repo *repo_model.Re
4143
restricted = user.IsRestricted
4244
}
4345

44-
if !restricted && !repo.IsPrivate {
46+
if err := repo.LoadOwner(ctx); err != nil {
47+
return mode, err
48+
}
49+
50+
repoIsFullyPublic := !setting.Service.RequireSignInViewStrict && repo.Owner.Visibility == structs.VisibleTypePublic && !repo.IsPrivate
51+
if (restricted && repoIsFullyPublic) || (!restricted && !repo.IsPrivate) {
4552
mode = perm.AccessModeRead
4653
}
4754

models/perm/access/access_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
repo_model "code.gitea.io/gitea/models/repo"
1313
"code.gitea.io/gitea/models/unittest"
1414
user_model "code.gitea.io/gitea/models/user"
15+
"code.gitea.io/gitea/modules/setting"
1516

1617
"github.com/stretchr/testify/assert"
1718
)
@@ -51,7 +52,14 @@ func TestAccessLevel(t *testing.T) {
5152
assert.NoError(t, err)
5253
assert.Equal(t, perm_model.AccessModeNone, level)
5354

54-
// restricted user has no access to a public repo
55+
// restricted user has default access to a public repo if no sign-in is required
56+
setting.Service.RequireSignInViewStrict = false
57+
level, err = access_model.AccessLevel(t.Context(), user29, repo1)
58+
assert.NoError(t, err)
59+
assert.Equal(t, perm_model.AccessModeRead, level)
60+
61+
// restricted user has no access to a public repo if sign-in is required
62+
setting.Service.RequireSignInViewStrict = true
5563
level, err = access_model.AccessLevel(t.Context(), user29, repo1)
5664
assert.NoError(t, err)
5765
assert.Equal(t, perm_model.AccessModeNone, level)

models/repo/repo_list.go

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,17 @@ func SearchRepositoryIDsByCondition(ctx context.Context, cond builder.Cond) ([]i
642642
Find(&repoIDs)
643643
}
644644

645+
func userAllPublicRepoCond(cond builder.Cond, orgVisibilityLimit []structs.VisibleType) builder.Cond {
646+
return cond.Or(builder.And(
647+
builder.Eq{"`repository`.is_private": false},
648+
// Aren't in a private organisation or limited organisation if we're not logged in
649+
builder.NotIn("`repository`.owner_id", builder.Select("id").From("`user`").Where(
650+
builder.And(
651+
builder.Eq{"type": user_model.UserTypeOrganization},
652+
builder.In("visibility", orgVisibilityLimit)),
653+
))))
654+
}
655+
645656
// AccessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible
646657
func AccessibleRepositoryCondition(user *user_model.User, unitType unit.Type) builder.Cond {
647658
cond := builder.NewCond()
@@ -651,15 +662,8 @@ func AccessibleRepositoryCondition(user *user_model.User, unitType unit.Type) bu
651662
if user == nil || user.ID <= 0 {
652663
orgVisibilityLimit = append(orgVisibilityLimit, structs.VisibleTypeLimited)
653664
}
654-
// 1. Be able to see all non-private repositories that either:
655-
cond = cond.Or(builder.And(
656-
builder.Eq{"`repository`.is_private": false},
657-
// 2. Aren't in an private organisation or limited organisation if we're not logged in
658-
builder.NotIn("`repository`.owner_id", builder.Select("id").From("`user`").Where(
659-
builder.And(
660-
builder.Eq{"type": user_model.UserTypeOrganization},
661-
builder.In("visibility", orgVisibilityLimit)),
662-
))))
665+
// 1. Be able to see all non-private repositories
666+
cond = userAllPublicRepoCond(cond, orgVisibilityLimit)
663667
}
664668

665669
if user != nil {
@@ -683,6 +687,9 @@ func AccessibleRepositoryCondition(user *user_model.User, unitType unit.Type) bu
683687
if !user.IsRestricted {
684688
// 5. Be able to see all public repos in private organizations that we are an org_user of
685689
cond = cond.Or(userOrgPublicRepoCond(user.ID))
690+
} else if !setting.Service.RequireSignInViewStrict {
691+
orgVisibilityLimit := []structs.VisibleType{structs.VisibleTypePrivate, structs.VisibleTypeLimited}
692+
cond = userAllPublicRepoCond(cond, orgVisibilityLimit)
686693
}
687694
}
688695

models/repo/repo_list_test.go

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,14 @@ import (
1010
"code.gitea.io/gitea/models/db"
1111
repo_model "code.gitea.io/gitea/models/repo"
1212
"code.gitea.io/gitea/models/unittest"
13+
user_model "code.gitea.io/gitea/models/user"
1314
"code.gitea.io/gitea/modules/optional"
15+
"code.gitea.io/gitea/modules/setting"
16+
"code.gitea.io/gitea/modules/structs"
17+
"code.gitea.io/gitea/modules/test"
1418

1519
"github.com/stretchr/testify/assert"
20+
"github.com/stretchr/testify/require"
1621
)
1722

1823
func getTestCases() []struct {
@@ -182,7 +187,16 @@ func getTestCases() []struct {
182187

183188
func TestSearchRepository(t *testing.T) {
184189
assert.NoError(t, unittest.PrepareTestDatabase())
190+
t.Run("SearchRepositoryPublic", testSearchRepositoryPublic)
191+
t.Run("SearchRepositoryPublicRestricted", testSearchRepositoryRestricted)
192+
t.Run("SearchRepositoryPrivate", testSearchRepositoryPrivate)
193+
t.Run("SearchRepositoryNonExistingOwner", testSearchRepositoryNonExistingOwner)
194+
t.Run("SearchRepositoryWithInDescription", testSearchRepositoryWithInDescription)
195+
t.Run("SearchRepositoryNotInDescription", testSearchRepositoryNotInDescription)
196+
t.Run("SearchRepositoryCases", testSearchRepositoryCases)
197+
}
185198

199+
func testSearchRepositoryPublic(t *testing.T) {
186200
// test search public repository on explore page
187201
repos, count, err := repo_model.SearchRepositoryByName(t.Context(), repo_model.SearchRepoOptions{
188202
ListOptions: db.ListOptions{
@@ -211,9 +225,54 @@ func TestSearchRepository(t *testing.T) {
211225
assert.NoError(t, err)
212226
assert.Equal(t, int64(2), count)
213227
assert.Len(t, repos, 2)
228+
}
229+
230+
func testSearchRepositoryRestricted(t *testing.T) {
231+
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
232+
restrictedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29, IsRestricted: true})
233+
234+
performSearch := func(t *testing.T, user *user_model.User) (publicRepoIDs []int64) {
235+
repos, count, err := repo_model.SearchRepositoryByName(t.Context(), repo_model.SearchRepoOptions{
236+
ListOptions: db.ListOptions{Page: 1, PageSize: 10000},
237+
Actor: user,
238+
})
239+
require.NoError(t, err)
240+
assert.Len(t, repos, int(count))
241+
for _, repo := range repos {
242+
require.NoError(t, repo.LoadOwner(t.Context()))
243+
if repo.Owner.Visibility == structs.VisibleTypePublic && !repo.IsPrivate {
244+
publicRepoIDs = append(publicRepoIDs, repo.ID)
245+
}
246+
}
247+
return publicRepoIDs
248+
}
249+
250+
normalPublicRepoIDs := performSearch(t, user2)
251+
require.Greater(t, len(normalPublicRepoIDs), 10) // quite a lot
252+
253+
t.Run("RestrictedUser-NoSignInRequirement", func(t *testing.T) {
254+
// restricted user can also see public repositories if no "required sign-in"
255+
repoIDs := performSearch(t, restrictedUser)
256+
assert.ElementsMatch(t, normalPublicRepoIDs, repoIDs)
257+
})
258+
259+
defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)()
214260

261+
t.Run("NormalUser-RequiredSignIn", func(t *testing.T) {
262+
// normal user can still see all public repos, not affected by "required sign-in"
263+
repoIDs := performSearch(t, user2)
264+
assert.ElementsMatch(t, normalPublicRepoIDs, repoIDs)
265+
})
266+
t.Run("RestrictedUser-RequiredSignIn", func(t *testing.T) {
267+
// restricted user can see only their own repo
268+
repoIDs := performSearch(t, restrictedUser)
269+
assert.Equal(t, []int64{4}, repoIDs)
270+
})
271+
}
272+
273+
func testSearchRepositoryPrivate(t *testing.T) {
215274
// test search private repository on explore page
216-
repos, count, err = repo_model.SearchRepositoryByName(t.Context(), repo_model.SearchRepoOptions{
275+
repos, count, err := repo_model.SearchRepositoryByName(t.Context(), repo_model.SearchRepoOptions{
217276
ListOptions: db.ListOptions{
218277
Page: 1,
219278
PageSize: 10,
@@ -242,16 +301,18 @@ func TestSearchRepository(t *testing.T) {
242301
assert.NoError(t, err)
243302
assert.Equal(t, int64(3), count)
244303
assert.Len(t, repos, 3)
304+
}
245305

246-
// Test non existing owner
247-
repos, count, err = repo_model.SearchRepositoryByName(t.Context(), repo_model.SearchRepoOptions{OwnerID: unittest.NonexistentID})
306+
func testSearchRepositoryNonExistingOwner(t *testing.T) {
307+
repos, count, err := repo_model.SearchRepositoryByName(t.Context(), repo_model.SearchRepoOptions{OwnerID: unittest.NonexistentID})
248308

249309
assert.NoError(t, err)
250310
assert.Empty(t, repos)
251311
assert.Equal(t, int64(0), count)
312+
}
252313

253-
// Test search within description
254-
repos, count, err = repo_model.SearchRepository(t.Context(), repo_model.SearchRepoOptions{
314+
func testSearchRepositoryWithInDescription(t *testing.T) {
315+
repos, count, err := repo_model.SearchRepository(t.Context(), repo_model.SearchRepoOptions{
255316
ListOptions: db.ListOptions{
256317
Page: 1,
257318
PageSize: 10,
@@ -266,9 +327,10 @@ func TestSearchRepository(t *testing.T) {
266327
assert.Equal(t, "test_repo_14", repos[0].Name)
267328
}
268329
assert.Equal(t, int64(1), count)
330+
}
269331

270-
// Test NOT search within description
271-
repos, count, err = repo_model.SearchRepository(t.Context(), repo_model.SearchRepoOptions{
332+
func testSearchRepositoryNotInDescription(t *testing.T) {
333+
repos, count, err := repo_model.SearchRepository(t.Context(), repo_model.SearchRepoOptions{
272334
ListOptions: db.ListOptions{
273335
Page: 1,
274336
PageSize: 10,
@@ -281,7 +343,9 @@ func TestSearchRepository(t *testing.T) {
281343
assert.NoError(t, err)
282344
assert.Empty(t, repos)
283345
assert.Equal(t, int64(0), count)
346+
}
284347

348+
func testSearchRepositoryCases(t *testing.T) {
285349
testCases := getTestCases()
286350

287351
for _, testCase := range testCases {

0 commit comments

Comments
 (0)