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 }