Use fileutils instead
							parent
							
								
									dac92eec8b
								
							
						
					
					
						commit
						ff034f7e8f
					
				| 
						 | 
				
			
			@ -13,7 +13,7 @@ import (
 | 
			
		|||
	"strings"
 | 
			
		||||
 | 
			
		||||
	. "github.com/hacdias/filemanager"
 | 
			
		||||
	"github.com/hacdias/filemanager/dir"
 | 
			
		||||
	"github.com/hacdias/fileutils"
 | 
			
		||||
	"github.com/mholt/caddy"
 | 
			
		||||
	"github.com/mholt/caddy/caddyhttp/httpserver"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -136,7 +136,7 @@ func parse(c *caddy.Controller) ([]*config, error) {
 | 
			
		|||
				Regexp: &Regexp{Raw: "\\/\\..+"},
 | 
			
		||||
			}},
 | 
			
		||||
			CSS:        "",
 | 
			
		||||
			FileSystem: dir.Dir(baseScope),
 | 
			
		||||
			FileSystem: fileutils.Dir(baseScope),
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,7 +12,7 @@ import (
 | 
			
		|||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/hacdias/filemanager"
 | 
			
		||||
	"github.com/hacdias/filemanager/dir"
 | 
			
		||||
	"github.com/hacdias/fileutils"
 | 
			
		||||
	"github.com/mholt/caddy"
 | 
			
		||||
	"github.com/mholt/caddy/caddyhttp/httpserver"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -112,7 +112,7 @@ func parse(c *caddy.Controller) ([]*filemanager.FileManager, error) {
 | 
			
		|||
				Regexp: &filemanager.Regexp{Raw: "\\/\\..+"},
 | 
			
		||||
			}},
 | 
			
		||||
			CSS:        "",
 | 
			
		||||
			FileSystem: dir.Dir(directory),
 | 
			
		||||
			FileSystem: fileutils.Dir(directory),
 | 
			
		||||
		})
 | 
			
		||||
 | 
			
		||||
		if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ import (
 | 
			
		|||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/hacdias/filemanager"
 | 
			
		||||
	"github.com/hacdias/filemanager/dir"
 | 
			
		||||
	"github.com/hacdias/fileutils"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// confFile contains the configuration file for this File Manager instance.
 | 
			
		||||
| 
						 | 
				
			
			@ -65,7 +65,7 @@ func main() {
 | 
			
		|||
		Commands:      strings.Split(strings.TrimSpace(commands), " "),
 | 
			
		||||
		Rules:         []*filemanager.Rule{},
 | 
			
		||||
		CSS:           "",
 | 
			
		||||
		FileSystem:    dir.Dir(scope),
 | 
			
		||||
		FileSystem:    fileutils.Dir(scope),
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	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"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/hacdias/filemanager/dir"
 | 
			
		||||
	"github.com/hacdias/fileutils"
 | 
			
		||||
	"github.com/mholt/archiver"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ func downloadHandler(c *RequestContext, w http.ResponseWriter, r *http.Request)
 | 
			
		|||
			}
 | 
			
		||||
 | 
			
		||||
			// Clean the slashes.
 | 
			
		||||
			name = dir.SlashClean(name)
 | 
			
		||||
			name = fileutils.SlashClean(name)
 | 
			
		||||
			files = append(files, filepath.Join(c.FI.Path, name))
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,7 @@ import (
 | 
			
		|||
 | 
			
		||||
	rice "github.com/GeertJohan/go.rice"
 | 
			
		||||
	"github.com/asdine/storm"
 | 
			
		||||
	"github.com/hacdias/filemanager/dir"
 | 
			
		||||
	"github.com/hacdias/fileutils"
 | 
			
		||||
	"github.com/mholt/caddy"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +76,7 @@ type User struct {
 | 
			
		|||
	Admin bool `json:"admin"`
 | 
			
		||||
 | 
			
		||||
	// 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 []*Rule `json:"rules"`
 | 
			
		||||
| 
						 | 
				
			
			@ -136,7 +136,7 @@ var DefaultUser = User{
 | 
			
		|||
	Rules:         []*Rule{},
 | 
			
		||||
	CSS:           "",
 | 
			
		||||
	Admin:         true,
 | 
			
		||||
	FileSystem:    dir.Dir("."),
 | 
			
		||||
	FileSystem:    fileutils.Dir("."),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New creates a new File Manager instance. If 'database' file already
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,7 +6,7 @@ import (
 | 
			
		|||
	"path/filepath"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/hacdias/filemanager/dir"
 | 
			
		||||
	"github.com/hacdias/fileutils"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type test struct {
 | 
			
		||||
| 
						 | 
				
			
			@ -28,13 +28,13 @@ func newTest(t *testing.T) *test {
 | 
			
		|||
	scope := filepath.Join(temp, "scope")
 | 
			
		||||
	database := filepath.Join(temp, "database.db")
 | 
			
		||||
 | 
			
		||||
	err = dir.CopyDir("./testdata", scope)
 | 
			
		||||
	err = fileutils.CopyDir("./testdata", scope)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		t.Fatalf("Error copying the test data: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	user := DefaultUser
 | 
			
		||||
	user.FileSystem = dir.Dir(scope)
 | 
			
		||||
	user.FileSystem = fileutils.Dir(scope)
 | 
			
		||||
 | 
			
		||||
	fm, err := New(database, user)
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -10,13 +10,13 @@ import (
 | 
			
		|||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"github.com/hacdias/filemanager/dir"
 | 
			
		||||
	"github.com/hacdias/fileutils"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 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 {
 | 
			
		||||
	path := dir.SlashClean(url)
 | 
			
		||||
	path := fileutils.SlashClean(url)
 | 
			
		||||
	if strings.HasSuffix(url, "/") && path != "/" {
 | 
			
		||||
		return path + "/"
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue