package core import ( "archive/zip" "fmt" "io" "os" "os/exec" "os/user" "path/filepath" "sort" "strings" ) const ( defaultTrimSet = "\r\n\t " ) func Trim(s string) string { return strings.Trim(s, defaultTrimSet) } func TrimRight(s string) string { return strings.TrimRight(s, defaultTrimSet) } func UniqueInts(a []int, sorted bool) []int { tmp := make(map[int]bool) uniq := make([]int, 0) for _, n := range a { tmp[n] = true } for n := range tmp { uniq = append(uniq, n) } if sorted { sort.Ints(uniq) } return uniq } func SepSplit(sv string, sep string) []string { filtered := make([]string, 0) for _, part := range strings.Split(sv, sep) { part = Trim(part) if part != "" { filtered = append(filtered, part) } } return filtered } func CommaSplit(csv string) []string { return SepSplit(csv, ",") } func ExecSilent(executable string, args []string) (string, error) { path, err := exec.LookPath(executable) if err != nil { return "", err } raw, err := exec.Command(path, args...).CombinedOutput() if err != nil { return "", err } else { return Trim(string(raw)), nil } } func Exec(executable string, args []string) (string, error) { out, err := ExecSilent(executable, args) if err != nil { fmt.Printf("ERROR for '%s %s': %s\n", executable, args, err) } return out, err } func Exists(path string) bool { if _, err := os.Stat(path); os.IsNotExist(err) { return false } return true } func ExpandPath(path string) (string, error) { // Check if path is empty if path != "" { if strings.HasPrefix(path, "~") { usr, err := user.Current() if err != nil { return "", err } else { // Replace only the first occurrence of ~ path = strings.Replace(path, "~", usr.HomeDir, 1) } } return filepath.Abs(path) } return "", nil } // Unzip will decompress a zip archive, moving all files and folders // within the zip file (parameter 1) to an output directory (parameter 2). // Credits to https://golangcode.com/unzip-files-in-go/ func Unzip(src string, dest string) ([]string, error) { var filenames []string r, err := zip.OpenReader(src) if err != nil { return filenames, err } defer r.Close() for _, f := range r.File { rc, err := f.Open() if err != nil { return filenames, err } defer rc.Close() // Store filename/path for returning and using later on fpath := filepath.Join(dest, f.Name) // Check for ZipSlip. More Info: https://snyk.io/research/zip-slip-vulnerability#go if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) { return filenames, fmt.Errorf("%s: illegal file path", fpath) } filenames = append(filenames, fpath) if f.FileInfo().IsDir() { os.MkdirAll(fpath, os.ModePerm) } else if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { return filenames, err } else if outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()); err != nil { return filenames, err } else { defer outFile.Close() if _, err = io.Copy(outFile, rc); err != nil { return filenames, err } } } return filenames, nil }