diff --git a/changelog.md b/changelog.md index c15ccbcc..6c315267 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,9 @@ ## Changelog +#### v1.6.0 + +* `[path]` Added package for working with paths + #### v1.5.1 * `[knf]` Fixed bug in HasProp method which return true for unset properties diff --git a/path/path.go b/path/path.go new file mode 100644 index 00000000..1a9b6e56 --- /dev/null +++ b/path/path.go @@ -0,0 +1,133 @@ +// +build !windows + +// Package path provides methods for working with paths (fully compatible with base path package) +package path + +// ////////////////////////////////////////////////////////////////////////////////// // +// // +// Copyright (c) 2009-2016 Essential Kaos // +// Essential Kaos Open Source License // +// // +// ////////////////////////////////////////////////////////////////////////////////// // + +import ( + "errors" + PATH "path" + "path/filepath" + + "pkg.re/essentialkaos/ek.v1/env" +) + +// ////////////////////////////////////////////////////////////////////////////////// // + +//ErrBadPattern indicates a globbing pattern was malformed +var ErrBadPattern = errors.New("syntax error in pattern") + +// unsafePaths is slice with unsafe paths +var unsafePaths = []string{ + "/lost+found", + "/bin", + "/boot", + "/etc", + "/dev", + "/lib", + "/lib64", + "/proc", + "/root", + "/sbin", + "/selinux", + "/sys", + "/usr/bin", + "/usr/lib", + "/usr/lib64", + "/usr/libexec", + "/usr/sbin", + "/usr/include", + "/var/cache", + "/var/db", + "/var/lib", +} + +// ////////////////////////////////////////////////////////////////////////////////// // + +// Base returns the last element of path +func Base(path string) string { + return PATH.Base(path) +} + +// Clean returns the shortest path name equivalent to path by purely lexical processing +func Clean(path string) string { + path = evalHome(path) + return PATH.Clean(path) +} + +// Dir returns all but the last element of path, typically the path's directory +func Dir(path string) string { + return PATH.Dir(path) +} + +// Ext returns the file name extension used by path +func Ext(path string) string { + return PATH.Ext(path) +} + +// IsAbs reports whether the path is absolute +func IsAbs(path string) bool { + return PATH.IsAbs(path) +} + +// Join joins any number of path elements into a single path, adding a separating slash if necessary +func Join(elem ...string) string { + return PATH.Join(elem...) +} + +// Match reports whether name matches the shell file name pattern +func Match(pattern, name string) (matched bool, err error) { + return PATH.Match(pattern, name) +} + +// Split splits path immediately following the final slash, separating it into a directory and file name component +func Split(path string) (dir, file string) { + return PATH.Split(path) +} + +// IsSafe return true is given path is safe to use (not points to system dirs) +func IsSafe(path string) bool { + if path == "" { + return false + } + + absPath, err := filepath.Abs(Clean(path)) + + if err != nil || absPath == "/" { + return false + } + + for _, up := range unsafePaths { + if contains(absPath, up) { + return false + } + } + + return true +} + +// ////////////////////////////////////////////////////////////////////////////////// // + +func evalHome(path string) string { + if path == "" || path[0:1] != "~" { + return path + } + + return env.Get()["HOME"] + path[1:] +} + +func contains(path, subpath string) bool { + spl := len(subpath) + + if len(path) < spl { + return false + } + + return path[:spl] == subpath +} diff --git a/path/path_test.go b/path/path_test.go new file mode 100644 index 00000000..5bb0e015 --- /dev/null +++ b/path/path_test.go @@ -0,0 +1,83 @@ +package path + +// ////////////////////////////////////////////////////////////////////////////////// // +// // +// Copyright (c) 2009-2016 Essential Kaos // +// Essential Kaos Open Source License // +// // +// ////////////////////////////////////////////////////////////////////////////////// // + +import ( + "pkg.re/essentialkaos/ek.v1/env" + "testing" + + . "pkg.re/check.v1" +) + +// ////////////////////////////////////////////////////////////////////////////////// // + +func Test(t *testing.T) { TestingT(t) } + +type PathUtilSuite struct{} + +// ////////////////////////////////////////////////////////////////////////////////// // + +var _ = Suite(&PathUtilSuite{}) + +// ////////////////////////////////////////////////////////////////////////////////// // + +func (s *PathUtilSuite) TestBase(c *C) { + c.Assert(Base("/some/test/path"), Equals, "path") + c.Assert(Clean("//some/test//path"), Equals, "/some/test/path") + c.Assert(Dir("/some/test/path"), Equals, "/some/test") + c.Assert(Ext("/some/test/path/file.jpg"), Equals, ".jpg") + c.Assert(IsAbs("/some/test/path"), Equals, true) + c.Assert(Join("/", "some", "test", "path"), Equals, "/some/test/path") + + match, err := Match("/some/test/*", "/some/test/path") + + c.Assert(match, Equals, true) + c.Assert(err, IsNil) + + d, f := Split("/some/test/path/file.jpg") + + c.Assert(d, Equals, "/some/test/path/") + c.Assert(f, Equals, "file.jpg") +} + +func (s *PathUtilSuite) TestEvalHome(c *C) { + homeDir := env.Get()["HOME"] + + c.Assert(Clean("~/path"), Equals, homeDir+"/path") + c.Assert(Clean("/path"), Equals, "/path") +} + +func (s *PathUtilSuite) TestSafe(c *C) { + c.Assert(IsSafe("/home/user/test.jpg"), Equals, true) + c.Assert(IsSafe("/home/user"), Equals, true) + c.Assert(IsSafe("/opt/software-1234"), Equals, true) + c.Assert(IsSafe("/srv/my-supper-service"), Equals, true) + + c.Assert(IsSafe(""), Equals, false) + c.Assert(IsSafe("/"), Equals, false) + c.Assert(IsSafe("/dev/tty3"), Equals, false) + c.Assert(IsSafe("/etc/file.conf"), Equals, false) + c.Assert(IsSafe("/lib/some-lib"), Equals, false) + c.Assert(IsSafe("/lib64/some-lib"), Equals, false) + c.Assert(IsSafe("/lost+found"), Equals, false) + c.Assert(IsSafe("/proc/19313"), Equals, false) + c.Assert(IsSafe("/root"), Equals, false) + c.Assert(IsSafe("/sbin/useradd"), Equals, false) + c.Assert(IsSafe("/bin/useradd"), Equals, false) + c.Assert(IsSafe("/selinux"), Equals, false) + c.Assert(IsSafe("/sys/kernel"), Equals, false) + c.Assert(IsSafe("/usr/bin/du"), Equals, false) + c.Assert(IsSafe("/usr/sbin/chroot"), Equals, false) + c.Assert(IsSafe("/usr/lib/some-lib"), Equals, false) + c.Assert(IsSafe("/usr/lib64/some-lib"), Equals, false) + c.Assert(IsSafe("/usr/libexec/gcc"), Equals, false) + c.Assert(IsSafe("/usr/include/xlocale.h"), Equals, false) + c.Assert(IsSafe("/var/cache/yum"), Equals, false) + c.Assert(IsSafe("/var/db/yum"), Equals, false) + c.Assert(IsSafe("/var/lib/pgsql"), Equals, false) +} diff --git a/path/path_windows.go b/path/path_windows.go new file mode 100644 index 00000000..713938ff --- /dev/null +++ b/path/path_windows.go @@ -0,0 +1,67 @@ +// +build windows + +// Package path provides methods for working with paths (fully compatible with base path package) +package path + +// ////////////////////////////////////////////////////////////////////////////////// // +// // +// Copyright (c) 2009-2016 Essential Kaos // +// Essential Kaos Open Source License // +// // +// ////////////////////////////////////////////////////////////////////////////////// // + +import ( + "errors" +) + +// ////////////////////////////////////////////////////////////////////////////////// // + +//ErrBadPattern indicates a globbing pattern was malformed +var ErrBadPattern = errors.New("syntax error in pattern") + +// ////////////////////////////////////////////////////////////////////////////////// // + +// Base returns the last element of path +func Base(path string) string { + return "" +} + +// Clean returns the shortest path name equivalent to path by purely lexical processing +func Clean(path string) string { + return "" +} + +// Dir returns all but the last element of path, typically the path's directory +func Dir(path string) string { + return "" +} + +// Ext returns the file name extension used by path +func Ext(path string) string { + return "" +} + +// IsAbs reports whether the path is absolute +func IsAbs(path string) bool { + return "" +} + +// Join joins any number of path elements into a single path, adding a separating slash if necessary +func Join(elem ...string) string { + return "" +} + +// Match reports whether name matches the shell file name pattern +func Match(pattern, name string) (matched bool, err error) { + return false, nil +} + +// Split splits path immediately following the final slash, separating it into a directory and file name component +func Split(path string) (dir, file string) { + return "", "" +} + +// IsSafe return true is given path is safe to use (not points to system dirs) +func IsSafe(path string) bool { + return false +} diff --git a/readme.md b/readme.md index 05db980d..88a5ba24 100644 --- a/readme.md +++ b/readme.md @@ -31,6 +31,7 @@ go get pkg.re/essentialkaos/ek.v1 * `log` - Package with improved logger * `mathutil` - Package with math utils * `netutil` - Package with network utils +* `path` - Package for working with paths (fully compatible with base path package) * `pid` - Package for working with pid files * `rand` - Package for generating random data * `req` - Package for working with http request