Use fileutils instead
Former-commit-id: 2688c5dca3865614edaf7b159b7f0dcebad77171 [formerly b919610fb1d09db5e6b6308e5adc0d431ce6c139] [formerly b7c60fcf5771ec9d1854947dd89dc51ff414bdb7 [formerly ff034f7e8f
]]
Former-commit-id: a63a598c5cef6c050a8a0d189bc5235a98d5457a [formerly cab7076a63efddbfb968c151c5ef1d34b00dac56]
Former-commit-id: f167b30eeea3a9c0b8fec43dc37ee95cd8c172e6
This commit is contained in:
parent
afb10cc02c
commit
f40731d3b4
|
@ -13,7 +13,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
. "github.com/hacdias/filemanager"
|
. "github.com/hacdias/filemanager"
|
||||||
"github.com/hacdias/filemanager/dir"
|
"github.com/hacdias/fileutils"
|
||||||
"github.com/mholt/caddy"
|
"github.com/mholt/caddy"
|
||||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||||
)
|
)
|
||||||
|
@ -136,7 +136,7 @@ func parse(c *caddy.Controller) ([]*config, error) {
|
||||||
Regexp: &Regexp{Raw: "\\/\\..+"},
|
Regexp: &Regexp{Raw: "\\/\\..+"},
|
||||||
}},
|
}},
|
||||||
CSS: "",
|
CSS: "",
|
||||||
FileSystem: dir.Dir(baseScope),
|
FileSystem: fileutils.Dir(baseScope),
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hacdias/filemanager"
|
"github.com/hacdias/filemanager"
|
||||||
"github.com/hacdias/filemanager/dir"
|
"github.com/hacdias/fileutils"
|
||||||
"github.com/mholt/caddy"
|
"github.com/mholt/caddy"
|
||||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||||
)
|
)
|
||||||
|
@ -112,7 +112,7 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) {
|
||||||
Regexp: &filemanager.Regexp{Raw: "\\/\\..+"},
|
Regexp: &filemanager.Regexp{Raw: "\\/\\..+"},
|
||||||
}},
|
}},
|
||||||
CSS: "",
|
CSS: "",
|
||||||
FileSystem: dir.Dir(directory),
|
FileSystem: fileutils.Dir(directory),
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hacdias/filemanager"
|
"github.com/hacdias/filemanager"
|
||||||
"github.com/hacdias/filemanager/dir"
|
"github.com/hacdias/fileutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// confFile contains the configuration file for this File Manager instance.
|
// confFile contains the configuration file for this File Manager instance.
|
||||||
|
@ -65,7 +65,7 @@ func main() {
|
||||||
Commands: strings.Split(strings.TrimSpace(commands), " "),
|
Commands: strings.Split(strings.TrimSpace(commands), " "),
|
||||||
Rules: []*filemanager.Rule{},
|
Rules: []*filemanager.Rule{},
|
||||||
CSS: "",
|
CSS: "",
|
||||||
FileSystem: dir.Dir(scope),
|
FileSystem: fileutils.Dir(scope),
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
230
dir/dir.go
230
dir/dir.go
|
@ -1,230 +0,0 @@
|
||||||
// Package dir implements a FileSystem interface using the native
|
|
||||||
// file system restricted to a specific directory tree. Originally from
|
|
||||||
// https://github.com/golang/net/blob/master/webdav/file.go#L68
|
|
||||||
package dir
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// A Dir uses the native file system restricted to a specific directory tree.
|
|
||||||
//
|
|
||||||
// While the FileSystem.OpenFile method takes '/'-separated paths, a Dir's
|
|
||||||
// string value is a filename on the native file system, not a URL, so it is
|
|
||||||
// separated by filepath.Separator, which isn't necessarily '/'.
|
|
||||||
//
|
|
||||||
// An empty Dir is treated as ".".
|
|
||||||
type Dir string
|
|
||||||
|
|
||||||
func (d Dir) resolve(name string) string {
|
|
||||||
// This implementation is based on Dir.Open's code in the standard net/http package.
|
|
||||||
if filepath.Separator != '/' && strings.IndexRune(name, filepath.Separator) >= 0 ||
|
|
||||||
strings.Contains(name, "\x00") {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
dir := string(d)
|
|
||||||
if dir == "" {
|
|
||||||
dir = "."
|
|
||||||
}
|
|
||||||
|
|
||||||
return filepath.Join(dir, filepath.FromSlash(SlashClean(name)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mkdir implements os.Mkdir in this directory context.
|
|
||||||
func (d Dir) Mkdir(name string, perm os.FileMode) error {
|
|
||||||
if name = d.resolve(name); name == "" {
|
|
||||||
return os.ErrNotExist
|
|
||||||
}
|
|
||||||
return os.Mkdir(name, perm)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenFile implements os.OpenFile in this directory context.
|
|
||||||
func (d Dir) OpenFile(name string, flag int, perm os.FileMode) (*os.File, error) {
|
|
||||||
if name = d.resolve(name); name == "" {
|
|
||||||
return nil, os.ErrNotExist
|
|
||||||
}
|
|
||||||
f, err := os.OpenFile(name, flag, perm)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return f, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveAll implements os.RemoveAll in this directory context.
|
|
||||||
func (d Dir) RemoveAll(name string) error {
|
|
||||||
if name = d.resolve(name); name == "" {
|
|
||||||
return os.ErrNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
if name == filepath.Clean(string(d)) {
|
|
||||||
// Prohibit removing the virtual root directory.
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
return os.RemoveAll(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rename implements os.Rename in this directory context.
|
|
||||||
func (d Dir) Rename(oldName, newName string) error {
|
|
||||||
if oldName = d.resolve(oldName); oldName == "" {
|
|
||||||
return os.ErrNotExist
|
|
||||||
}
|
|
||||||
if newName = d.resolve(newName); newName == "" {
|
|
||||||
return os.ErrNotExist
|
|
||||||
}
|
|
||||||
if root := filepath.Clean(string(d)); root == oldName || root == newName {
|
|
||||||
// Prohibit renaming from or to the virtual root directory.
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
return os.Rename(oldName, newName)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stat implements os.Stat in this directory context.
|
|
||||||
func (d Dir) Stat(name string) (os.FileInfo, error) {
|
|
||||||
if name = d.resolve(name); name == "" {
|
|
||||||
return nil, os.ErrNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.Stat(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy copies a file or directory from src to dst. If it is
|
|
||||||
// a directory, all of the files and sub-directories will be copied.
|
|
||||||
func (d Dir) Copy(src, dst string) error {
|
|
||||||
if src = d.resolve(src); src == "" {
|
|
||||||
return os.ErrNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
if dst = d.resolve(dst); dst == "" {
|
|
||||||
return os.ErrNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
if root := filepath.Clean(string(d)); root == src || root == dst {
|
|
||||||
// Prohibit copying from or to the virtual root directory.
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
|
|
||||||
if dst == src {
|
|
||||||
return os.ErrInvalid
|
|
||||||
}
|
|
||||||
|
|
||||||
info, err := os.Stat(src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if info.IsDir() {
|
|
||||||
return CopyDir(src, dst)
|
|
||||||
}
|
|
||||||
|
|
||||||
return CopyFile(src, dst)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SlashClean is equivalent to but slightly more efficient than
|
|
||||||
// path.Clean("/" + name).
|
|
||||||
func SlashClean(name string) string {
|
|
||||||
if name == "" || name[0] != '/' {
|
|
||||||
name = "/" + name
|
|
||||||
}
|
|
||||||
return path.Clean(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyFile copies a file from source to dest and returns
|
|
||||||
// an error if any.
|
|
||||||
func CopyFile(source string, dest string) error {
|
|
||||||
// Open the source file.
|
|
||||||
src, err := os.Open(source)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer src.Close()
|
|
||||||
|
|
||||||
// Makes the directory needed to create the dst
|
|
||||||
// file.
|
|
||||||
err = os.MkdirAll(filepath.Dir(dest), 0666)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the destination file.
|
|
||||||
dst, err := os.Create(dest)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer dst.Close()
|
|
||||||
|
|
||||||
// Copy the contents of the file.
|
|
||||||
_, err = io.Copy(dst, src)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the mode if the user can't
|
|
||||||
// open the file.
|
|
||||||
info, err := os.Stat(source)
|
|
||||||
if err != nil {
|
|
||||||
err = os.Chmod(dest, info.Mode())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyDir copies a directory from source to dest and all
|
|
||||||
// of its sub-directories. It doesn't stop if it finds an error
|
|
||||||
// during the copy. Returns an error if any.
|
|
||||||
func CopyDir(source string, dest string) error {
|
|
||||||
// Get properties of source.
|
|
||||||
srcinfo, err := os.Stat(source)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the destination directory.
|
|
||||||
err = os.MkdirAll(dest, srcinfo.Mode())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
dir, _ := os.Open(source)
|
|
||||||
obs, err := dir.Readdir(-1)
|
|
||||||
|
|
||||||
var errs []error
|
|
||||||
|
|
||||||
for _, obj := range obs {
|
|
||||||
fsource := source + "/" + obj.Name()
|
|
||||||
fdest := dest + "/" + obj.Name()
|
|
||||||
|
|
||||||
if obj.IsDir() {
|
|
||||||
// Create sub-directories, recursively.
|
|
||||||
err = CopyDir(fsource, fdest)
|
|
||||||
if err != nil {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Perform the file copy.
|
|
||||||
err = CopyFile(fsource, fdest)
|
|
||||||
if err != nil {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var errString string
|
|
||||||
for _, err := range errs {
|
|
||||||
errString += err.Error() + "\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
if errString != "" {
|
|
||||||
return errors.New(errString)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hacdias/filemanager/dir"
|
"github.com/hacdias/fileutils"
|
||||||
"github.com/mholt/archiver"
|
"github.com/mholt/archiver"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ func downloadHandler(c *RequestContext, w http.ResponseWriter, r *http.Request)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean the slashes.
|
// Clean the slashes.
|
||||||
name = dir.SlashClean(name)
|
name = fileutils.SlashClean(name)
|
||||||
files = append(files, filepath.Join(c.FI.Path, name))
|
files = append(files, filepath.Join(c.FI.Path, name))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
|
|
||||||
rice "github.com/GeertJohan/go.rice"
|
rice "github.com/GeertJohan/go.rice"
|
||||||
"github.com/asdine/storm"
|
"github.com/asdine/storm"
|
||||||
"github.com/hacdias/filemanager/dir"
|
"github.com/hacdias/fileutils"
|
||||||
"github.com/mholt/caddy"
|
"github.com/mholt/caddy"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ type User struct {
|
||||||
Admin bool `json:"admin"`
|
Admin bool `json:"admin"`
|
||||||
|
|
||||||
// FileSystem is the virtual file system the user has access.
|
// FileSystem is the virtual file system the user has access.
|
||||||
FileSystem dir.Dir `json:"filesystem"`
|
FileSystem fileutils.Dir `json:"filesystem"`
|
||||||
|
|
||||||
// Rules is an array of access and deny rules.
|
// Rules is an array of access and deny rules.
|
||||||
Rules []*Rule `json:"rules"`
|
Rules []*Rule `json:"rules"`
|
||||||
|
@ -136,7 +136,7 @@ var DefaultUser = User{
|
||||||
Rules: []*Rule{},
|
Rules: []*Rule{},
|
||||||
CSS: "",
|
CSS: "",
|
||||||
Admin: true,
|
Admin: true,
|
||||||
FileSystem: dir.Dir("."),
|
FileSystem: fileutils.Dir("."),
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new File Manager instance. If 'database' file already
|
// New creates a new File Manager instance. If 'database' file already
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hacdias/filemanager/dir"
|
"github.com/hacdias/fileutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
type test struct {
|
type test struct {
|
||||||
|
@ -28,13 +28,13 @@ func newTest(t *testing.T) *test {
|
||||||
scope := filepath.Join(temp, "scope")
|
scope := filepath.Join(temp, "scope")
|
||||||
database := filepath.Join(temp, "database.db")
|
database := filepath.Join(temp, "database.db")
|
||||||
|
|
||||||
err = dir.CopyDir("./testdata", scope)
|
err = fileutils.CopyDir("./testdata", scope)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Error copying the test data: %v", err)
|
t.Fatalf("Error copying the test data: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
user := DefaultUser
|
user := DefaultUser
|
||||||
user.FileSystem = dir.Dir(scope)
|
user.FileSystem = fileutils.Dir(scope)
|
||||||
|
|
||||||
fm, err := New(database, user)
|
fm, err := New(database, user)
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,13 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/hacdias/filemanager/dir"
|
"github.com/hacdias/fileutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// sanitizeURL sanitizes the URL to prevent path transversal
|
// sanitizeURL sanitizes the URL to prevent path transversal
|
||||||
// using dir.SlashClean and adds the trailing slash bar.
|
// using fileutils.SlashClean and adds the trailing slash bar.
|
||||||
func sanitizeURL(url string) string {
|
func sanitizeURL(url string) string {
|
||||||
path := dir.SlashClean(url)
|
path := fileutils.SlashClean(url)
|
||||||
if strings.HasSuffix(url, "/") && path != "/" {
|
if strings.HasSuffix(url, "/") && path != "/" {
|
||||||
return path + "/"
|
return path + "/"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue