-
-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Add anonymous access support for private repositories (backend) #33257
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
// Copyright 2025 The Gitea Authors. All rights reserved. | ||
// SPDX-License-Identifier: MIT | ||
|
||
package v1_24 //nolint | ||
|
||
import ( | ||
"code.gitea.io/gitea/models/perm" | ||
|
||
"xorm.io/xorm" | ||
) | ||
|
||
func AddRepoUnitAnonymousAccessMode(x *xorm.Engine) error { | ||
type RepoUnit struct { //revive:disable-line:exported | ||
AnonymousAccessMode perm.AccessMode `xorm:"NOT NULL DEFAULT 0"` | ||
} | ||
return x.Sync(&RepoUnit{}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,7 +25,8 @@ type Permission struct { | |
units []*repo_model.RepoUnit | ||
unitsMode map[unit.Type]perm_model.AccessMode | ||
|
||
everyoneAccessMode map[unit.Type]perm_model.AccessMode | ||
everyoneAccessMode map[unit.Type]perm_model.AccessMode // the unit's minimal access mode for every signed-in user | ||
anonymousAccessMode map[unit.Type]perm_model.AccessMode // the unit's minimal access mode for anonymous (non-signed-in) user | ||
} | ||
|
||
// IsOwner returns true if current user is the owner of repository. | ||
|
@@ -39,7 +40,7 @@ func (p *Permission) IsAdmin() bool { | |
} | ||
|
||
// HasAnyUnitAccess returns true if the user might have at least one access mode to any unit of this repository. | ||
// It doesn't count the "everyone access mode". | ||
// It doesn't count the "public(anonymous/everyone) access mode". | ||
func (p *Permission) HasAnyUnitAccess() bool { | ||
for _, v := range p.unitsMode { | ||
if v >= perm_model.AccessModeRead { | ||
|
@@ -49,7 +50,12 @@ func (p *Permission) HasAnyUnitAccess() bool { | |
return p.AccessMode >= perm_model.AccessModeRead | ||
} | ||
|
||
func (p *Permission) HasAnyUnitAccessOrEveryoneAccess() bool { | ||
func (p *Permission) HasAnyUnitAccessOrPublicAccess() bool { | ||
for _, v := range p.anonymousAccessMode { | ||
if v >= perm_model.AccessModeRead { | ||
return true | ||
} | ||
} | ||
for _, v := range p.everyoneAccessMode { | ||
if v >= perm_model.AccessModeRead { | ||
return true | ||
|
@@ -73,14 +79,16 @@ func (p *Permission) GetFirstUnitRepoID() int64 { | |
} | ||
|
||
// UnitAccessMode returns current user access mode to the specify unit of the repository | ||
// It also considers "everyone access mode" | ||
// It also considers "public (anonymous/everyone) access mode" | ||
func (p *Permission) UnitAccessMode(unitType unit.Type) perm_model.AccessMode { | ||
// if the units map contains the access mode, use it, but admin/owner mode could override it | ||
if m, ok := p.unitsMode[unitType]; ok { | ||
return util.Iif(p.AccessMode >= perm_model.AccessModeAdmin, p.AccessMode, m) | ||
} | ||
// if the units map does not contain the access mode, return the default access mode if the unit exists | ||
unitDefaultAccessMode := max(p.AccessMode, p.everyoneAccessMode[unitType]) | ||
unitDefaultAccessMode := p.AccessMode | ||
unitDefaultAccessMode = max(unitDefaultAccessMode, p.anonymousAccessMode[unitType]) | ||
unitDefaultAccessMode = max(unitDefaultAccessMode, p.everyoneAccessMode[unitType]) | ||
hasUnit := slices.ContainsFunc(p.units, func(u *repo_model.RepoUnit) bool { return u.Type == unitType }) | ||
return util.Iif(hasUnit, unitDefaultAccessMode, perm_model.AccessModeNone) | ||
} | ||
|
@@ -171,27 +179,38 @@ func (p *Permission) LogString() string { | |
format += "\n\tunitsMode[%-v]: %-v" | ||
args = append(args, key.LogString(), value.LogString()) | ||
} | ||
format += "\n\tanonymousAccessMode: %-v" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here we can use the string builder for better performance. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function won't be called in production. So it doesn't affect performance. |
||
args = append(args, p.anonymousAccessMode) | ||
format += "\n\teveryoneAccessMode: %-v" | ||
args = append(args, p.everyoneAccessMode) | ||
format += "\n\t]>" | ||
return fmt.Sprintf(format, args...) | ||
} | ||
|
||
func applyPublicAccessPermission(unitType unit.Type, accessMode perm_model.AccessMode, modeMap *map[unit.Type]perm_model.AccessMode) { | ||
if accessMode >= perm_model.AccessModeRead && accessMode > (*modeMap)[unitType] { | ||
lunny marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if *modeMap == nil { | ||
*modeMap = make(map[unit.Type]perm_model.AccessMode) | ||
} | ||
(*modeMap)[unitType] = accessMode | ||
} | ||
} | ||
|
||
func finalProcessRepoUnitPermission(user *user_model.User, perm *Permission) { | ||
// apply public (anonymous) access permissions | ||
for _, u := range perm.units { | ||
applyPublicAccessPermission(u.Type, u.AnonymousAccessMode, &perm.anonymousAccessMode) | ||
} | ||
|
||
if user == nil || user.ID <= 0 { | ||
// for anonymous access, it could be: | ||
// AccessMode is None or Read, units has repo units, unitModes is nil | ||
return | ||
} | ||
|
||
// apply everyone access permissions | ||
// apply public (everyone) access permissions | ||
for _, u := range perm.units { | ||
if u.EveryoneAccessMode >= perm_model.AccessModeRead && u.EveryoneAccessMode > perm.everyoneAccessMode[u.Type] { | ||
if perm.everyoneAccessMode == nil { | ||
perm.everyoneAccessMode = make(map[unit.Type]perm_model.AccessMode) | ||
} | ||
perm.everyoneAccessMode[u.Type] = u.EveryoneAccessMode | ||
} | ||
applyPublicAccessPermission(u.Type, u.EveryoneAccessMode, &perm.everyoneAccessMode) | ||
} | ||
|
||
if perm.unitsMode == nil { | ||
|
@@ -209,6 +228,11 @@ func finalProcessRepoUnitPermission(user *user_model.User, perm *Permission) { | |
break | ||
} | ||
} | ||
for t := range perm.anonymousAccessMode { | ||
if shouldKeep = shouldKeep || u.Type == t; shouldKeep { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here's what I prefer to write: shouldKeep |= u.Type == t, But that's just my personal opinion, and there's nothing wrong with writing it that way There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then it needs 2 lines. Current code only uses one line ....... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right. |
||
break | ||
} | ||
} | ||
for t := range perm.everyoneAccessMode { | ||
if shouldKeep = shouldKeep || u.Type == t; shouldKeep { | ||
break | ||
|
Uh oh!
There was an error while loading. Please reload this page.