Skip to content

Commit 8aefbcf

Browse files
committed
fix
1 parent 840ad7e commit 8aefbcf

File tree

8 files changed

+52
-41
lines changed

8 files changed

+52
-41
lines changed

routers/common/lfs.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"code.gitea.io/gitea/services/lfs"
1111
)
1212

13+
const RouterMockPointCommonLFS = "common-lfs"
14+
1315
func AddOwnerRepoGitLFSRoutes(m *web.Router, middlewares ...any) {
1416
// shared by web and internal routers
1517
m.Group("/{username}/{reponame}/info/lfs", func() {
@@ -25,5 +27,5 @@ func AddOwnerRepoGitLFSRoutes(m *web.Router, middlewares ...any) {
2527
m.Post("/{lid}/unlock", lfs.UnLockHandler)
2628
}, lfs.CheckAcceptMediaType)
2729
m.Any("/*", http.NotFound)
28-
}, middlewares...)
30+
}, append([]any{web.RouterMockPoint(RouterMockPointCommonLFS)}, middlewares...)...)
2931
}

routers/private/internal.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,6 @@ import (
2020
chi_middleware "github.com/go-chi/chi/v5/middleware"
2121
)
2222

23-
const RouterMockPointInternalLFS = "internal-lfs"
24-
2523
func authInternal(next http.Handler) http.Handler {
2624
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
2725
if setting.InternalToken == "" {
@@ -87,10 +85,11 @@ func Routes() *web.Router {
8785

8886
r.Group("/repo", func() {
8987
// FIXME: it is not right to use context.Contexter here because all routes here should use PrivateContext
88+
// Fortunately, the LFS handlers are able to handle requests without a complete web context
9089
common.AddOwnerRepoGitLFSRoutes(r, func(ctx *context.PrivateContext) {
9190
webContext := &context.Context{Base: ctx.Base}
9291
ctx.AppendContextValue(context.WebContextKey, webContext)
93-
}, web.RouterMockPoint(RouterMockPointInternalLFS))
92+
})
9493
})
9594

9695
return r

routers/web/auth/oauth2_provider.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ type userInfoResponse struct {
9191
// InfoOAuth manages request for userinfo endpoint
9292
func InfoOAuth(ctx *context.Context) {
9393
if ctx.Doer == nil || ctx.Data["AuthedMethod"] != (&auth_service.OAuth2{}).Name() {
94-
ctx.Resp.Header().Set("WWW-Authenticate", `Bearer realm=""`)
94+
ctx.Resp.Header().Set("WWW-Authenticate", `Bearer realm="Gitea OAuth2"`)
9595
ctx.PlainText(http.StatusUnauthorized, "no valid authorization")
9696
return
9797
}
@@ -136,7 +136,7 @@ func IntrospectOAuth(ctx *context.Context) {
136136
clientIDValid = err == nil && app.ValidateClientSecret([]byte(clientSecret))
137137
}
138138
if !clientIDValid {
139-
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm=""`)
139+
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="Gitea OAuth2"`)
140140
ctx.PlainText(http.StatusUnauthorized, "no valid authorization")
141141
return
142142
}

services/context/base.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ type contextValuePair struct {
3030
valueFn func() any
3131
}
3232

33+
type BaseContextKeyType struct{}
34+
35+
var BaseContextKey BaseContextKeyType
36+
3337
type Base struct {
3438
originCtx context.Context
3539
contextValues []contextValuePair
@@ -315,6 +319,7 @@ func NewBaseContext(resp http.ResponseWriter, req *http.Request) (b *Base, close
315319
Data: middleware.GetContextData(req.Context()),
316320
}
317321
b.Req = b.Req.WithContext(b)
322+
b.AppendContextValue(BaseContextKey, b)
318323
b.AppendContextValue(translation.ContextKey, b.Locale)
319324
b.AppendContextValue(httplib.RequestContextKey, b.Req)
320325
return b, b.cleanUp

services/context/context.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,9 @@ type Context struct {
6565
type TemplateContext map[string]any
6666

6767
func init() {
68+
web.RegisterResponseStatusProvider[*Base](func(req *http.Request) web_types.ResponseStatusProvider {
69+
return req.Context().Value(BaseContextKey).(*Base)
70+
})
6871
web.RegisterResponseStatusProvider[*Context](func(req *http.Request) web_types.ResponseStatusProvider {
6972
return req.Context().Value(WebContextKey).(*Context)
7073
})

services/lfs/locks.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func GetListLockHandler(ctx *context.Context) {
5151
repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, rv.User, rv.Repo)
5252
if err != nil {
5353
log.Debug("Could not find repository: %s/%s - %s", rv.User, rv.Repo, err)
54-
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
54+
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`)
5555
ctx.JSON(http.StatusUnauthorized, api.LFSLockError{
5656
Message: "You must have pull access to list locks",
5757
})
@@ -66,7 +66,7 @@ func GetListLockHandler(ctx *context.Context) {
6666

6767
authenticated := authenticate(ctx, repository, rv.Authorization, true, false)
6868
if !authenticated {
69-
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
69+
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`)
7070
ctx.JSON(http.StatusUnauthorized, api.LFSLockError{
7171
Message: "You must have pull access to list locks",
7272
})
@@ -143,7 +143,7 @@ func PostLockHandler(ctx *context.Context) {
143143
repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, userName, repoName)
144144
if err != nil {
145145
log.Error("Unable to get repository: %s/%s Error: %v", userName, repoName, err)
146-
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
146+
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`)
147147
ctx.JSON(http.StatusUnauthorized, api.LFSLockError{
148148
Message: "You must have push access to create locks",
149149
})
@@ -158,7 +158,7 @@ func PostLockHandler(ctx *context.Context) {
158158

159159
authenticated := authenticate(ctx, repository, authorization, true, true)
160160
if !authenticated {
161-
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
161+
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`)
162162
ctx.JSON(http.StatusUnauthorized, api.LFSLockError{
163163
Message: "You must have push access to create locks",
164164
})
@@ -191,7 +191,7 @@ func PostLockHandler(ctx *context.Context) {
191191
return
192192
}
193193
if git_model.IsErrLFSUnauthorizedAction(err) {
194-
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
194+
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`)
195195
ctx.JSON(http.StatusUnauthorized, api.LFSLockError{
196196
Message: "You must have push access to create locks : " + err.Error(),
197197
})
@@ -215,7 +215,7 @@ func VerifyLockHandler(ctx *context.Context) {
215215
repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, userName, repoName)
216216
if err != nil {
217217
log.Error("Unable to get repository: %s/%s Error: %v", userName, repoName, err)
218-
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
218+
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`)
219219
ctx.JSON(http.StatusUnauthorized, api.LFSLockError{
220220
Message: "You must have push access to verify locks",
221221
})
@@ -230,7 +230,7 @@ func VerifyLockHandler(ctx *context.Context) {
230230

231231
authenticated := authenticate(ctx, repository, authorization, true, true)
232232
if !authenticated {
233-
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
233+
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`)
234234
ctx.JSON(http.StatusUnauthorized, api.LFSLockError{
235235
Message: "You must have push access to verify locks",
236236
})
@@ -286,7 +286,7 @@ func UnLockHandler(ctx *context.Context) {
286286
repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, userName, repoName)
287287
if err != nil {
288288
log.Error("Unable to get repository: %s/%s Error: %v", userName, repoName, err)
289-
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
289+
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`)
290290
ctx.JSON(http.StatusUnauthorized, api.LFSLockError{
291291
Message: "You must have push access to delete locks",
292292
})
@@ -301,7 +301,7 @@ func UnLockHandler(ctx *context.Context) {
301301

302302
authenticated := authenticate(ctx, repository, authorization, true, true)
303303
if !authenticated {
304-
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
304+
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`)
305305
ctx.JSON(http.StatusUnauthorized, api.LFSLockError{
306306
Message: "You must have push access to delete locks",
307307
})
@@ -324,7 +324,7 @@ func UnLockHandler(ctx *context.Context) {
324324
lock, err := git_model.DeleteLFSLockByID(ctx, ctx.PathParamInt64("lid"), repository, ctx.Doer, req.Force)
325325
if err != nil {
326326
if git_model.IsErrLFSUnauthorizedAction(err) {
327-
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
327+
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`)
328328
ctx.JSON(http.StatusUnauthorized, api.LFSLockError{
329329
Message: "You must have push access to delete locks : " + err.Error(),
330330
})

services/lfs/server.go

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import (
2121
actions_model "code.gitea.io/gitea/models/actions"
2222
auth_model "code.gitea.io/gitea/models/auth"
2323
git_model "code.gitea.io/gitea/models/git"
24-
"code.gitea.io/gitea/models/perm"
24+
perm_model "code.gitea.io/gitea/models/perm"
2525
access_model "code.gitea.io/gitea/models/perm/access"
2626
repo_model "code.gitea.io/gitea/models/repo"
2727
"code.gitea.io/gitea/models/unit"
@@ -77,7 +77,7 @@ func CheckAcceptMediaType(ctx *context.Context) {
7777
}
7878
}
7979

80-
var rangeHeaderRegexp = regexp.MustCompile(`bytes=(\d+)\-(\d*).*`)
80+
var rangeHeaderRegexp = regexp.MustCompile(`bytes=(\d+)-(\d*).*`)
8181

8282
// DownloadHandler gets the content from the content store
8383
func DownloadHandler(ctx *context.Context) {
@@ -507,11 +507,11 @@ func writeStatusMessage(ctx *context.Context, status int, message string) {
507507
}
508508

509509
// authenticate uses the authorization string to determine whether
510-
// or not to proceed. This server assumes an HTTP Basic auth format.
510+
// to proceed. This server assumes an HTTP Basic auth format.
511511
func authenticate(ctx *context.Context, repository *repo_model.Repository, authorization string, requireSigned, requireWrite bool) bool {
512-
accessMode := perm.AccessModeRead
512+
accessMode := perm_model.AccessModeRead
513513
if requireWrite {
514-
accessMode = perm.AccessModeWrite
514+
accessMode = perm_model.AccessModeWrite
515515
}
516516

517517
if ctx.Data["IsActionsToken"] == true {
@@ -526,9 +526,9 @@ func authenticate(ctx *context.Context, repository *repo_model.Repository, autho
526526
}
527527

528528
if task.IsForkPullRequest {
529-
return accessMode <= perm.AccessModeRead
529+
return accessMode <= perm_model.AccessModeRead
530530
}
531-
return accessMode <= perm.AccessModeWrite
531+
return accessMode <= perm_model.AccessModeWrite
532532
}
533533

534534
// ctx.IsSigned is unnecessary here, this will be checked in perm.CanAccess
@@ -553,7 +553,7 @@ func authenticate(ctx *context.Context, repository *repo_model.Repository, autho
553553
return true
554554
}
555555

556-
func handleLFSToken(ctx stdCtx.Context, tokenSHA string, target *repo_model.Repository, mode perm.AccessMode) (*user_model.User, error) {
556+
func handleLFSToken(ctx stdCtx.Context, tokenSHA string, target *repo_model.Repository, mode perm_model.AccessMode) (*user_model.User, error) {
557557
if !strings.Contains(tokenSHA, ".") {
558558
return nil, nil
559559
}
@@ -576,7 +576,7 @@ func handleLFSToken(ctx stdCtx.Context, tokenSHA string, target *repo_model.Repo
576576
return nil, fmt.Errorf("invalid token claim")
577577
}
578578

579-
if mode == perm.AccessModeWrite && claims.Op != "upload" {
579+
if mode == perm_model.AccessModeWrite && claims.Op != "upload" {
580580
return nil, fmt.Errorf("invalid token claim")
581581
}
582582

@@ -588,7 +588,7 @@ func handleLFSToken(ctx stdCtx.Context, tokenSHA string, target *repo_model.Repo
588588
return u, nil
589589
}
590590

591-
func parseToken(ctx stdCtx.Context, authorization string, target *repo_model.Repository, mode perm.AccessMode) (*user_model.User, error) {
591+
func parseToken(ctx stdCtx.Context, authorization string, target *repo_model.Repository, mode perm_model.AccessMode) (*user_model.User, error) {
592592
if authorization == "" {
593593
return nil, fmt.Errorf("no token")
594594
}
@@ -608,6 +608,6 @@ func parseToken(ctx stdCtx.Context, authorization string, target *repo_model.Rep
608608
}
609609

610610
func requireAuth(ctx *context.Context) {
611-
ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs")
611+
ctx.Resp.Header().Set("WWW-Authenticate", `Basic realm="gitea-lfs"`)
612612
writeStatus(ctx, http.StatusUnauthorized)
613613
}

tests/integration/git_lfs_ssh_test.go

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,18 @@
44
package integration
55

66
import (
7+
gocontext "context"
78
"net/url"
9+
"slices"
10+
"strings"
811
"sync"
912
"testing"
1013

1114
auth_model "code.gitea.io/gitea/models/auth"
15+
"code.gitea.io/gitea/modules/git"
1216
"code.gitea.io/gitea/modules/setting"
1317
"code.gitea.io/gitea/modules/web"
14-
"code.gitea.io/gitea/routers/private"
18+
"code.gitea.io/gitea/routers/common"
1519
"code.gitea.io/gitea/services/context"
1620

1721
"github.com/stretchr/testify/assert"
@@ -25,7 +29,7 @@ func TestGitLFSSSH(t *testing.T) {
2529

2630
var mu sync.Mutex
2731
var routerCalls []string
28-
web.RouteMock(private.RouterMockPointInternalLFS, func(ctx *context.PrivateContext) {
32+
web.RouteMock(common.RouterMockPointCommonLFS, func(ctx *context.Base) {
2933
mu.Lock()
3034
routerCalls = append(routerCalls, ctx.Req.Method+" "+ctx.Req.URL.Path)
3135
mu.Unlock()
@@ -42,20 +46,18 @@ func TestGitLFSSSH(t *testing.T) {
4246
setting.LFS.AllowPureSSH = true
4347
require.NoError(t, cfg.Save())
4448

45-
// do LFS SSH transfer?
49+
_, _, cmdErr := git.NewCommand(gocontext.Background(), "config", "lfs.sshtransfer", "always").RunStdString(&git.RunOpts{Dir: dstPath})
50+
assert.NoError(t, cmdErr)
4651
lfsCommitAndPushTest(t, dstPath, 10)
4752
})
4853

49-
// FIXME: Here we only see the following calls, but actually there should be calls to "PUT"?
50-
// 0 = {string} "GET /api/internal/repo/user2/repo1.git/info/lfs/locks"
51-
// 1 = {string} "POST /api/internal/repo/user2/repo1.git/info/lfs/objects/batch"
52-
// 2 = {string} "GET /api/internal/repo/user2/repo1.git/info/lfs/locks"
53-
// 3 = {string} "POST /api/internal/repo/user2/repo1.git/info/lfs/locks"
54-
// 4 = {string} "GET /api/internal/repo/user2/repo1.git/info/lfs/locks"
55-
// 5 = {string} "GET /api/internal/repo/user2/repo1.git/info/lfs/locks"
56-
// 6 = {string} "GET /api/internal/repo/user2/repo1.git/info/lfs/locks"
57-
// 7 = {string} "POST /api/internal/repo/user2/repo1.git/info/lfs/locks/24/unlock"
58-
assert.NotEmpty(t, routerCalls)
59-
// assert.Contains(t, routerCalls, "PUT /api/internal/repo/user2/repo1.git/info/lfs/objects/....")
54+
countBatch := slices.ContainsFunc(routerCalls, func(s string) bool {
55+
return strings.Contains(s, "POST /api/internal/repo/user2/repo1.git/info/lfs/objects/batch")
56+
})
57+
countUpload := slices.ContainsFunc(routerCalls, func(s string) bool {
58+
return strings.Contains(s, "PUT /user2/repo1.git/info/lfs/objects/")
59+
})
60+
assert.NotZero(t, countBatch)
61+
assert.NotZero(t, countUpload)
6062
})
6163
}

0 commit comments

Comments
 (0)