Skip to content

Commit

Permalink
move unzip util to ios.Utils, fix image auto command for 17+ (#420)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielpaulus authored Jul 2, 2024
1 parent 970aa04 commit e04bd84
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 76 deletions.
58 changes: 47 additions & 11 deletions ios/imagemounter/imagedownloader.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ var (
const (
imageFile = "DeveloperDiskImage.dmg"
signatureFile = "DeveloperDiskImage.dmg.signature"
devicebox = "https://deviceboxhq.com/"
xcode15_4_ddi = "ddi-15F31d"
)

func MatchAvailable(version string) string {
Expand Down Expand Up @@ -118,14 +120,55 @@ func MatchAvailable(version string) string {
return bestMatchString
}

func Download17Plus(device ios.DeviceEntry, baseDir string, version *semver.Version) (string, error) {
downloadUrl := fmt.Sprintf("%s%s%s", devicebox, xcode15_4_ddi, ".zip")
log.Infof("device iOS version: %s, getting developer image: %s", version.String(), downloadUrl)

imageDownloaded, err := validateBaseDirAndLookForImage(baseDir, xcode15_4_ddi)
if err != nil {
return "", err
}
if imageDownloaded != "" {
log.Infof("using already downloaded image: %s", imageDownloaded)
return path.Join(imageDownloaded, "Restore"), err
}
imageFileName := path.Join(baseDir, xcode15_4_ddi+".zip")
extractedPath := path.Join(baseDir, xcode15_4_ddi)
log.Infof("downloading '%s' to path '%s'", downloadUrl, imageFileName)
err = downloadFile(imageFileName, downloadUrl)
if err != nil {
return "", err
}
_, _, err = ios.Unzip(imageFileName, extractedPath)
if err != nil {
return "", fmt.Errorf("Download17Plus: error extracting image %s %w", imageFileName, err)
}

return path.Join(extractedPath, "Restore"), nil
}

func DownloadImageFor(device ios.DeviceEntry, baseDir string) (string, error) {
allValues, err := ios.GetValues(device)
if err != nil {
return "", err
}
parsedVersion, err := semver.NewVersion(allValues.Value.ProductVersion)
if err != nil {
return "", fmt.Errorf("DownloadImageFor: failed parsing ios productversion: '%s' with %w", allValues.Value.ProductVersion, err)
}
if parsedVersion.GreaterThan(ios.IOS17()) || parsedVersion.Equal(ios.IOS17()) {
return Download17Plus(device, baseDir, parsedVersion)
}
version := MatchAvailable(allValues.Value.ProductVersion)
log.Infof("device iOS version: %s, getting developer image for iOS %s", allValues.Value.ProductVersion, version)
imageDownloaded, err := validateBaseDirAndLookForImage(baseDir, version)
var imageToFind string
switch runtime.GOOS {
case "windows":
imageToFind = fmt.Sprintf("%s\\%s", version, imageFile)
default:
imageToFind = fmt.Sprintf("%s/%s", version, imageFile)
}
imageDownloaded, err := validateBaseDirAndLookForImage(baseDir, imageToFind)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -160,14 +203,7 @@ func DownloadImageFor(device ios.DeviceEntry, baseDir string) (string, error) {
return imageFileName, nil
}

func findImage(dir string, version string) (string, error) {
var imageToFind string
switch runtime.GOOS {
case "windows":
imageToFind = fmt.Sprintf("%s\\%s", version, imageFile)
default:
imageToFind = fmt.Sprintf("%s/%s", version, imageFile)
}
func findImage(dir string, imageToFind string) (string, error) {
var imageWeFound string
err := filepath.Walk(dir,
func(path string, info os.FileInfo, err error) error {
Expand All @@ -188,7 +224,7 @@ func findImage(dir string, version string) (string, error) {
return "", fmt.Errorf("image not found")
}

func validateBaseDirAndLookForImage(baseDir string, version string) (string, error) {
func validateBaseDirAndLookForImage(baseDir string, imageToFind string) (string, error) {
dirHandle, err := os.Open(baseDir)
defer dirHandle.Close()
if err != nil {
Expand All @@ -199,7 +235,7 @@ func validateBaseDirAndLookForImage(baseDir string, version string) (string, err
return "", nil
}

dmgPath, err := findImage(baseDir, version)
dmgPath, err := findImage(baseDir, imageToFind)
if err != nil {
return "", nil
}
Expand Down
62 changes: 62 additions & 0 deletions ios/utils.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package ios

import (
"archive/zip"
"encoding/binary"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"strings"

Expand Down Expand Up @@ -199,3 +202,62 @@ func GenericSliceToType[T any](input []interface{}) ([]T, error) {
}
return result, nil
}

// Unzip is code I copied from https://golangcode.com/unzip-files-in-go/
// thank you guys for the cool helpful code examples :-D
func Unzip(src string, dest string) ([]string, uint64, error) {
var overallSize uint64
var filenames []string

r, err := zip.OpenReader(src)
if err != nil {
return filenames, 0, err
}
defer r.Close()

for _, f := range r.File {

// Store filename/path for returning and using later on
fpath := filepath.Join(dest, f.Name)

// Check for ZipSlip. More Info: http://bit.ly/2MsjAWE
if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) {
return filenames, 0, fmt.Errorf("%s: illegal file path", fpath)
}

filenames = append(filenames, fpath)

if f.FileInfo().IsDir() {
// Make Folder
os.MkdirAll(fpath, os.ModePerm)
continue
}

// Make File
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
return filenames, 0, err
}

outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return filenames, 0, err
}

rc, err := f.Open()
if err != nil {
return filenames, 0, err
}

_, err = io.Copy(outFile, rc)
// sizeStat, err := outFile.Stat()
overallSize += f.UncompressedSize64
// Close the file without defer to close before next iteration of loop
outFile.Close()
rc.Close()

if err != nil {
return filenames, 0, err
}
}
return filenames, overallSize, nil
}
64 changes: 0 additions & 64 deletions ios/zipconduit/zip_utils.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
package zipconduit

import (
"archive/zip"
"encoding/hex"
"fmt"
"io"
"os"
"path/filepath"
"strings"

log "github.com/sirupsen/logrus"
Expand Down Expand Up @@ -94,62 +89,3 @@ type zipHeader struct {

// standard header signature for central directory of a zip file
var centralDirectoryHeader []byte = []byte{0x50, 0x4b, 0x01, 0x02}

// Unzip is code I copied from https://golangcode.com/unzip-files-in-go/
// thank you guys for the cool helpful code examples :-D
func Unzip(src string, dest string) ([]string, uint64, error) {
var overallSize uint64
var filenames []string

r, err := zip.OpenReader(src)
if err != nil {
return filenames, 0, err
}
defer r.Close()

for _, f := range r.File {

// Store filename/path for returning and using later on
fpath := filepath.Join(dest, f.Name)

// Check for ZipSlip. More Info: http://bit.ly/2MsjAWE
if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) {
return filenames, 0, fmt.Errorf("%s: illegal file path", fpath)
}

filenames = append(filenames, fpath)

if f.FileInfo().IsDir() {
// Make Folder
os.MkdirAll(fpath, os.ModePerm)
continue
}

// Make File
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
return filenames, 0, err
}

outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return filenames, 0, err
}

rc, err := f.Open()
if err != nil {
return filenames, 0, err
}

_, err = io.Copy(outFile, rc)
// sizeStat, err := outFile.Stat()
overallSize += f.UncompressedSize64
// Close the file without defer to close before next iteration of loop
outFile.Close()
rc.Close()

if err != nil {
return filenames, 0, err
}
}
return filenames, overallSize, nil
}
2 changes: 1 addition & 1 deletion ios/zipconduit/zipconduit_installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ func (conn Connection) sendIpaFile(ipaFile string) error {
}
}()
log.Debug("unzipping..")
unzippedFiles, totalBytes, err := Unzip(ipaFile, tmpDir)
unzippedFiles, totalBytes, err := ios.Unzip(ipaFile, tmpDir)
if err != nil {
return err
}
Expand Down

0 comments on commit e04bd84

Please sign in to comment.