Skip to content

Commit 67e75f3

Browse files
authored
Fix bug on notification read (#36339)
When a user has been revoked permission to access a repository, the related notification could still be visited. But the repository's information should not be leaked any more.
1 parent 3f46de8 commit 67e75f3

2 files changed

Lines changed: 69 additions & 6 deletions

File tree

services/convert/notification.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import (
88
"net/url"
99

1010
activities_model "code.gitea.io/gitea/models/activities"
11-
"code.gitea.io/gitea/models/perm"
1211
access_model "code.gitea.io/gitea/models/perm/access"
12+
"code.gitea.io/gitea/modules/log"
1313
api "code.gitea.io/gitea/modules/structs"
1414
)
1515

@@ -25,11 +25,17 @@ func ToNotificationThread(ctx context.Context, n *activities_model.Notification)
2525

2626
// since user only get notifications when he has access to use minimal access mode
2727
if n.Repository != nil {
28-
result.Repository = ToRepo(ctx, n.Repository, access_model.Permission{AccessMode: perm.AccessModeRead})
29-
30-
// This permission is not correct and we should not be reporting it
31-
for repository := result.Repository; repository != nil; repository = repository.Parent {
32-
repository.Permissions = nil
28+
perm, err := access_model.GetUserRepoPermission(ctx, n.Repository, n.User)
29+
if err != nil {
30+
log.Error("GetUserRepoPermission failed: %v", err)
31+
return result
32+
}
33+
if perm.HasAnyUnitAccessOrPublicAccess() { // if user has been revoked access to repo, do not show repo info
34+
result.Repository = ToRepo(ctx, n.Repository, perm)
35+
// This permission is not correct and we should not be reporting it
36+
for repository := result.Repository; repository != nil; repository = repository.Parent {
37+
repository.Permissions = nil
38+
}
3339
}
3440
}
3541

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2026 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package convert
5+
6+
import (
7+
"testing"
8+
9+
activities_model "code.gitea.io/gitea/models/activities"
10+
repo_model "code.gitea.io/gitea/models/repo"
11+
"code.gitea.io/gitea/models/unittest"
12+
user_model "code.gitea.io/gitea/models/user"
13+
"code.gitea.io/gitea/modules/timeutil"
14+
15+
"github.com/stretchr/testify/assert"
16+
)
17+
18+
func TestToNotificationThreadIncludesRepoForAccessibleUser(t *testing.T) {
19+
assert.NoError(t, unittest.PrepareTestDatabase())
20+
21+
n := newRepoNotification(t, 1, 4)
22+
thread := ToNotificationThread(t.Context(), n)
23+
24+
if assert.NotNil(t, thread.Repository) {
25+
assert.Equal(t, n.Repository.FullName(), thread.Repository.FullName)
26+
assert.Nil(t, thread.Repository.Permissions)
27+
}
28+
}
29+
30+
func TestToNotificationThreadOmitsRepoWhenAccessRevoked(t *testing.T) {
31+
assert.NoError(t, unittest.PrepareTestDatabase())
32+
33+
n := newRepoNotification(t, 2, 4)
34+
thread := ToNotificationThread(t.Context(), n)
35+
36+
assert.Nil(t, thread.Repository)
37+
}
38+
39+
func newRepoNotification(t *testing.T, repoID, userID int64) *activities_model.Notification {
40+
t.Helper()
41+
42+
ctx := t.Context()
43+
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID})
44+
assert.NoError(t, repo.LoadOwner(ctx))
45+
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID})
46+
47+
return &activities_model.Notification{
48+
ID: repoID*1000 + userID,
49+
UserID: user.ID,
50+
RepoID: repo.ID,
51+
Status: activities_model.NotificationStatusUnread,
52+
Source: activities_model.NotificationSourceRepository,
53+
UpdatedUnix: timeutil.TimeStampNow(),
54+
Repository: repo,
55+
User: user,
56+
}
57+
}

0 commit comments

Comments
 (0)