Skip to content

Commit da0b2cb

Browse files
committed
Merge branch 'main' into lunny/fix-oauth2-disable
2 parents 2d8d8aa + 4c924bf commit da0b2cb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+4152
-3744
lines changed

cmd/serv.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,10 @@ func fail(ctx context.Context, userMessage, logMsgFmt string, args ...any) error
111111
if !setting.IsProd {
112112
_, _ = fmt.Fprintln(os.Stderr, "Gitea:", logMsg)
113113
}
114-
if userMessage != "" {
115-
if unicode.IsPunct(rune(userMessage[len(userMessage)-1])) {
116-
logMsg = userMessage + " " + logMsg
117-
} else {
118-
logMsg = userMessage + ". " + logMsg
119-
}
114+
if unicode.IsPunct(rune(userMessage[len(userMessage)-1])) {
115+
logMsg = userMessage + " " + logMsg
116+
} else {
117+
logMsg = userMessage + ". " + logMsg
120118
}
121119
_ = private.SSHLog(ctx, true, logMsg)
122120
}
@@ -288,10 +286,10 @@ func runServ(c *cli.Context) error {
288286
if allowedCommands.Contains(verb) {
289287
if allowedCommandsLfs.Contains(verb) {
290288
if !setting.LFS.StartServer {
291-
return fail(ctx, "Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
289+
return fail(ctx, "LFS Server is not enabled", "")
292290
}
293291
if verb == verbLfsTransfer && !setting.LFS.AllowPureSSH {
294-
return fail(ctx, "Unknown git command", "LFS SSH transfer connection denied, pure SSH protocol is disabled")
292+
return fail(ctx, "LFS SSH transfer is not enabled", "")
295293
}
296294
if len(words) > 2 {
297295
lfsVerb = words[2]

models/actions/task.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ func UpdateTask(ctx context.Context, task *ActionTask, cols ...string) error {
341341
// UpdateTaskByState updates the task by the state.
342342
// It will always update the task if the state is not final, even there is no change.
343343
// So it will update ActionTask.Updated to avoid the task being judged as a zombie task.
344-
func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionTask, error) {
344+
func UpdateTaskByState(ctx context.Context, runnerID int64, state *runnerv1.TaskState) (*ActionTask, error) {
345345
stepStates := map[int64]*runnerv1.StepState{}
346346
for _, v := range state.Steps {
347347
stepStates[v.Id] = v
@@ -360,6 +360,8 @@ func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionT
360360
return nil, err
361361
} else if !has {
362362
return nil, util.ErrNotExist
363+
} else if runnerID != task.RunnerID {
364+
return nil, fmt.Errorf("invalid runner for task")
363365
}
364366

365367
if task.Status.IsDone() {

models/fixtures/lfs_meta_object.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
# These are the LFS objects in user2/lfs.git
2+
# user2/lfs is an INVALID repository
3+
#
4+
# commit e9c32647bab825977942598c0efa415de300304b (HEAD -> master)
5+
# Author: Rowan Bohde <[email protected]>
6+
# Date: Thu Aug 1 14:38:23 2024 -0500
7+
#
8+
# add invalid lfs file
29
-
310

411
id: 1
@@ -11,7 +18,7 @@
1118

1219
id: 2
1320
oid: 2eccdb43825d2a49d99d542daa20075cff1d97d9d2349a8977efe9c03661737c
14-
size: 107
21+
size: 107 # real size is 2048
1522
repository_id: 54
1623
created_unix: 1671607299
1724

@@ -30,3 +37,12 @@
3037
size: 25
3138
repository_id: 54
3239
created_unix: 1671607299
40+
41+
# this file is missing
42+
# -
43+
#
44+
# id: 5
45+
# oid: 9d178b5f15046343fd32f451df93acc2bdd9e6373be478b968e4cad6b6647351
46+
# size: 25
47+
# repository_id: 54
48+
# created_unix: 1671607299

models/fixtures/org_user.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,9 @@
129129
uid: 2
130130
org_id: 35
131131
is_public: true
132+
133+
-
134+
id: 23
135+
uid: 20
136+
org_id: 17
137+
is_public: false

models/fixtures/user.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@
623623
num_stars: 0
624624
num_repos: 2
625625
num_teams: 3
626-
num_members: 4
626+
num_members: 5
627627
visibility: 0
628628
repo_admin_change_team_access: false
629629
theme: ""

models/migrations/v1_21/v276.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"code.gitea.io/gitea/modules/git"
1313
giturl "code.gitea.io/gitea/modules/git/url"
1414
"code.gitea.io/gitea/modules/setting"
15+
"code.gitea.io/gitea/modules/util"
1516

1617
"xorm.io/xorm"
1718
)
@@ -163,7 +164,9 @@ func migratePushMirrors(x *xorm.Engine) error {
163164

164165
func getRemoteAddress(ownerName, repoName, remoteName string) (string, error) {
165166
repoPath := filepath.Join(setting.RepoRootPath, strings.ToLower(ownerName), strings.ToLower(repoName)+".git")
166-
167+
if exist, _ := util.IsExist(repoPath); !exist {
168+
return "", nil
169+
}
167170
remoteURL, err := git.GetRemoteAddress(context.Background(), repoPath, remoteName)
168171
if err != nil {
169172
return "", fmt.Errorf("get remote %s's address of %s/%s failed: %v", remoteName, ownerName, repoName, err)

models/organization/org.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"code.gitea.io/gitea/modules/util"
2323

2424
"xorm.io/builder"
25+
"xorm.io/xorm"
2526
)
2627

2728
// ________ .__ __ .__
@@ -205,11 +206,28 @@ func (opts FindOrgMembersOpts) PublicOnly() bool {
205206
return opts.Doer == nil || !(opts.IsDoerMember || opts.Doer.IsAdmin)
206207
}
207208

209+
// applyTeamMatesOnlyFilter make sure restricted users only see public team members and there own team mates
210+
func (opts FindOrgMembersOpts) applyTeamMatesOnlyFilter(sess *xorm.Session) {
211+
if opts.Doer != nil && opts.IsDoerMember && opts.Doer.IsRestricted {
212+
teamMates := builder.Select("DISTINCT team_user.uid").
213+
From("team_user").
214+
Where(builder.In("team_user.team_id", getUserTeamIDsQueryBuilder(opts.OrgID, opts.Doer.ID))).
215+
And(builder.Eq{"team_user.org_id": opts.OrgID})
216+
217+
sess.And(
218+
builder.In("org_user.uid", teamMates).
219+
Or(builder.Eq{"org_user.is_public": true}),
220+
)
221+
}
222+
}
223+
208224
// CountOrgMembers counts the organization's members
209225
func CountOrgMembers(ctx context.Context, opts *FindOrgMembersOpts) (int64, error) {
210226
sess := db.GetEngine(ctx).Where("org_id=?", opts.OrgID)
211227
if opts.PublicOnly() {
212-
sess.And("is_public = ?", true)
228+
sess = sess.And("is_public = ?", true)
229+
} else {
230+
opts.applyTeamMatesOnlyFilter(sess)
213231
}
214232

215233
return sess.Count(new(OrgUser))
@@ -533,7 +551,9 @@ func GetOrgsCanCreateRepoByUserID(ctx context.Context, userID int64) ([]*Organiz
533551
func GetOrgUsersByOrgID(ctx context.Context, opts *FindOrgMembersOpts) ([]*OrgUser, error) {
534552
sess := db.GetEngine(ctx).Where("org_id=?", opts.OrgID)
535553
if opts.PublicOnly() {
536-
sess.And("is_public = ?", true)
554+
sess = sess.And("is_public = ?", true)
555+
} else {
556+
opts.applyTeamMatesOnlyFilter(sess)
537557
}
538558

539559
if opts.ListOptions.PageSize > 0 {
@@ -664,6 +684,15 @@ func (org *Organization) getUserTeamIDs(ctx context.Context, userID int64) ([]in
664684
Find(&teamIDs)
665685
}
666686

687+
func getUserTeamIDsQueryBuilder(orgID, userID int64) *builder.Builder {
688+
return builder.Select("team.id").From("team").
689+
InnerJoin("team_user", "team_user.team_id = team.id").
690+
Where(builder.Eq{
691+
"team_user.org_id": orgID,
692+
"team_user.uid": userID,
693+
})
694+
}
695+
667696
// TeamsWithAccessToRepo returns all teams that have given access level to the repository.
668697
func (org *Organization) TeamsWithAccessToRepo(ctx context.Context, repoID int64, mode perm.AccessMode) ([]*Team, error) {
669698
return GetTeamsWithAccessToRepo(ctx, org.ID, repoID, mode)

models/organization/org_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package organization_test
55

66
import (
7+
"slices"
78
"sort"
89
"testing"
910

@@ -181,6 +182,75 @@ func TestIsPublicMembership(t *testing.T) {
181182
test(unittest.NonexistentID, unittest.NonexistentID, false)
182183
}
183184

185+
func TestRestrictedUserOrgMembers(t *testing.T) {
186+
assert.NoError(t, unittest.PrepareTestDatabase())
187+
188+
restrictedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{
189+
ID: 29,
190+
IsRestricted: true,
191+
})
192+
if !assert.True(t, restrictedUser.IsRestricted) {
193+
return // ensure fixtures return restricted user
194+
}
195+
196+
testCases := []struct {
197+
name string
198+
opts *organization.FindOrgMembersOpts
199+
expectedUIDs []int64
200+
}{
201+
{
202+
name: "restricted user sees public members and teammates",
203+
opts: &organization.FindOrgMembersOpts{
204+
OrgID: 17, // org17 where user29 is in team9
205+
Doer: restrictedUser,
206+
IsDoerMember: true,
207+
},
208+
expectedUIDs: []int64{2, 15, 20, 29}, // Public members (2) + teammates in team9 (15, 20, 29)
209+
},
210+
{
211+
name: "restricted user sees only public members when not member",
212+
opts: &organization.FindOrgMembersOpts{
213+
OrgID: 3, // org3 where user29 is not a member
214+
Doer: restrictedUser,
215+
},
216+
expectedUIDs: []int64{2, 28}, // Only public members
217+
},
218+
{
219+
name: "non logged in only shows public members",
220+
opts: &organization.FindOrgMembersOpts{
221+
OrgID: 3,
222+
},
223+
expectedUIDs: []int64{2, 28}, // Only public members
224+
},
225+
{
226+
name: "non restricted user sees all members",
227+
opts: &organization.FindOrgMembersOpts{
228+
OrgID: 17,
229+
Doer: unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}),
230+
IsDoerMember: true,
231+
},
232+
expectedUIDs: []int64{2, 15, 18, 20, 29}, // All members
233+
},
234+
}
235+
236+
for _, tc := range testCases {
237+
t.Run(tc.name, func(t *testing.T) {
238+
count, err := organization.CountOrgMembers(db.DefaultContext, tc.opts)
239+
assert.NoError(t, err)
240+
assert.EqualValues(t, len(tc.expectedUIDs), count)
241+
242+
members, err := organization.GetOrgUsersByOrgID(db.DefaultContext, tc.opts)
243+
assert.NoError(t, err)
244+
memberUIDs := make([]int64, 0, len(members))
245+
for _, member := range members {
246+
memberUIDs = append(memberUIDs, member.UID)
247+
}
248+
slices.Sort(memberUIDs)
249+
assert.EqualValues(t, tc.expectedUIDs, memberUIDs)
250+
})
251+
}
252+
}
253+
184254
func TestFindOrgs(t *testing.T) {
185255
assert.NoError(t, unittest.PrepareTestDatabase())
186256

modules/git/batch_reader.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,8 @@ func catFileBatch(ctx context.Context, repoPath string) (WriteCloserError, *bufi
146146
}
147147

148148
// ReadBatchLine reads the header line from cat-file --batch
149-
// We expect:
150-
// <sha> SP <type> SP <size> LF
151-
// sha is a hex encoded here
149+
// We expect: <oid> SP <type> SP <size> LF
150+
// then leaving the rest of the stream "<contents> LF" to be read
152151
func ReadBatchLine(rd *bufio.Reader) (sha []byte, typ string, size int64, err error) {
153152
typ, err = rd.ReadString('\n')
154153
if err != nil {

modules/lfstransfer/backend/backend.go

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ var _ transfer.Backend = &GiteaBackend{}
3333

3434
// GiteaBackend is an adapter between git-lfs-transfer library and Gitea's internal LFS API
3535
type GiteaBackend struct {
36-
ctx context.Context
37-
server *url.URL
38-
op string
39-
token string
40-
itoken string
41-
logger transfer.Logger
36+
ctx context.Context
37+
server *url.URL
38+
op string
39+
authToken string
40+
internalAuth string
41+
logger transfer.Logger
4242
}
4343

4444
func New(ctx context.Context, repo, op, token string, logger transfer.Logger) (transfer.Backend, error) {
@@ -48,7 +48,7 @@ func New(ctx context.Context, repo, op, token string, logger transfer.Logger) (t
4848
return nil, err
4949
}
5050
server = server.JoinPath("api/internal/repo", repo, "info/lfs")
51-
return &GiteaBackend{ctx: ctx, server: server, op: op, token: token, itoken: fmt.Sprintf("Bearer %s", setting.InternalToken), logger: logger}, nil
51+
return &GiteaBackend{ctx: ctx, server: server, op: op, authToken: token, internalAuth: fmt.Sprintf("Bearer %s", setting.InternalToken), logger: logger}, nil
5252
}
5353

5454
// Batch implements transfer.Backend
@@ -73,10 +73,10 @@ func (g *GiteaBackend) Batch(_ string, pointers []transfer.BatchItem, args trans
7373
}
7474
url := g.server.JoinPath("objects/batch").String()
7575
headers := map[string]string{
76-
headerAuthorisation: g.itoken,
77-
headerAuthX: g.token,
78-
headerAccept: mimeGitLFS,
79-
headerContentType: mimeGitLFS,
76+
headerAuthorization: g.authToken,
77+
headerGiteaInternalAuth: g.internalAuth,
78+
headerAccept: mimeGitLFS,
79+
headerContentType: mimeGitLFS,
8080
}
8181
req := newInternalRequest(g.ctx, url, http.MethodPost, headers, bodyBytes)
8282
resp, err := req.Response()
@@ -119,7 +119,7 @@ func (g *GiteaBackend) Batch(_ string, pointers []transfer.BatchItem, args trans
119119
}
120120
idMapStr := base64.StdEncoding.EncodeToString(idMapBytes)
121121
item.Args[argID] = idMapStr
122-
if authHeader, ok := action.Header[headerAuthorisation]; ok {
122+
if authHeader, ok := action.Header[headerAuthorization]; ok {
123123
authHeaderB64 := base64.StdEncoding.EncodeToString([]byte(authHeader))
124124
item.Args[argToken] = authHeaderB64
125125
}
@@ -142,7 +142,7 @@ func (g *GiteaBackend) Batch(_ string, pointers []transfer.BatchItem, args trans
142142
}
143143
idMapStr := base64.StdEncoding.EncodeToString(idMapBytes)
144144
item.Args[argID] = idMapStr
145-
if authHeader, ok := action.Header[headerAuthorisation]; ok {
145+
if authHeader, ok := action.Header[headerAuthorization]; ok {
146146
authHeaderB64 := base64.StdEncoding.EncodeToString([]byte(authHeader))
147147
item.Args[argToken] = authHeaderB64
148148
}
@@ -183,9 +183,9 @@ func (g *GiteaBackend) Download(oid string, args transfer.Args) (io.ReadCloser,
183183
}
184184
url := action.Href
185185
headers := map[string]string{
186-
headerAuthorisation: g.itoken,
187-
headerAuthX: g.token,
188-
headerAccept: mimeOctetStream,
186+
headerAuthorization: g.authToken,
187+
headerGiteaInternalAuth: g.internalAuth,
188+
headerAccept: mimeOctetStream,
189189
}
190190
req := newInternalRequest(g.ctx, url, http.MethodGet, headers, nil)
191191
resp, err := req.Response()
@@ -229,10 +229,10 @@ func (g *GiteaBackend) Upload(oid string, size int64, r io.Reader, args transfer
229229
}
230230
url := action.Href
231231
headers := map[string]string{
232-
headerAuthorisation: g.itoken,
233-
headerAuthX: g.token,
234-
headerContentType: mimeOctetStream,
235-
headerContentLength: strconv.FormatInt(size, 10),
232+
headerAuthorization: g.authToken,
233+
headerGiteaInternalAuth: g.internalAuth,
234+
headerContentType: mimeOctetStream,
235+
headerContentLength: strconv.FormatInt(size, 10),
236236
}
237237
reqBytes, err := io.ReadAll(r)
238238
if err != nil {
@@ -279,10 +279,10 @@ func (g *GiteaBackend) Verify(oid string, size int64, args transfer.Args) (trans
279279
}
280280
url := action.Href
281281
headers := map[string]string{
282-
headerAuthorisation: g.itoken,
283-
headerAuthX: g.token,
284-
headerAccept: mimeGitLFS,
285-
headerContentType: mimeGitLFS,
282+
headerAuthorization: g.authToken,
283+
headerGiteaInternalAuth: g.internalAuth,
284+
headerAccept: mimeGitLFS,
285+
headerContentType: mimeGitLFS,
286286
}
287287
req := newInternalRequest(g.ctx, url, http.MethodPost, headers, bodyBytes)
288288
resp, err := req.Response()

0 commit comments

Comments
 (0)