diff --git a/models/organization/org.go b/models/organization/org.go index e668269679d..3314e3f65f0 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -140,10 +140,6 @@ func (org *Organization) GetMembers(ctx context.Context, doer *user_model.User) // HasMemberWithUserID returns true if user with userID is part of the u organisation. func (org *Organization) HasMemberWithUserID(ctx context.Context, userID int64) bool { - return org.hasMemberWithUserID(ctx, userID) -} - -func (org *Organization) hasMemberWithUserID(ctx context.Context, userID int64) bool { isMember, err := IsOrganizationMember(ctx, org.ID, userID) if err != nil { log.Error("IsOrganizationMember: %v", err) @@ -303,7 +299,7 @@ func (org *Organization) AnyRepoUnitPermission(ctx context.Context, doer *user_m } } - if org.Visibility.IsPublic() { + if ownerVisibilitySatisfiesDoer(org.AsUser(), doer) { return perm.AccessModeRead } @@ -445,8 +441,7 @@ func GetUsersWhoCanCreateOrgRepo(ctx context.Context, orgID int64) (map[int64]*u And("team_user.org_id = ?", orgID).Find(&users) } -// HasOrgOrUserVisible tells if the given user can see the given org or user -func HasOrgOrUserVisible(ctx context.Context, orgOrUser, user *user_model.User) bool { +func ownerVisibilitySatisfiesDoer(orgOrUser, user *user_model.User) bool { // If user is nil, it's an anonymous user/request. // The Ghost user is handled like an anonymous user. if user == nil || user.IsGhost() { @@ -461,18 +456,17 @@ func HasOrgOrUserVisible(ctx context.Context, orgOrUser, user *user_model.User) return true } - if (orgOrUser.Visibility == structs.VisibleTypePrivate || user.IsRestricted) && !OrgFromUser(orgOrUser).hasMemberWithUserID(ctx, user.ID) { - return false - } - return true + return orgOrUser.Visibility != structs.VisibleTypePrivate && !user.IsRestricted +} + +// HasOrgOrUserVisible tells if the given user can see the given org or user +func HasOrgOrUserVisible(ctx context.Context, owner, doer *user_model.User) bool { + return ownerVisibilitySatisfiesDoer(owner, doer) || + (doer != nil && OrgFromUser(owner).HasMemberWithUserID(ctx, doer.ID)) } // HasOrgsVisible tells if the given user can see at least one of the orgs provided func HasOrgsVisible(ctx context.Context, orgs []*Organization, user *user_model.User) bool { - if len(orgs) == 0 { - return false - } - for _, org := range orgs { if HasOrgOrUserVisible(ctx, org.AsUser(), user) { return true diff --git a/models/organization/org_test.go b/models/organization/org_test.go index e24de5b054b..028b0c4434e 100644 --- a/models/organization/org_test.go +++ b/models/organization/org_test.go @@ -10,7 +10,9 @@ import ( "gitea.dev/models/db" "gitea.dev/models/organization" + "gitea.dev/models/perm" repo_model "gitea.dev/models/repo" + "gitea.dev/models/unit" "gitea.dev/models/unittest" user_model "gitea.dev/models/user" "gitea.dev/modules/setting" @@ -626,3 +628,10 @@ func TestCreateOrganization4(t *testing.T) { assert.True(t, db.IsErrNameReserved(err)) unittest.CheckConsistencyFor(t, &organization.Organization{}, &organization.Team{}) } + +func TestOrAnyRepoUnitPermission(t *testing.T) { + defer test.MockVariableValue(&setting.Service.RequireSignInViewStrict, true)() + org := organization.Organization{Visibility: structs.VisibleTypeLimited} + assert.Equal(t, perm.AccessModeNone, org.AnyRepoUnitPermission(t.Context(), nil, unit.TypeWiki)) + assert.Equal(t, perm.AccessModeRead, org.AnyRepoUnitPermission(t.Context(), &user_model.User{}, unit.TypeWiki)) +} diff --git a/routers/web/web.go b/routers/web/web.go index b882995a1c6..bc5d80fd1b0 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -441,19 +441,13 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { } } - reqUnitAccess := func(unitType unit.Type, accessMode perm.AccessMode, ignoreGlobal bool) func(ctx *context.Context) { + reqAnyRepoUnitAccess := func(unitType unit.Type, accessMode perm.AccessMode, ignoreGlobal bool) func(ctx *context.Context) { return func(ctx *context.Context) { // only check global disabled units when ignoreGlobal is false if !ignoreGlobal && unitType.UnitGlobalDisabled() { ctx.NotFound(nil) return } - - if ctx.ContextUser == nil { - ctx.NotFound(nil) - return - } - if ctx.ContextUser.IsOrganization() { if ctx.Org.Organization.AnyRepoUnitPermission(ctx, ctx.Doer, unitType) < accessMode { ctx.NotFound(nil) @@ -1125,7 +1119,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { } // at the moment, only editing "owner-level projects" need to "mention", maybe in the future we can relax the permission check - m.Get("/mentions-in-owner", reqUnitAccess(unit.TypeProjects, perm.AccessModeWrite, true), org.GetMentionsInOwner) + m.Get("/mentions-in-owner", reqAnyRepoUnitAccess(unit.TypeProjects, perm.AccessModeWrite, true), org.GetMentionsInOwner) m.Get("/repositories", org.Repositories) m.Get("/heatmap", user.DashboardHeatmap) @@ -1134,7 +1128,7 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { m.Group("", func() { m.Get("", org.Projects) m.Get("/{id}", org.ViewProject) - }, reqUnitAccess(unit.TypeProjects, perm.AccessModeRead, true)) + }, reqAnyRepoUnitAccess(unit.TypeProjects, perm.AccessModeRead, true)) m.Group("", func() { m.Get("/new", org.RenderNewProject) m.Post("/new", web.Bind[*forms.CreateProjectForm](), org.NewProjectPost) @@ -1147,17 +1141,17 @@ func registerWebRoutes(m *web.Router, webAuth *AuthMiddleware) { addProjectBoardRoutes(m) }) - }, reqSignIn, reqUnitAccess(unit.TypeProjects, perm.AccessModeWrite, true), func(ctx *context.Context) { + }, reqSignIn, reqAnyRepoUnitAccess(unit.TypeProjects, perm.AccessModeWrite, true), func(ctx *context.Context) { if ctx.ContextUser.IsIndividual() && ctx.ContextUser.ID != ctx.Doer.ID { ctx.NotFound(nil) return } }) - }, reqUnitAccess(unit.TypeProjects, perm.AccessModeRead, true), individualPermsChecker) + }, reqAnyRepoUnitAccess(unit.TypeProjects, perm.AccessModeRead, true), individualPermsChecker) m.Group("", func() { m.Get("/code", user.CodeSearch) - }, reqUnitAccess(unit.TypeCode, perm.AccessModeRead, false), individualPermsChecker) + }, reqAnyRepoUnitAccess(unit.TypeCode, perm.AccessModeRead, false), individualPermsChecker) }, optSignIn, context.UserAssignmentWeb(), context.OrgAssignment(context.OrgAssignmentOptions{})) // end "/{username}/-": packages, projects, code