github.com/criteo/command-launcher@v0.0.0-20230407142452-fb616f546e98/internal/pkg/zip-package.go (about)

     1  package pkg
     2  
     3  import (
     4  	"archive/zip"
     5  	"crypto/sha256"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"path/filepath"
    10  
    11  	"github.com/criteo/command-launcher/internal/command"
    12  	"github.com/criteo/command-launcher/internal/config"
    13  	log "github.com/sirupsen/logrus"
    14  	"github.com/spf13/viper"
    15  )
    16  
    17  type zipPackage struct {
    18  	defaultPackage
    19  	ZipFile string
    20  }
    21  
    22  func CreateZipPackage(zipFilename string) (command.Package, error) {
    23  	reader, err := zip.OpenReader(zipFilename)
    24  	if err != nil {
    25  		return nil, fmt.Errorf("failed to open: %s", err)
    26  	}
    27  	defer reader.Close()
    28  	manifestFile, err := reader.Open("manifest.mf")
    29  	if err != nil {
    30  		return nil, fmt.Errorf("failed to open the manifest: %s", err)
    31  	}
    32  	defer manifestFile.Close()
    33  
    34  	mf, err := ReadManifest(manifestFile)
    35  	if err != nil {
    36  		return nil, fmt.Errorf("failed to read the manifest: %s", err)
    37  	}
    38  
    39  	var pkg = zipPackage{
    40  		defaultPackage: defaultPackage{
    41  			Manifest: mf,
    42  		},
    43  		ZipFile: zipFilename,
    44  	}
    45  
    46  	return &pkg, nil
    47  }
    48  
    49  func (pkg *zipPackage) InstallTo(targetDir string) (command.PackageManifest, error) {
    50  	zipReader, _ := zip.OpenReader(pkg.ZipFile)
    51  	defer zipReader.Close()
    52  	for _, file := range zipReader.Reader.File {
    53  		zippedFile, err := file.Open()
    54  		if err != nil {
    55  			return nil, fmt.Errorf("installation failed: %s", err)
    56  		}
    57  		defer zippedFile.Close()
    58  
    59  		extractedFilePath := filepath.Join(targetDir, file.Name)
    60  		if file.FileInfo().IsDir() {
    61  			log.Println("Directory Created:", extractedFilePath)
    62  			err := os.MkdirAll(extractedFilePath, file.Mode())
    63  			if err != nil {
    64  				return nil, fmt.Errorf("directory extraction failed: %s", err)
    65  			}
    66  		} else {
    67  			log.Println("File extracted:", file.Name)
    68  			outputFile, err := os.OpenFile(
    69  				extractedFilePath,
    70  				os.O_WRONLY|os.O_CREATE|os.O_TRUNC,
    71  				file.Mode(),
    72  			)
    73  			if err != nil {
    74  				return nil, fmt.Errorf("file extraction failed: %s", err)
    75  			}
    76  			defer outputFile.Close()
    77  
    78  			_, err = io.Copy(outputFile, zippedFile)
    79  			if err != nil {
    80  				return nil, fmt.Errorf("file data extraction failed: %s", err)
    81  			}
    82  		}
    83  	}
    84  
    85  	if viper.GetBool(config.ENABLE_PACKAGE_SETUP_HOOK_KEY) {
    86  		// for now ignore the setup error
    87  		pkg.RunSetup(targetDir)
    88  	}
    89  
    90  	return pkg.Manifest, nil
    91  }
    92  
    93  func (pkg *zipPackage) VerifyChecksum(checksum string) (bool, error) {
    94  	sha, err := packageChecksum(pkg.ZipFile)
    95  	if err != nil {
    96  		return false, fmt.Errorf("failed to calculate checksum of package %s@%s", pkg.Name(), pkg.Version())
    97  	}
    98  	remoteChecksum := fmt.Sprintf("%x", sha)
    99  	if remoteChecksum != checksum {
   100  		return false, fmt.Errorf("package %s@%s has a wrong checksum, expected %s, but get %s", pkg.Name(), pkg.Version(), checksum, remoteChecksum)
   101  	}
   102  	return true, nil
   103  }
   104  
   105  func (pkg *defaultPackage) VerifySignature(signature string) (bool, error) {
   106  	// TODO: implement the signature verification
   107  	return true, nil
   108  }
   109  
   110  func packageChecksum(pkgFile string) ([]byte, error) {
   111  	f, err := os.Open(pkgFile)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	defer f.Close()
   116  
   117  	h := sha256.New()
   118  	if _, err := io.Copy(h, f); err != nil {
   119  		return nil, err
   120  	}
   121  
   122  	return h.Sum(nil), nil
   123  }