mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-26 06:16:56 +09:00
fix: add missing checks to several handlers and models (#39839)
Several handlers and model helpers skipped checks that their siblings already perform. - Only match principal keys when looking up SSH certificate principals - Return no attachments for an unsaved issue instead of every issue-less one - Reject issue and comment attachments when adding release attachments - Share one permission check for editing, deleting and reacting to issue content and for comment attachments between the web UI and the API, refusing them on locked issues for users who can't write - Reject issue edits, deletion and label changes in archived repositories via the API - Apply cross-origin protection to the repository topics endpoint - Return 404 for the repositories tab of individual users and respect profile visibility for the heatmap Fixes: https://github.com/go-gitea/gitea/issues/39226 Co-authored-by: wxiaoguang <wxiaoguang@gmail.com> Co-authored-by: bircni <bircni@icloud.com>
This commit is contained in:
28 files changed
+290
-221
No files matched your search
@@ -10,14 +10,17 @@ import (
|
||||
activities_model "gitea.dev/models/activities"
|
||||
"gitea.dev/models/db"
|
||||
issues_model "gitea.dev/models/issues"
|
||||
"gitea.dev/models/perm"
|
||||
access_model "gitea.dev/models/perm/access"
|
||||
project_model "gitea.dev/models/project"
|
||||
repo_model "gitea.dev/models/repo"
|
||||
system_model "gitea.dev/models/system"
|
||||
"gitea.dev/models/unit"
|
||||
user_model "gitea.dev/models/user"
|
||||
"gitea.dev/modules/git"
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/storage"
|
||||
"gitea.dev/modules/util"
|
||||
notify_service "gitea.dev/services/notify"
|
||||
)
|
||||
|
||||
@@ -309,3 +312,23 @@ func DeleteIssuesByRepoID(ctx context.Context, repoID int64) (attachmentPaths []
|
||||
|
||||
return attachmentPaths, err
|
||||
}
|
||||
|
||||
// CanSelfChangeOrAccessContent checks whether the doer can access the content:
|
||||
// * If the doer is the content poster, then the doer can access the content if they have read access to issues.
|
||||
// * If the doer is not the content poster, then the doer can access the content if they have the required access mode to the unit type (issues or pull requests).
|
||||
// * If the issue is locked, then the doer can only access the content if they have write access.
|
||||
func CanSelfChangeOrAccessContent(doer *user_model.User, doerPerm access_model.Permission, refIssue *issues_model.Issue, contentPosterID int64, accessMode perm.AccessMode) bool {
|
||||
unitType := util.Iif(refIssue.IsPull, unit.TypePullRequests, unit.TypeIssues)
|
||||
if doer == nil || !doerPerm.CanAccess(perm.AccessModeRead, unitType) {
|
||||
return false
|
||||
}
|
||||
ok := doer.ID == contentPosterID || doerPerm.CanAccess(accessMode, unitType)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
// TODO: the UI can also be updated in the future to hide the "edit" menu
|
||||
if refIssue.IsLocked && !doerPerm.CanWrite(unitType) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -7,13 +7,56 @@ import (
|
||||
"testing"
|
||||
|
||||
issues_model "gitea.dev/models/issues"
|
||||
"gitea.dev/models/perm"
|
||||
access_model "gitea.dev/models/perm/access"
|
||||
repo_model "gitea.dev/models/repo"
|
||||
"gitea.dev/models/unit"
|
||||
"gitea.dev/models/unittest"
|
||||
user_model "gitea.dev/models/user"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCanSelfChangeOrAccessContent(t *testing.T) {
|
||||
doer := &user_model.User{ID: 1}
|
||||
for _, u := range []struct {
|
||||
name string
|
||||
unitType unit.Type
|
||||
}{
|
||||
{"issues", unit.TypeIssues},
|
||||
{"pulls", unit.TypePullRequests},
|
||||
} {
|
||||
t.Run(u.name, func(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
doer *user_model.User
|
||||
posterID int64
|
||||
mode perm.AccessMode
|
||||
requiredMode perm.AccessMode
|
||||
locked bool
|
||||
allowed bool
|
||||
}{
|
||||
{"anonymous", nil, 1, perm.AccessModeWrite, perm.AccessModeWrite, false, false},
|
||||
{"author without read access", doer, 1, perm.AccessModeNone, perm.AccessModeWrite, false, false},
|
||||
{"author with read access", doer, 1, perm.AccessModeRead, perm.AccessModeWrite, false, true},
|
||||
{"reader cannot edit others", doer, 2, perm.AccessModeRead, perm.AccessModeWrite, false, false},
|
||||
{"reader can access others", doer, 2, perm.AccessModeRead, perm.AccessModeRead, false, true},
|
||||
{"writer can edit others", doer, 2, perm.AccessModeWrite, perm.AccessModeWrite, false, true},
|
||||
{"locked author needs write access", doer, 1, perm.AccessModeRead, perm.AccessModeWrite, true, false},
|
||||
{"locked reader needs write access", doer, 2, perm.AccessModeRead, perm.AccessModeRead, true, false},
|
||||
{"locked writer can edit", doer, 2, perm.AccessModeWrite, perm.AccessModeWrite, true, true},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
var permission access_model.Permission
|
||||
permission.SetUnitsWithDefaultAccessMode([]*repo_model.RepoUnit{{Type: u.unitType}}, tc.mode)
|
||||
issue := &issues_model.Issue{IsPull: u.unitType == unit.TypePullRequests, IsLocked: tc.locked}
|
||||
assert.Equal(t, tc.allowed, CanSelfChangeOrAccessContent(tc.doer, permission, issue, tc.posterID, tc.requiredMode))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetRefEndNamesAndURLs(t *testing.T) {
|
||||
issues := []*issues_model.Issue{
|
||||
{ID: 1, Ref: "refs/heads/branch1"},
|
||||
|
||||
Reference in new issue
Block a user