diff --git a/go.mod b/go.mod index cf6252f02e..12d2c3803b 100644 --- a/go.mod +++ b/go.mod @@ -53,7 +53,7 @@ require ( github.com/gobwas/glob v0.2.3 github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 - github.com/golang-jwt/jwt/v5 v5.2.1 + github.com/golang-jwt/jwt/v5 v5.2.2 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 github.com/google/go-github/v64 v64.0.0 github.com/google/pprof v0.0.0-20241017200806-017d972448fc @@ -103,8 +103,8 @@ require ( go.uber.org/mock v0.4.0 golang.org/x/crypto v0.35.0 golang.org/x/image v0.23.0 - golang.org/x/net v0.33.0 - golang.org/x/oauth2 v0.23.0 + golang.org/x/net v0.36.0 + golang.org/x/oauth2 v0.27.0 golang.org/x/sync v0.11.0 golang.org/x/sys v0.30.0 golang.org/x/text v0.22.0 diff --git a/go.sum b/go.sum index cedec7d4e9..1c8e75c1ff 100644 --- a/go.sum +++ b/go.sum @@ -981,8 +981,8 @@ github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JP github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= -github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= -github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= +github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A= @@ -1631,8 +1631,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= -golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= +golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA= +golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1662,8 +1662,8 @@ golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I= golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw= golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= +golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/routers/common/middleware.go b/routers/common/middleware.go index 856c10e678..873bc09b1d 100644 --- a/routers/common/middleware.go +++ b/routers/common/middleware.go @@ -74,27 +74,27 @@ func ProtocolMiddlewares() (handlers []any) { func stripSlashesMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { - // First of all escape the URL RawPath to ensure that all routing is done using a correctly escaped URL + // Ensure that URL.RawPath is always set. req.URL.RawPath = req.URL.EscapedPath() - urlPath := req.URL.RawPath - rctx := chi.RouteContext(req.Context()) - if rctx != nil && rctx.RoutePath != "" { - urlPath = rctx.RoutePath - } - - sanitizedPath := &strings.Builder{} - prevWasSlash := false - for _, chr := range strings.TrimRight(urlPath, "/") { - if chr != '/' || !prevWasSlash { - sanitizedPath.WriteRune(chr) + sanitize := func(path string) string { + sanitizedPath := &strings.Builder{} + prevWasSlash := false + for _, chr := range strings.TrimRight(path, "/") { + if chr != '/' || !prevWasSlash { + sanitizedPath.WriteRune(chr) + } + prevWasSlash = chr == '/' } - prevWasSlash = chr == '/' + return sanitizedPath.String() } - req.URL.Path = sanitizedPath.String() + // Sanitize the unescaped path for application logic. + req.URL.Path = sanitize(req.URL.Path) + rctx := chi.RouteContext(req.Context()) if rctx != nil { - rctx.RoutePath = req.URL.Path + // Sanitize the escaped path for routing. + rctx.RoutePath = sanitize(req.URL.RawPath) } next.ServeHTTP(resp, req) }) diff --git a/routers/common/middleware_test.go b/routers/common/middleware_test.go index 0e111e1261..6126e0afcc 100644 --- a/routers/common/middleware_test.go +++ b/routers/common/middleware_test.go @@ -15,9 +15,10 @@ import ( func TestStripSlashesMiddleware(t *testing.T) { type test struct { - name string - expectedPath string - inputPath string + name string + expectedPath string + expectedNormalPath string + inputPath string } tests := []test{ @@ -57,9 +58,16 @@ func TestStripSlashesMiddleware(t *testing.T) { expectedPath: "/repo/migrate", }, { - name: "path with encoded slash", - inputPath: "/user2/%2F%2Frepo1", - expectedPath: "/user2/%2F%2Frepo1", + name: "path with encoded slash", + inputPath: "/user2/%2F%2Frepo1", + expectedPath: "/user2/%2F%2Frepo1", + expectedNormalPath: "/user2/repo1", + }, + { + name: "path with space", + inputPath: "/assets/css/theme%20cappuccino.css", + expectedPath: "/assets/css/theme%20cappuccino.css", + expectedNormalPath: "/assets/css/theme cappuccino.css", }, } @@ -69,7 +77,11 @@ func TestStripSlashesMiddleware(t *testing.T) { called := false r.Get("*", func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, tt.expectedPath, r.URL.Path) + if tt.expectedNormalPath != "" { + assert.Equal(t, tt.expectedNormalPath, r.URL.Path) + } else { + assert.Equal(t, tt.expectedPath, r.URL.Path) + } rctx := chi.RouteContext(r.Context()) assert.Equal(t, tt.expectedPath, rctx.RoutePath) diff --git a/services/context/repo.go b/services/context/repo.go index 71cf431273..462d843bfc 100644 --- a/services/context/repo.go +++ b/services/context/repo.go @@ -1051,7 +1051,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context if refType == RepoRefLegacy { // redirect from old URL scheme to new URL scheme - prefix := strings.TrimPrefix(setting.AppSubURL+strings.ToLower(strings.TrimSuffix(ctx.Req.URL.Path, ctx.PathParamRaw("*"))), strings.ToLower(ctx.Repo.RepoLink)) + prefix := strings.TrimPrefix(setting.AppSubURL+strings.ToLower(strings.TrimSuffix(ctx.Req.URL.Path, ctx.Params("*"))), strings.ToLower(ctx.Repo.RepoLink)) ctx.Redirect(path.Join( ctx.Repo.RepoLink,