github.com/mattermost/mattermost-server/v5@v5.39.3/utils/archive.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package utils
     5  
     6  import (
     7  	"archive/zip"
     8  	"fmt"
     9  	"io"
    10  	"os"
    11  	"path/filepath"
    12  	"strings"
    13  )
    14  
    15  func sanitizePath(p string) string {
    16  	dir := strings.ReplaceAll(filepath.Dir(filepath.Clean(p)), "..", "")
    17  	base := filepath.Base(p)
    18  	if strings.Count(base, ".") == len(base) {
    19  		return ""
    20  	}
    21  	return filepath.Join(dir, base)
    22  }
    23  
    24  // UnzipToPath extracts a given zip archive into a given path.
    25  // It returns a list of extracted paths.
    26  func UnzipToPath(zipFile io.ReaderAt, size int64, outPath string) ([]string, error) {
    27  	rd, err := zip.NewReader(zipFile, size)
    28  	if err != nil {
    29  		return nil, fmt.Errorf("failed to create reader: %w", err)
    30  	}
    31  
    32  	paths := make([]string, len(rd.File))
    33  	for i, f := range rd.File {
    34  		filePath := sanitizePath(f.Name)
    35  		if filePath == "" {
    36  			return nil, fmt.Errorf("invalid filepath `%s`", f.Name)
    37  		}
    38  		path := filepath.Join(outPath, filePath)
    39  		paths[i] = path
    40  		if f.FileInfo().IsDir() {
    41  			if err := os.Mkdir(path, 0700); err != nil {
    42  				return nil, fmt.Errorf("failed to create directory: %w", err)
    43  			}
    44  			continue
    45  		}
    46  		if _, err := os.Stat(filepath.Dir(path)); os.IsNotExist(err) {
    47  			if err = os.MkdirAll(filepath.Dir(path), 0700); err != nil {
    48  				return nil, fmt.Errorf("failed to create directory: %w", err)
    49  			}
    50  		}
    51  		outFile, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0600)
    52  		if err != nil {
    53  			return nil, fmt.Errorf("failed to create file: %w", err)
    54  		}
    55  		defer outFile.Close()
    56  
    57  		file, err := f.Open()
    58  		if err != nil {
    59  			return nil, fmt.Errorf("failed to open file: %w", err)
    60  		}
    61  		defer file.Close()
    62  
    63  		if _, err := io.Copy(outFile, file); err != nil {
    64  			return nil, fmt.Errorf("failed to write to file: %w", err)
    65  		}
    66  	}
    67  
    68  	return paths, nil
    69  }