Skip to content

Commit b116418

Browse files
authored
Use CleanPath instead of path.Clean (#23371)
As title.
1 parent 090e753 commit b116418

File tree

13 files changed

+45
-28
lines changed

13 files changed

+45
-28
lines changed

models/git/lfs_lock.go

+4-8
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package git
66
import (
77
"context"
88
"fmt"
9-
"path"
109
"strings"
1110
"time"
1211

@@ -17,6 +16,7 @@ import (
1716
"code.gitea.io/gitea/models/unit"
1817
user_model "code.gitea.io/gitea/models/user"
1918
"code.gitea.io/gitea/modules/setting"
19+
"code.gitea.io/gitea/modules/util"
2020
)
2121

2222
// LFSLock represents a git lfs lock of repository.
@@ -34,11 +34,7 @@ func init() {
3434

3535
// BeforeInsert is invoked from XORM before inserting an object of this type.
3636
func (l *LFSLock) BeforeInsert() {
37-
l.Path = cleanPath(l.Path)
38-
}
39-
40-
func cleanPath(p string) string {
41-
return path.Clean("/" + p)[1:]
37+
l.Path = util.CleanPath(l.Path)
4238
}
4339

4440
// CreateLFSLock creates a new lock.
@@ -53,7 +49,7 @@ func CreateLFSLock(ctx context.Context, repo *repo_model.Repository, lock *LFSLo
5349
return nil, err
5450
}
5551

56-
lock.Path = cleanPath(lock.Path)
52+
lock.Path = util.CleanPath(lock.Path)
5753
lock.RepoID = repo.ID
5854

5955
l, err := GetLFSLock(dbCtx, repo, lock.Path)
@@ -73,7 +69,7 @@ func CreateLFSLock(ctx context.Context, repo *repo_model.Repository, lock *LFSLo
7369

7470
// GetLFSLock returns release by given path.
7571
func GetLFSLock(ctx context.Context, repo *repo_model.Repository, path string) (*LFSLock, error) {
76-
path = cleanPath(path)
72+
path = util.CleanPath(path)
7773
rel := &LFSLock{RepoID: repo.ID}
7874
has, err := db.GetEngine(ctx).Where("lower(path) = ?", strings.ToLower(path)).Get(rel)
7975
if err != nil {

modules/options/base.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,27 @@ import (
1616

1717
// Locale reads the content of a specific locale from static/bindata or custom path.
1818
func Locale(name string) ([]byte, error) {
19-
return fileFromDir(path.Join("locale", path.Clean("/"+name)))
19+
return fileFromDir(path.Join("locale", util.CleanPath(name)))
2020
}
2121

2222
// Readme reads the content of a specific readme from static/bindata or custom path.
2323
func Readme(name string) ([]byte, error) {
24-
return fileFromDir(path.Join("readme", path.Clean("/"+name)))
24+
return fileFromDir(path.Join("readme", util.CleanPath(name)))
2525
}
2626

2727
// Gitignore reads the content of a gitignore locale from static/bindata or custom path.
2828
func Gitignore(name string) ([]byte, error) {
29-
return fileFromDir(path.Join("gitignore", path.Clean("/"+name)))
29+
return fileFromDir(path.Join("gitignore", util.CleanPath(name)))
3030
}
3131

3232
// License reads the content of a specific license from static/bindata or custom path.
3333
func License(name string) ([]byte, error) {
34-
return fileFromDir(path.Join("license", path.Clean("/"+name)))
34+
return fileFromDir(path.Join("license", util.CleanPath(name)))
3535
}
3636

3737
// Labels reads the content of a specific labels from static/bindata or custom path.
3838
func Labels(name string) ([]byte, error) {
39-
return fileFromDir(path.Join("label", path.Clean("/"+name)))
39+
return fileFromDir(path.Join("label", util.CleanPath(name)))
4040
}
4141

4242
// WalkLocales reads the content of a specific locale

modules/public/public.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ package public
66
import (
77
"net/http"
88
"os"
9-
"path"
109
"path/filepath"
1110
"strings"
1211

1312
"code.gitea.io/gitea/modules/container"
1413
"code.gitea.io/gitea/modules/httpcache"
1514
"code.gitea.io/gitea/modules/log"
1615
"code.gitea.io/gitea/modules/setting"
16+
"code.gitea.io/gitea/modules/util"
1717
)
1818

1919
// Options represents the available options to configure the handler.
@@ -103,7 +103,7 @@ func setWellKnownContentType(w http.ResponseWriter, file string) {
103103

104104
func (opts *Options) handle(w http.ResponseWriter, req *http.Request, fs http.FileSystem, file string) bool {
105105
// use clean to keep the file is a valid path with no . or ..
106-
f, err := fs.Open(path.Clean(file))
106+
f, err := fs.Open(util.CleanPath(file))
107107
if err != nil {
108108
if os.IsNotExist(err) {
109109
return false

modules/storage/local.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"io"
99
"net/url"
1010
"os"
11-
"path"
1211
"path/filepath"
1312
"strings"
1413

@@ -59,7 +58,7 @@ func NewLocalStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
5958
}
6059

6160
func (l *LocalStorage) buildLocalPath(p string) string {
62-
return filepath.Join(l.dir, path.Clean("/" + strings.ReplaceAll(p, "\\", "/"))[1:])
61+
return filepath.Join(l.dir, util.CleanPath(strings.ReplaceAll(p, "\\", "/")))
6362
}
6463

6564
// Open a file

modules/storage/minio.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"time"
1616

1717
"code.gitea.io/gitea/modules/log"
18+
"code.gitea.io/gitea/modules/util"
1819

1920
"github.com/minio/minio-go/v7"
2021
"github.com/minio/minio-go/v7/pkg/credentials"
@@ -120,7 +121,7 @@ func NewMinioStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
120121
}
121122

122123
func (m *MinioStorage) buildMinioPath(p string) string {
123-
return strings.TrimPrefix(path.Join(m.basePath, path.Clean("/" + strings.ReplaceAll(p, "\\", "/"))[1:]), "/")
124+
return strings.TrimPrefix(path.Join(m.basePath, util.CleanPath(strings.ReplaceAll(p, "\\", "/"))), "/")
124125
}
125126

126127
// Open open a file

modules/util/path.go

+8
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ import (
1414
"strings"
1515
)
1616

17+
// CleanPath ensure to clean the path
18+
func CleanPath(p string) string {
19+
if strings.HasPrefix(p, "/") {
20+
return path.Clean(p)
21+
}
22+
return path.Clean("/" + p)[1:]
23+
}
24+
1725
// EnsureAbsolutePath ensure that a path is absolute, making it
1826
// relative to absoluteBase if necessary
1927
func EnsureAbsolutePath(path, absoluteBase string) string {

modules/util/path_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,15 @@ func TestMisc_IsReadmeFileName(t *testing.T) {
136136
assert.Equal(t, testCase.idx, idx)
137137
}
138138
}
139+
140+
func TestCleanPath(t *testing.T) {
141+
cases := map[string]string{
142+
"../../test": "test",
143+
"/test": "/test",
144+
"/../test": "/test",
145+
}
146+
147+
for k, v := range cases {
148+
assert.Equal(t, v, CleanPath(k))
149+
}
150+
}

routers/web/base.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"code.gitea.io/gitea/modules/setting"
2020
"code.gitea.io/gitea/modules/storage"
2121
"code.gitea.io/gitea/modules/templates"
22+
"code.gitea.io/gitea/modules/util"
2223
"code.gitea.io/gitea/modules/web/middleware"
2324
"code.gitea.io/gitea/modules/web/routing"
2425
"code.gitea.io/gitea/services/auth"
@@ -44,7 +45,7 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
4445
routing.UpdateFuncInfo(req.Context(), funcInfo)
4546

4647
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
47-
rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:]
48+
rPath = util.CleanPath(strings.ReplaceAll(rPath, "\\", "/"))
4849

4950
u, err := objStore.URL(rPath, path.Base(rPath))
5051
if err != nil {
@@ -80,7 +81,7 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
8081
routing.UpdateFuncInfo(req.Context(), funcInfo)
8182

8283
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
83-
rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:]
84+
rPath = util.CleanPath(strings.ReplaceAll(rPath, "\\", "/"))
8485
if rPath == "" {
8586
http.Error(w, "file not found", http.StatusNotFound)
8687
return

routers/web/repo/editor.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -726,7 +726,7 @@ func UploadFilePost(ctx *context.Context) {
726726

727727
func cleanUploadFileName(name string) string {
728728
// Rebase the filename
729-
name = strings.Trim(path.Clean("/"+name), "/")
729+
name = strings.Trim(util.CleanPath(name), "/")
730730
// Git disallows any filenames to have a .git directory in them.
731731
for _, part := range strings.Split(name, "/") {
732732
if strings.ToLower(part) == ".git" {

routers/web/repo/lfs.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ func LFSLockFile(ctx *context.Context) {
207207
ctx.Redirect(ctx.Repo.RepoLink + "/settings/lfs/locks")
208208
return
209209
}
210-
lockPath = path.Clean("/" + lockPath)[1:]
210+
lockPath = util.CleanPath(lockPath)
211211
if len(lockPath) == 0 {
212212
ctx.Flash.Error(ctx.Tr("repo.settings.lfs_invalid_locking_path", originalPath))
213213
ctx.Redirect(ctx.Repo.RepoLink + "/settings/lfs/locks")

services/migrations/gitea_uploader.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"fmt"
1010
"io"
1111
"os"
12-
"path"
1312
"path/filepath"
1413
"strconv"
1514
"strings"
@@ -30,6 +29,7 @@ import (
3029
"code.gitea.io/gitea/modules/structs"
3130
"code.gitea.io/gitea/modules/timeutil"
3231
"code.gitea.io/gitea/modules/uri"
32+
"code.gitea.io/gitea/modules/util"
3333
"code.gitea.io/gitea/services/pull"
3434

3535
"github.com/google/uuid"
@@ -866,7 +866,7 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error {
866866
}
867867

868868
// SECURITY: The TreePath must be cleaned!
869-
comment.TreePath = path.Clean("/" + comment.TreePath)[1:]
869+
comment.TreePath = util.CleanPath(comment.TreePath)
870870

871871
var patch string
872872
reader, writer := io.Pipe()

services/packages/container/blob_uploader.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ import (
88
"errors"
99
"io"
1010
"os"
11-
"path"
1211
"path/filepath"
1312
"strings"
1413

1514
packages_model "code.gitea.io/gitea/models/packages"
1615
packages_module "code.gitea.io/gitea/modules/packages"
1716
"code.gitea.io/gitea/modules/setting"
17+
"code.gitea.io/gitea/modules/util"
1818
)
1919

2020
var (
@@ -33,7 +33,7 @@ type BlobUploader struct {
3333
}
3434

3535
func buildFilePath(id string) string {
36-
return filepath.Join(setting.Packages.ChunkedUploadPath, path.Clean("/" + strings.ReplaceAll(id, "\\", "/"))[1:])
36+
return filepath.Join(setting.Packages.ChunkedUploadPath, util.CleanPath(strings.ReplaceAll(id, "\\", "/")))
3737
}
3838

3939
// NewBlobUploader creates a new blob uploader for the given id

services/repository/files/file.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import (
77
"context"
88
"fmt"
99
"net/url"
10-
"path"
1110
"strings"
1211
"time"
1312

1413
repo_model "code.gitea.io/gitea/models/repo"
1514
user_model "code.gitea.io/gitea/models/user"
1615
"code.gitea.io/gitea/modules/git"
1716
api "code.gitea.io/gitea/modules/structs"
17+
"code.gitea.io/gitea/modules/util"
1818
)
1919

2020
// GetFileResponseFromCommit Constructs a FileResponse from a Commit object
@@ -129,7 +129,7 @@ func GetAuthorAndCommitterUsers(author, committer *IdentityOptions, doer *user_m
129129
// CleanUploadFileName Trims a filename and returns empty string if it is a .git directory
130130
func CleanUploadFileName(name string) string {
131131
// Rebase the filename
132-
name = strings.Trim(path.Clean("/"+name), "/")
132+
name = strings.Trim(util.CleanPath(name), "/")
133133
// Git disallows any filenames to have a .git directory in them.
134134
for _, part := range strings.Split(name, "/") {
135135
if strings.ToLower(part) == ".git" {

0 commit comments

Comments
 (0)