Skip to content

Commit

Permalink
fix: improve zip extraction
Browse files Browse the repository at this point in the history
  • Loading branch information
sahinfalcon committed Dec 23, 2024
1 parent 0935416 commit a99e468
Showing 1 changed file with 46 additions and 12 deletions.
58 changes: 46 additions & 12 deletions src/internal/file_operations_extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io"
"os"
"path/filepath"
"runtime"
"strings"
"time"

Expand All @@ -15,6 +16,20 @@ import (
"golift.io/xtractr"
)

func getDefaultFileMode() os.FileMode {
if runtime.GOOS == "windows" {
return 0666
}
return 0644
}

func shouldSkipFile(name string) bool {
// Skip system files across platforms
return strings.HasPrefix(name, "__MACOSX/") ||
strings.EqualFold(name, "Thumbs.db") ||
strings.EqualFold(name, "desktop.ini")
}

func extractCompressFile(src, dest string) error {
id := shortuuid.New()

Expand Down Expand Up @@ -116,31 +131,44 @@ func unzip(src, dest string) error {

path := filepath.Join(dest, f.Name)

// Check for ZipSlip (Directory traversal)
if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
// Cross-platform path security check
if !strings.HasPrefix(filepath.Clean(path), filepath.Clean(dest)+string(os.PathSeparator)) {
return fmt.Errorf("illegal file path: %s", path)
}

fileMode := f.Mode()
if f.FileInfo().IsDir() {
os.MkdirAll(path, f.Mode())
} else {
os.MkdirAll(filepath.Dir(path), f.Mode())
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
err := os.MkdirAll(path, fileMode)
if err != nil {
return fmt.Errorf("failed to create directory: %w", err)
}
defer func() {
if err := f.Close(); err != nil {
panic(err)
}
}()
return nil
}

_, err = io.Copy(f, rc)
// Create directory structure
if err := os.MkdirAll(filepath.Dir(path), fileMode); err != nil {
return fmt.Errorf("failed to create parent directory: %w", err)
}

// Try default permissions first
outFile, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, getDefaultFileMode())
if err != nil {
// Fall back to original file permissions
outFile, err = os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fileMode)
if err != nil {
return fmt.Errorf("failed to create file: %w", err)
}
}
defer func() {
if err := outFile.Close(); err != nil {
outPutLog(fmt.Sprintf("Error closing output file %s: %v", path, err))
}
}()

if _, err := io.Copy(outFile, rc); err != nil {
return fmt.Errorf("failed to write file content: %w", err)
}

return nil
}

Expand All @@ -150,6 +178,12 @@ func unzip(src, dest string) error {
message.processNewState = p
channel <- message
}

if shouldSkipFile(f.Name) {
p.done++
continue
}

err := extractAndWriteFile(f)
if err != nil {
p.state = failure
Expand Down

0 comments on commit a99e468

Please sign in to comment.