Skip to content

Commit

Permalink
fix zip.Unzip path traversal vulnerability and add some new file util…
Browse files Browse the repository at this point in the history
…ity functions
  • Loading branch information
R22627 authored and R22627 committed Mar 14, 2023
1 parent 4c79264 commit 0e308b0
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 45 deletions.
66 changes: 48 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,24 @@ gbkStr := []byte{0xC4, 0xE3, 0xBA, 0xC3} // 你好 in gbk
utf8Str, _ := GbkToUtf8(gbkStr) // 你好 in utf8
gbkStrRes, _ := Utf8ToGbk(utf8Str) // [196 227 186 195]
```
Some converting function to json.
```go
student := struct {
Hobby string
Age int32
}{
Hobby: "pingpopng",
Age: 28,
}
encoding.ToIndentJSON(&student)
/*
output:
{
"Hobby": "pingpopng",
"Age": 28
}
*/
```
# Net
Some useful functions can be used to handle network. For example you can use `IPv4StrToU32()` transform ipv4 string to uint32 value.

Expand Down Expand Up @@ -329,26 +347,38 @@ math.GetRandLowerStr(3) // lts
math.GetRandUpperStr(3) // YUT
```

# JSON

Some converting function to json.
# File

```go
student := struct {
Hobby string
Age int32
}{
Hobby: "pingpopng",
Age: 28,
}
encoding.ToIndentJSON(&student)
/*
output:
{
"Hobby": "pingpopng",
"Age": 28
}
*/
// ListDir lists all the file or directory names in the specified directory.
ListDir()

// IsExist checks whether a file/dir exists.
IsExist()

// IsDir checks whether a path is a directory.
IsDir()
IsDirE()

// IsFile checks whether a path is a file.
IsFile()
IsFileE()

// IsSymlink checks a file whether is a symbolic link file on Linux.
IsSymlink()
IsSymlinkE()

// IsShortcut checks a file whether is a shortcut on Windows.
IsShortcutFile()

// Create a file.
Create()
CreateFile()

// ClearFile clears a file content.
ClearFile()

// ...
```

# Comparison
Expand Down
65 changes: 44 additions & 21 deletions file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func ReadLinesV2(path string) ([]string, int, error) {
}
}

// ListDir lists all the file or dir names in the specified directory.
// ListDir lists all the file or directory names in the specified directory.
// Note that ListDir don't traverse recursively.
func ListDir(dirname string) ([]string, error) {
infos, err := ioutil.ReadDir(dirname)
Expand All @@ -69,12 +69,12 @@ func ListDir(dirname string) ([]string, error) {
return names, nil
}

// IsPathExist checks whether a file/dir exists.
// IsExist checks whether a file/dir exists.
// Use os.Stat to get the info of the target file or dir to check whether exists.
// If os.Stat returns nil err, the target exists.
// If os.Stat returns a os.ErrNotExist err, the target does not exist.
// If the error returned is another type, the target is uncertain whether exists.
func IsPathExist(path string) (bool, error) {
func IsExist(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
Expand Down Expand Up @@ -123,17 +123,19 @@ func IsFileE(path string) (bool, error) {
return false, err
}

// IsSymlink checks a file whether is a symbolic link.
// IsSymlink checks a file whether is a symbolic link on Linux.
// Note that this doesn't work for the shortcut file on windows.
// If you want to check a file whether is a shortcut file on Windows please use IsShortcut function.
func IsSymlink(path string) bool {
if info, err := os.Lstat(path); err == nil && info.Mode()&os.ModeSymlink != 0 {
return true
}
return false
}

// IsSymlinkE checks a file whether is a symbolic link.
// IsSymlinkE checks a file whether is a symbolic link on Linux.
// Note that this doesn't work for the shortcut file on windows.
// If you want to check a file whether is a shortcut file on Windows please use IsShortcut function.
func IsSymlinkE(path string) (bool, error) {
info, err := os.Lstat(path)
if err == nil && info.Mode()&os.ModeSymlink != 0 {
Expand All @@ -142,27 +144,37 @@ func IsSymlinkE(path string) (bool, error) {
return false, err
}

// IsShortcut checks a file whether is a shortcut on Windows.
func IsShortcut(path string) bool {
ext := filepath.Ext(path)
if ext == ".lnk" {
return true
}
return false
}

// RemoveFile removes the named file or empty directory.
// https://gist.github.com/novalagung/13c5c8f4d30e0c4bff27
// If there is an error, it will be of type *PathError.
func RemoveFile(path string) error {
err := os.Remove(path)
return err
return os.Remove(path)
}

// Create creates or truncates the target file specified by path.
// If the parent directory does not exist, it will be created with mode os.ModePerm.is cr truncated.
// If the parent directory does not exist, it will be created with mode os.ModePerm.
// If the file does not exist, it is created with mode 0666.
// If successful, methods on the returned File can be used for I/O; the associated file descriptor has mode O_RDWR.
func Create(filePath string) (*os.File, error) {
if exist, err := IsPathExist(filePath); err != nil {
// If successful, methods on the returned file can be used for I/O; the associated file descriptor has mode O_RDWR.
func Create(path string) (*os.File, error) {
exist, err := IsExist(path)
if err != nil {
return nil, err
} else if exist {
return os.Create(filePath)
}
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
if exist {
return os.Create(path)
}
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
return nil, err
}
return os.Create(filePath)
return os.Create(path)
}

// CreateFile creates a file specified by path.
Expand All @@ -181,15 +193,16 @@ func FileToBytes(path string) []byte {
return byteStream
}

// BytesToFile writes data to a file. If the file does not exist it will be created with permission mode 0644.
func BytesToFile(filePath string, data []byte) error {
exist, _ := IsPathExist(filePath)
// BytesToFile writes data to a file.
// If the file does not exist it will be created with permission mode 0644.
func BytesToFile(path string, data []byte) error {
exist, _ := IsExist(path)
if !exist {
if err := CreateFile(filePath); err != nil {
if err := CreateFile(path); err != nil {
return err
}
}
return ioutil.WriteFile(filePath, data, 0644)
return ioutil.WriteFile(path, data, 0644)
}

// GetDirAllEntryPaths gets all the file or dir paths in the specified directory recursively.
Expand Down Expand Up @@ -260,3 +273,13 @@ func GetDirAllEntryPathsFollowSymlink(dirname string, incl bool) ([]string, erro
}
return paths, nil
}

// ClearFile clears a file content.
func ClearFile(path string) error {
f, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0777)
if err != nil {
return err
}
defer f.Close()
return nil
}
15 changes: 10 additions & 5 deletions zip/unzip.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"path"
"path/filepath"
"strings"
)

// Unzip decompresses a zip file to specified directory.
Expand All @@ -26,8 +27,12 @@ func Unzip(zipPath, dstDir string) error {
}

func unzipFile(file *zip.File, dstDir string) error {
// create the directory of file
filePath := path.Join(dstDir, file.Name)
// Prevent path traversal vulnerability.
// Such as if the file name is "../../../path/to/file.txt" which will be cleaned to "path/to/file.txt".
name := strings.TrimPrefix(filepath.Join(string(filepath.Separator), file.Name), string(filepath.Separator))
filePath := path.Join(dstDir, name)

// Create the directory of file.
if file.FileInfo().IsDir() {
if err := os.MkdirAll(filePath, os.ModePerm); err != nil {
return err
Expand All @@ -38,21 +43,21 @@ func unzipFile(file *zip.File, dstDir string) error {
return err
}

// open the file
// Open the file.
r, err := file.Open()
if err != nil {
return err
}
defer r.Close()

// create the file
// Create the file.
w, err := os.Create(filePath)
if err != nil {
return err
}
defer w.Close()

// save the decompressed file content
// Save the decompressed file content.
_, err = io.Copy(w, r)
return err
}
3 changes: 2 additions & 1 deletion zip/zip.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import (
// dir
// ├── bar.txt
// └── foo.txt
// Note that if a file is a symbolic link it will be skipped.
// Note that if a file is a symbolic link on Linux it will be skipped.
// If you want to follow a symbolic link please use the function ZipFollowSymlink.
func Zip(zipPath string, paths ...string) error {
// Create zip file and it's parent dir.
if err := os.MkdirAll(filepath.Dir(zipPath), os.ModePerm); err != nil {
Expand Down

0 comments on commit 0e308b0

Please sign in to comment.