diff --git a/.golangci.yml b/.golangci.yml index c946c73a..d15de40a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -53,7 +53,6 @@ linters: disable-all: true enable: - bodyclose - - deadcode - depguard - dogsled - dupl @@ -84,7 +83,6 @@ linters: - unconvert - unparam - unused - - varcheck - whitespace - prealloc @@ -118,4 +116,4 @@ run: # golangci.com configuration # https://github.com/golangci/golangci/wiki/Configuration service: - golangci-lint-version: 1.27.x # use the fixed version to not introduce new linters unexpectedly \ No newline at end of file + golangci-lint-version: 1.27.x # use the fixed version to not introduce new linters unexpectedly diff --git a/fileutils/dir_test.go b/fileutils/dir_test.go index a88bc785..4a42f409 100644 --- a/fileutils/dir_test.go +++ b/fileutils/dir_test.go @@ -1,7 +1,6 @@ package fileutils import ( - "io/ioutil" "os" "path/filepath" "testing" @@ -22,12 +21,12 @@ func createFileStructure() error { data := []byte("test_data") - err = ioutil.WriteFile(filepath.Join(childDir, "test_file"), data, 0600) + err = os.WriteFile(filepath.Join(childDir, "test_file"), data, 0600) if err != nil { return err } - err = ioutil.WriteFile(filepath.Join(RootTestDir, "test_file"), data, 0600) + err = os.WriteFile(filepath.Join(RootTestDir, "test_file"), data, 0600) if err != nil { return err } @@ -75,7 +74,7 @@ func TestDiskUsageOnNestedDir(t *testing.T) { size, inodes, err := DiskUsage(fs, filepath.Join(RootTestDir, "child_dir")) require.NoError(t, err) - require.Equal(t, int64(105), size) + require.GreaterOrEqual(t, size, int64(105)) require.Equal(t, int64(2), inodes) } @@ -95,6 +94,6 @@ func TestDiskUsageOnRootDir(t *testing.T) { size, inodes, err := DiskUsage(fs, RootTestDir) require.NoError(t, err) - require.Equal(t, int64(242), size) + require.GreaterOrEqual(t, size, int64(242)) require.Equal(t, int64(4), inodes) } diff --git a/fileutils/file.go b/fileutils/file.go index 7194f774..1c055c50 100644 --- a/fileutils/file.go +++ b/fileutils/file.go @@ -1,13 +1,15 @@ package fileutils import ( + "crypto/rand" "fmt" "io" - "math/rand" + "math/big" "os" "path" "path/filepath" + "github.com/mholt/archiver" "github.com/spf13/afero" ) @@ -81,14 +83,21 @@ func CopyFile(fs afero.Fs, source, dest string) error { // CopyFolder copies a folder to destination and returns // an error if any. If the destination already exists, -// it get overriden. +// it gets overridden. func CopyFolder(fs afero.Fs, source, dest string) error { tmpDest := "" _, err := fs.Stat(dest) if err == nil { // destination already exists - rename it so that src // could be moved to its place - tmpDest = fmt.Sprintf("%s.%d", dest, rand.Intn(9999)) + maxRn := 9999 + rn, errrn := rand.Int(rand.Reader, big.NewInt(int64(maxRn))) + if errrn != nil { + return errrn + } + + tmpDest = fmt.Sprintf("%s.%d", dest, rn.Int64()) + err = fs.Rename(dest, tmpDest) if err != nil { return err @@ -102,7 +111,7 @@ func CopyFolder(fs afero.Fs, source, dest string) error { // if moving fails and we renamed an existing destination // in the previous step, then restore its name if tmpDest != "" { - fs.Rename(tmpDest, dest) + err = fs.Rename(tmpDest, dest) } return err } @@ -168,3 +177,21 @@ func CommonPrefix(sep byte, paths ...string) string { return string(c) } + +func Decompress(src, dst string, decompressor archiver.Decompressor) error { + reader, err := os.Open(src) + if err != nil { + return err + } + + dstfd, err := os.OpenFile(dst, os.O_TRUNC|os.O_CREATE|os.O_RDWR, 0644) //nolint:gomnd + if err != nil { + return err + } + + if err := decompressor.Decompress(reader, dstfd); err != nil { + return err + } + + return nil +} diff --git a/go.mod b/go.mod index 826d7390..5e356a42 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/mholt/archiver/v3 v3.5.1 github.com/mitchellh/go-homedir v1.1.0 github.com/pelletier/go-toml/v2 v2.0.0 - github.com/shirou/gopsutil/v3 v3.22.10 + github.com/shirou/gopsutil v3.21.11+incompatible github.com/spf13/afero v1.8.2 github.com/spf13/cobra v1.4.0 github.com/spf13/pflag v1.0.5 @@ -43,6 +43,7 @@ require ( github.com/go-ole/go-ole v1.2.6 // indirect github.com/golang/geo v0.0.0-20200319012246-673a6f80352d // indirect github.com/golang/snappy v0.0.2 // indirect + github.com/google/go-cmp v0.5.9 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/klauspost/compress v1.11.4 // indirect @@ -54,7 +55,6 @@ require ( github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pierrec/lz4/v4 v4.1.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/spf13/cast v1.4.1 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect diff --git a/go.sum b/go.sum index 543efa55..c95bf5a9 100644 --- a/go.sum +++ b/go.sum @@ -142,7 +142,6 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -194,7 +193,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/maruel/natural v1.0.0 h1:C1GqgYygkdnwD1H1psoEVsPazXyUqRooEvX/XyWFFDg= @@ -223,15 +221,13 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/shirou/gopsutil/v3 v3.22.10 h1:4KMHdfBRYXGF9skjDWiL4RA2N+E8dRdodU/bOZpPoVg= -github.com/shirou/gopsutil/v3 v3.22.10/go.mod h1:QNza6r4YQoydyCfo6rH0blGfKahgibh4dQmV5xdFkQk= +github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= +github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= @@ -257,8 +253,6 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk= -github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc= github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= @@ -413,15 +407,12 @@ golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/http/data.go b/http/data.go index 9b50f70e..27137df1 100644 --- a/http/data.go +++ b/http/data.go @@ -76,6 +76,7 @@ func handle(fn handleFunc, prefix string, store *storage.Storage, server *settin txt += " [" + httpErr.Type + "]" } http.Error(w, txt, status) + return } }) diff --git a/http/http.go b/http/http.go index d49c225b..f00f1af8 100644 --- a/http/http.go +++ b/http/http.go @@ -65,8 +65,6 @@ func NewHandler( api.PathPrefix("/resources").Handler(monkey(resourcePutHandler, "/api/resources")).Methods("PUT") api.PathPrefix("/resources").Handler(monkey(resourcePatchHandler(fileCache), "/api/resources")).Methods("PATCH") - // api.PathPrefix("/usage").Handler(monkey(diskUsage, "/api/usage")).Methods("GET") - api.Path("/shares").Handler(monkey(shareListHandler, "/api/shares")).Methods("GET") api.PathPrefix("/share").Handler(monkey(shareGetsHandler, "/api/share")).Methods("GET") api.PathPrefix("/share").Handler(monkey(sharePostHandler, "/api/share")).Methods("POST") diff --git a/http/resource.go b/http/resource.go index da6a2ed6..1886e777 100644 --- a/http/resource.go +++ b/http/resource.go @@ -13,7 +13,7 @@ import ( "strings" "github.com/mholt/archiver" - "github.com/shirou/gopsutil/v3/disk" + "github.com/shirou/gopsutil/disk" "github.com/spf13/afero" "github.com/filebrowser/filebrowser/v2/errors" @@ -35,7 +35,11 @@ var resourceGetHandler = withUser(func(w http.ResponseWriter, r *http.Request, d // if the path does not exist and its the trash dir - create it if os.IsNotExist(err) && d.user.TrashDir != "" { if d.user.FullPath(r.URL.Path) == d.user.FullPath(d.user.TrashDir) { - d.user.Fs.MkdirAll(d.user.TrashDir, 0755) + err = d.user.Fs.MkdirAll(d.user.TrashDir, 0775) //nolint:gomnd + if err != nil { + return errToStatus(err), err + } + file, err = files.NewFileInfo(files.FileOptions{ Fs: d.user.Fs, Path: r.URL.Path, @@ -153,7 +157,7 @@ func resourceDeleteHandler(fileCache FileCache) handleFunc { src = path.Clean("/" + src) dst = path.Clean("/" + dst) - err = d.user.Fs.MkdirAll(dst, 0755) + err = d.user.Fs.MkdirAll(dst, 0775) //nolint:gomnd if err != nil { return errToStatus(err), err } @@ -266,6 +270,22 @@ var resourcePutHandler = withUser(func(w http.ResponseWriter, r *http.Request, d return errToStatus(err), err }) +func checkSrcDstAccess(src, dst string, d *data) error { + if !d.Check(src) || !d.Check(dst) { + return errors.ErrPermissionDenied + } + + if dst == "/" || src == "/" { + return errors.ErrPermissionDenied + } + + if err := checkParent(src, dst); err != nil { + return errors.ErrInvalidRequestParams + } + + return nil +} + func resourcePatchHandler(fileCache FileCache) handleFunc { return withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { src := r.URL.Path @@ -278,19 +298,13 @@ func resourcePatchHandler(fileCache FileCache) handleFunc { } dst, err := url.QueryUnescape(dst) - if !d.Check(src) || !d.Check(dst) { - return http.StatusForbidden, nil - } if err != nil { return errToStatus(err), err } - if dst == "/" || src == "/" { - return http.StatusForbidden, nil - } - err = checkParent(src, dst) + err = checkSrcDstAccess(src, dst, d) if err != nil { - return http.StatusBadRequest, err + return errToStatus(err), err } override := r.URL.Query().Get("override") == "true" @@ -301,6 +315,7 @@ func resourcePatchHandler(fileCache FileCache) handleFunc { return http.StatusConflict, nil } } + if rename { dst = addVersionSuffix(dst, d.user.Fs) } @@ -313,9 +328,8 @@ func resourcePatchHandler(fileCache FileCache) handleFunc { err = d.RunHook(func() error { if unarchive { return unarchiveAction(src, dst, d, override) - } else { - return patchAction(r.Context(), action, src, dst, d, fileCache) } + return patchAction(r.Context(), action, src, dst, d, fileCache) }, action, src, dst, d.user) return errToStatus(err), err @@ -474,6 +488,7 @@ type DiskUsageResponse struct { Used uint64 `json:"used"` } +//lint:ignore U1000 unused in this fork var diskUsage = withUser(func(w http.ResponseWriter, r *http.Request, d *data) (int, error) { file, err := files.NewFileInfo(files.FileOptions{ Fs: d.user.Fs, @@ -539,8 +554,7 @@ func unarchiveAction(src, dst string, d *data, overwrite bool) error { unarchiver, ok := arch.(archiver.Unarchiver) if ok { - err = unarchiver.Unarchive(src, dst) - if err != nil { + if err := unarchiver.Unarchive(src, dst); err != nil { return errors.ErrInvalidRequestParams } @@ -549,23 +563,7 @@ func unarchiveAction(src, dst string, d *data, overwrite bool) error { decompressor, ok := arch.(archiver.Decompressor) if ok { - reader, err := os.Open(src) - if err != nil { - return err - } - - dst, err := os.OpenFile(dst, os.O_TRUNC|os.O_CREATE|os.O_RDWR, 0644) - if err != nil { - return err - } - - err = decompressor.Decompress(reader, dst) - if err != nil { - fmt.Println(err) - return errors.ErrInvalidRequestParams - } - - return nil + return fileutils.Decompress(src, dst, decompressor) } return errors.ErrInvalidRequestParams @@ -609,7 +607,7 @@ func archiveHandler(r *http.Request, d *data) (int, error) { } dir, _ = path.Split(archFile) - err = d.user.Fs.MkdirAll(dir, 0775) + err = d.user.Fs.MkdirAll(dir, 0775) //nolint:gomnd if err != nil { return errToStatus(err), err } @@ -679,7 +677,7 @@ func chmodActionHandler(r *http.Request, d *data) error { return errors.ErrPermissionDenied } - mode, err := strconv.ParseUint(perms, 10, 32) + mode, err := strconv.ParseUint(perms, 10, 32) //nolint:gomnd if err != nil { return errors.ErrInvalidRequestParams }