chore: more cleanup and refactoring

This commit is contained in:
blacktop
2022-03-05 17:44:54 -07:00
parent 204abd0855
commit 9d7d39fcb1
12 changed files with 374 additions and 196 deletions
+2 -2
View File
@@ -104,7 +104,7 @@ var deviceTreeCmd = &cobra.Command{
if err != nil {
return errors.Wrap(err, "failed to parse device-tree")
}
utils.Indent(log.Info, 2)(fmt.Sprintf("Model: %s", s.Model))
utils.Indent(log.Info, 2)(fmt.Sprintf("Model: %s", s.ProductType))
utils.Indent(log.Info, 2)(fmt.Sprintf("Board Config: %s", s.BoardConfig))
utils.Indent(log.Info, 2)(fmt.Sprintf("Product Name: %s", s.ProductName))
}
@@ -143,7 +143,7 @@ var deviceTreeCmd = &cobra.Command{
if err != nil {
return errors.Wrap(err, "failed to parse device-tree")
}
utils.Indent(log.Info, 2)(fmt.Sprintf("Model: %s", s.Model))
utils.Indent(log.Info, 2)(fmt.Sprintf("Model: %s", s.ProductType))
utils.Indent(log.Info, 2)(fmt.Sprintf("Board Config: %s", s.BoardConfig))
utils.Indent(log.Info, 2)(fmt.Sprintf("Product Name: %s", s.ProductName))
}
+1 -3
View File
@@ -122,7 +122,6 @@ var otaDLCmd = &cobra.Command{
otaInfo := viper.GetBool("download.ota.info")
otaInfoType := viper.GetString("download.ota.info-type")
output := viper.GetString("download.ota.output")
// verify args
if len(dyldArches) > 0 && !remoteDyld {
return errors.New("--dyld-arch || -a can only be used with --dyld || -d")
@@ -361,8 +360,7 @@ var otaDLCmd = &cobra.Command{
// download file
downloader.URL = url
downloader.DestName = destName
err = downloader.Do()
if err != nil {
if err := downloader.Do(); err != nil {
return fmt.Errorf("failed to download file: %v", err)
}
} else {
+11 -10
View File
@@ -26,13 +26,13 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"text/tabwriter"
"github.com/apex/log"
"github.com/blacktop/ipsw/internal/download"
"github.com/blacktop/ipsw/pkg/info"
"github.com/dustin/go-humanize"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -57,7 +57,7 @@ var infoCmd = &cobra.Command{
SilenceErrors: true,
RunE: func(cmd *cobra.Command, args []string) error {
var pIPSW *info.Info
var i *info.Info
if Verbose {
log.SetLevel(log.DebugLevel)
@@ -76,7 +76,7 @@ var infoCmd = &cobra.Command{
Insecure: insecure,
})
if err != nil {
return errors.Wrap(err, "failed to create new remote zip reader")
return fmt.Errorf("failed to create new remote zip reader: %w", err)
}
if listFiles {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
@@ -87,9 +87,9 @@ var infoCmd = &cobra.Command{
}
w.Flush()
} else {
pIPSW, err = info.ParseZipFiles(zr.File)
i, err = info.ParseZipFiles(zr.File)
if err != nil {
return errors.Wrap(err, "failed to extract remote plists")
return fmt.Errorf("failed to parse plists in zip: %w", err)
}
}
} else {
@@ -113,17 +113,18 @@ var infoCmd = &cobra.Command{
w.Flush()
} else {
var err error
pIPSW, err = info.Parse(fPath)
i, err = info.Parse(fPath)
if err != nil {
return errors.Wrap(err, "failed to extract and parse IPSW info")
return fmt.Errorf("failed to parse plists: %w", err)
}
}
}
if !listFiles {
fmt.Println("\n[IPSW Info]")
fmt.Println("===========")
fmt.Println(pIPSW)
title := fmt.Sprintf("[%s Info]", i.Plists.Type)
fmt.Printf("\n%s\n", title)
fmt.Println(strings.Repeat("=", len(title)))
fmt.Println(i)
}
return nil
+40 -36
View File
@@ -25,12 +25,16 @@ import (
"bufio"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"regexp"
"strings"
"github.com/apex/log"
"github.com/blacktop/ipsw/internal/download"
"github.com/blacktop/ipsw/pkg/info"
"github.com/blacktop/ipsw/pkg/ota/types"
"github.com/spf13/cobra"
)
@@ -95,7 +99,7 @@ var updateDBCmd = &cobra.Command{
zr, err := download.NewRemoteZipReader(url, &download.RemoteConfig{})
if err != nil {
// log.WithError(err).Fatal("failed to create remote zip reader")
log.Error("failed to create remote zip reader")
continue
}
i, err := info.ParseZipFiles(zr.File)
@@ -115,42 +119,41 @@ var updateDBCmd = &cobra.Command{
if err != nil {
log.WithError(err).Fatal("failed to parse remote zip")
}
if err := i.GetDevices(&devices); err != nil {
log.WithError(err).Fatal("failed to get devices")
if i.Plists.Type == "OTA" {
foundMap := false
for _, f := range zr.File {
if regexp.MustCompile(`.*plist$`).MatchString(f.Name) {
switch {
case strings.HasSuffix(f.Name, "AssetData/boot/Firmware/device_map.plist"):
foundMap = true
dat := make([]byte, f.UncompressedSize64)
rc, err := f.Open()
if err != nil {
log.WithError(err).Fatal("failed to open file within zip")
}
defer rc.Close()
io.ReadFull(rc, dat)
dmap, err := types.ParseDeviceMap(dat)
if err != nil {
log.WithError(err).Fatal("failed to parse device map")
}
if err := i.GetDevicesFromMap(dmap, &devices); err != nil {
log.WithError(err).Fatal("failed to get devices")
}
}
}
}
if !foundMap {
if err := i.GetDevices(&devices); err != nil {
log.WithError(err).Fatal("failed to get devices")
}
}
} else {
if err := i.GetDevices(&devices); err != nil {
log.WithError(err).Fatal("failed to get devices")
}
}
} else {
// for _, version := range []string{"9.0", "10.0", "11.0", "12.0", "13.0", "14.0", "15.0"} {
// for _, version := range []string{"10.0", "11.0", "12.0", "13.0", "14.0", "15.0"} {
// ipsws, err := download.GetAllIPSW(version)
// if err != nil {
// log.WithError(err).Fatal("failed to get IPSWs")
// }
// unique := make(map[string]bool, len(ipsws))
// uniqueIPSWs := make([]download.IPSW, len(unique))
// for _, i := range ipsws {
// if len(i.URL) != 0 {
// if !unique[i.URL] {
// uniqueIPSWs = append(uniqueIPSWs, i)
// unique[i.URL] = true
// }
// }
// }
// for _, ipsw := range uniqueIPSWs {
// zr, err := download.NewRemoteZipReader(ipsw.URL, &download.RemoteConfig{})
// if err != nil {
// log.WithError(err).Fatal("failed to create remote zip reader")
// }
// i, err := info.ParseZipFiles(zr.File)
// if err != nil {
// // log.WithError(err).Fatal("failed to parse remote ipsw")
// continue
// }
// if err := i.GetDevices(&devices); err != nil {
// log.WithError(err).Fatal("failed to get devices")
// }
// }
// }
} else { // TODO: add default "latest" URL streams here to collect new devices
itunes, err := download.NewMacOsXML()
if err != nil {
log.WithError(err).Fatal("failed to create itunes API")
@@ -170,6 +173,7 @@ var updateDBCmd = &cobra.Command{
}
}
}
// OUTPUT JSON
dat, err := json.Marshal(devices)
if err != nil {
+36 -29
View File
@@ -5,6 +5,7 @@ import (
"bytes"
"encoding/base64"
"encoding/binary"
"time"
"fmt"
"io"
@@ -16,7 +17,6 @@ import (
"github.com/apex/log"
"github.com/blacktop/ipsw/internal/utils"
"github.com/pkg/errors"
)
// Img4 DeviceTree object
@@ -47,9 +47,11 @@ type DeviceTree map[string]Properties
// Summary object
type Summary struct {
ProductName string
BoardConfig string
Model string
ProductName string
ProductDescription string
ProductType string
BoardConfig string
Timestamp time.Time
}
// Summary prints out a summary of the DeviceTree
@@ -67,11 +69,14 @@ func (dtree *DeviceTree) Summary() (*Summary, error) {
if product, ok := (c)["product"]["product-name"].(string); ok {
summary.ProductName = product
}
if productDesc, ok := (c)["product"]["product-description"].(string); ok {
summary.ProductDescription = productDesc
}
}
}
if model, ok := (*dtree)["device-tree"]["model"].(string); ok {
summary.Model = model
summary.ProductType = model
compatible := (*dtree)["device-tree"]["compatible"]
switch reflect.TypeOf(compatible).Kind() {
case reflect.Slice:
@@ -87,6 +92,24 @@ func (dtree *DeviceTree) Summary() (*Summary, error) {
return nil, fmt.Errorf("devicetree model is not a string")
}
if stamp, ok := (*dtree)["device-tree"]["time-stamp"].(string); ok {
location, err := time.LoadLocation("PST8PDT")
if err != nil {
return nil, fmt.Errorf("failed to load location PST8PDT: %v", err)
}
layout := "Mon Jan 2 15:04:05 MST 2006"
t, err := time.ParseInLocation(layout, stamp, location)
if err != nil {
return nil, err
}
zone, _ := time.Now().Zone()
location, err = time.LoadLocation(zone)
if err != nil {
return nil, fmt.Errorf("failed to load location %s: %v", zone, err)
}
summary.Timestamp = t.In(location)
}
return summary, nil
}
@@ -135,17 +158,6 @@ func (dtree *DeviceTree) GetModel() (string, error) {
return "", fmt.Errorf("failed to get model")
}
func findDeviceTreesInList(list []string) []string {
var validDT = regexp.MustCompile(`.*DeviceTree.*im4p$`)
dTrees := []string{}
for _, v := range list {
if validDT.MatchString(v) {
dTrees = append(dTrees, v)
}
}
return dTrees
}
func parseValue(value []byte) interface{} {
// remove trailing NULLs
value = bytes.TrimRight(value[:], "\x00")
@@ -280,7 +292,7 @@ func Parse(ipswPath string) (map[string]*DeviceTree, error) {
zr, err := zip.OpenReader(ipswPath)
if err != nil {
return nil, errors.Wrap(err, "failed to open ipsw as zip")
return nil, fmt.Errorf("failed to open zip: %s", err)
}
defer zr.Close()
@@ -293,7 +305,7 @@ func Parse(ipswPath string) (map[string]*DeviceTree, error) {
dt[filepath.Base(f.Name)], err = ParseImg4Data(dtData)
if err != nil {
return nil, errors.Wrap(err, "failed to parse DeviceTree")
return nil, fmt.Errorf("failed to parse Img4 DeviceTree: %v", err)
}
} else if regexp.MustCompile(`.*DeviceTree.*img3$`).MatchString(f.Name) {
dtData := make([]byte, f.UncompressedSize64)
@@ -303,7 +315,7 @@ func Parse(ipswPath string) (map[string]*DeviceTree, error) {
dt[filepath.Base(f.Name)], err = ParseImg3Data(dtData)
if err != nil {
return nil, errors.Wrap(err, "failed to parse DeviceTree")
return nil, fmt.Errorf("failed to parse Img3 DeviceTree: %w", err)
}
}
}
@@ -327,7 +339,7 @@ func ParseZipFiles(files []*zip.File) (map[string]*DeviceTree, error) {
dt[filepath.Base(f.Name)], err = ParseImg4Data(dtData)
if err != nil {
return nil, errors.Wrap(err, "failed to parse DeviceTree")
return nil, fmt.Errorf("failed to parse Img4 DeviceTree: %v", err)
}
} else if regexp.MustCompile(`.*DeviceTree.*img3$`).MatchString(f.Name) {
dtData := make([]byte, f.UncompressedSize64)
@@ -337,7 +349,7 @@ func ParseZipFiles(files []*zip.File) (map[string]*DeviceTree, error) {
dt[filepath.Base(f.Name)], err = ParseImg3Data(dtData)
if err != nil {
return nil, fmt.Errorf("failed to parse DeviceTree: %w", err)
return nil, fmt.Errorf("failed to parse Img3 DeviceTree: %w", err)
}
}
}
@@ -348,19 +360,14 @@ func ParseZipFiles(files []*zip.File) (map[string]*DeviceTree, error) {
// Extract extracts DeviceTree(s) from ipsw
func Extract(ipsw, destPath string) error {
_, err := utils.Unzip(ipsw, destPath, func(f *zip.File) bool {
var validDT = regexp.MustCompile(`.*DeviceTree.*im4p$`)
if validDT.MatchString(f.Name) {
if regexp.MustCompile(`.*DeviceTree.*im4p$`).MatchString(f.Name) {
return true
}
validDT = regexp.MustCompile(`.*DeviceTree.*img3$`)
if validDT.MatchString(f.Name) {
return true
}
return false
return regexp.MustCompile(`.*DeviceTree.*img3$`).MatchString(f.Name)
})
if err != nil {
return errors.Wrap(err, "failed to extract DeviceTree from ipsw")
return fmt.Errorf("failed to extract DeviceTree: %w", err)
}
return nil
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+153 -101
View File
@@ -1,147 +1,199 @@
package info
import (
"fmt"
"strconv"
"strings"
"github.com/blacktop/ipsw/internal/utils"
"github.com/apex/log"
"github.com/blacktop/ipsw/pkg/ota/types"
"github.com/blacktop/ipsw/pkg/xcode"
)
type Board struct {
CPU string `json:"cpu,omitempty"`
Platform string `json:"platform,omitempty"`
CpuID int `json:"cpu_id,omitempty"`
Arch string `json:"arch,omitempty"`
CpuISA string `json:"cpu_isa,omitempty"`
BoardConfig string `json:"board_config,omitempty"`
BoardID int `json:"board_id,omitempty"`
CPU string `json:"cpu,omitempty"`
Platform string `json:"platform,omitempty"`
PlatformName string `json:"platform_name,omitempty"`
ChipID string `json:"cpuid,omitempty"`
Arch string `json:"arch,omitempty"`
CpuISA string `json:"cpuisa,omitempty"`
BoardID string `json:"board_id,omitempty"`
BasebandChipID string `json:"bbid,omitempty"`
KernelCacheType string `json:"kc_type,omitempty"`
ResearchSupported bool `json:"research_support,omitempty"`
}
type Device struct {
Name string `json:"name,omitempty"`
Boards []Board `json:"boards,omitempty"`
MemClass int `json:"mem_class,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"desc,omitempty"`
Boards map[string]Board `json:"boards,omitempty"`
MemClass string `json:"mem_class,omitempty"`
SDKPlatform string `json:"sdk,omitempty"`
}
type Devices map[string]Device
func (i *Info) GetDevices(devs *Devices) error {
var xdev xcode.Device
if i.DeviceTrees != nil && len(i.DeviceTrees) > 0 {
for _, dtree := range i.DeviceTrees {
dt, _ := dtree.Summary()
prodName := dt.ProductName
dt, err := dtree.Summary()
if err != nil {
return fmt.Errorf("error getting device tree summary: %v", err)
}
if devices, err := xcode.GetDevices(); err == nil {
for _, device := range devices {
if device.ProductType == dt.Model {
xdev = device
if len(prodName) == 0 {
prodName = xdev.ProductDescription
var kctype string
if kcs := i.Plists.BuildManifest.GetKernelForModel(strings.ToLower(dt.BoardConfig)); kcs != nil {
if len(kcs) == 1 {
kctype = kcs[0][strings.LastIndex(kcs[0], ".")+1:]
} else {
kctype = kcs[0][strings.LastIndex(kcs[0], ".")+1:] // FIXME: what?
}
}
xdev, err := xcode.GetDeviceForProd(dt.ProductType)
if err != nil {
return fmt.Errorf("error getting device %s in xcode device list: %v", dt.ProductType, err)
}
if len(dt.ProductType) > 0 {
if _, ok := (*devs)[dt.ProductType]; !ok {
if dt.ProductName != dt.ProductDescription {
(*devs)[dt.ProductType] = Device{
Name: dt.ProductName,
Description: dt.ProductDescription,
Boards: make(map[string]Board),
MemClass: strconv.Itoa(xdev.DeviceTrait.DevicePerformanceMemoryClass),
}
} else {
(*devs)[dt.ProductType] = Device{
Name: dt.ProductName,
Boards: make(map[string]Board),
MemClass: strconv.Itoa(xdev.DeviceTrait.DevicePerformanceMemoryClass),
}
break
}
}
}
if i.Plists.Restore != nil { // IPSW
var boards []Board
for _, board := range i.Plists.Restore.DeviceMap {
if board.BoardConfig == strings.ToLower(dt.BoardConfig) {
proc := getProcessor(board.Platform)
boards = append(boards, Board{
CPU: proc.Name,
Platform: board.Platform,
CpuID: board.CPID,
CpuISA: proc.CPUISA,
Arch: xdev.DeviceTrait.PreferredArchitecture,
BoardConfig: dt.BoardConfig,
BoardID: board.BDID,
})
}
}
if _, ok := (*devs)[dt.Model]; !ok {
(*devs)[dt.Model] = Device{
Name: prodName,
Boards: boards,
MemClass: xdev.DeviceTrait.DevicePerformanceMemoryClass,
}
}
} else { // OTA
for _, board := range i.Plists.BuildIdentities {
if board.Info.DeviceClass == strings.ToLower(dt.BoardConfig) {
if _, ok := (*devs)[dt.Model]; !ok {
chipID, err := utils.ConvertStrToInt(board.ApChipID)
if err != nil {
chipID = 0
}
boardID, err := utils.ConvertStrToInt(board.ApBoardID)
if err != nil {
boardID = 0
}
proc := getProcessor(xdev.Platform)
(*devs)[dt.Model] = Device{
Name: prodName,
Boards: []Board{
{
CPU: proc.Name,
Platform: xdev.Platform,
CpuID: int(chipID),
CpuISA: proc.CPUISA,
Arch: xdev.DeviceTrait.PreferredArchitecture,
BoardConfig: dt.BoardConfig,
BoardID: int(boardID),
},
},
MemClass: xdev.DeviceTrait.DevicePerformanceMemoryClass,
}
}
}
}
proc := getProcessor(xdev.Platform)
if len(proc.Name) == 0 {
log.Errorf("no processor for %s for board %s: %s", dt.ProductType, dt.BoardConfig, dt.ProductName)
}
(*devs)[dt.ProductType].Boards[dt.BoardConfig] = Board{
CPU: proc.Name,
Platform: xdev.Platform,
// PlatformName: d.PlatformName,
ChipID: i.Plists.BuildManifest.BuildIdentities[0].ApChipID,
CpuISA: proc.CPUISA,
Arch: xdev.DeviceTrait.PreferredArchitecture,
BoardID: i.Plists.BuildManifest.BuildIdentities[0].ApBoardID,
BasebandChipID: i.Plists.BuildManifest.BuildIdentities[0].BbChipID,
KernelCacheType: kctype,
// ResearchSupported: d.ResearchSupported,
}
}
} else {
if i.Plists.Restore != nil {
var prodType string
var prodName string
for idx, prod := range i.Plists.Restore.SupportedProductTypes {
if devices, err := xcode.GetDevices(); err == nil {
for _, device := range devices {
if device.ProductType == prod {
xdev = device
if len(prodName) == 0 {
prodName = xdev.ProductDescription
}
break
}
}
} else if len(prodName) == 0 {
var arch string
var memClass string
if len(i.Plists.Restore.SupportedProductTypes) == 1 {
prodType = i.Plists.Restore.SupportedProductTypes[0]
} else {
prodType = i.Plists.Restore.SupportedProductTypes[0]
log.Error("BAD ASSUMPTIONS: multiple product types in restore plist")
}
kcs := i.Plists.BuildManifest.GetKernelCaches()
for _, dev := range i.Plists.Restore.DeviceMap {
if xdev, err := xcode.GetDeviceForProd(prodType); err == nil {
prodName = xdev.ProductDescription
arch = xdev.DeviceTrait.PreferredArchitecture
memClass = strconv.Itoa(xdev.DeviceTrait.DevicePerformanceMemoryClass)
}
if len(prodName) == 0 {
if i.Plists.OTAInfo != nil {
prodName = "FIXME - " + i.Plists.OTAInfo.MobileAssetProperties.DeviceName
} else {
prodName = "FIXME"
}
}
if _, ok := (*devs)[prod]; !ok {
proc := getProcessor(i.Plists.Restore.DeviceMap[idx].Platform)
(*devs)[prod] = Device{
if _, ok := (*devs)[prodType]; !ok {
proc := getProcessor(dev.Platform)
if len(proc.Name) == 0 {
log.Errorf("no processor for %s for board %s: %s", dev.Platform, dev.BoardConfig, prodName)
}
(*devs)[prodType] = Device{
Name: prodName,
Boards: []Board{
{
CPU: proc.Name,
Platform: i.Plists.Restore.DeviceMap[idx].Platform,
CpuID: i.Plists.Restore.DeviceMap[idx].CPID,
CpuISA: proc.CPUISA,
Arch: xdev.DeviceTrait.PreferredArchitecture,
BoardConfig: strings.ToUpper(i.Plists.Restore.DeviceMap[idx].BoardConfig),
BoardID: i.Plists.Restore.DeviceMap[idx].BDID,
Boards: map[string]Board{
strings.ToUpper(dev.BoardConfig): {
CPU: proc.Name,
Platform: dev.Platform,
// PlatformName: d.PlatformName,
ChipID: i.Plists.BuildManifest.BuildIdentities[0].ApChipID,
CpuISA: proc.CPUISA,
Arch: arch,
BoardID: i.Plists.BuildManifest.BuildIdentities[0].ApBoardID,
BasebandChipID: i.Plists.BuildManifest.BuildIdentities[0].BbChipID,
KernelCacheType: kcs[dev.BoardConfig][0][strings.LastIndex(kcs[dev.BoardConfig][0], ".")+1:],
// ResearchSupported: d.ResearchSupported,
},
},
MemClass: xdev.DeviceTrait.DevicePerformanceMemoryClass,
MemClass: memClass,
}
}
}
} else {
panic("unsupport IPSW/OTA type w/ no devicetree?")
panic("unsupported IPSW/OTA type")
}
}
return nil
}
func mLBTypeToBoardConfig(bc string, mlbType string) string {
return mlbType + strings.ToUpper(strings.TrimPrefix(bc, strings.ToLower(mlbType)))
}
func (i *Info) GetDevicesFromMap(dmap *types.DeviceMap, devs *Devices) error {
for bc, d := range *dmap {
if len(d.ProductType) > 0 {
if _, ok := (*devs)[d.ProductType]; !ok {
if d.ProductName != d.ProductDescription {
(*devs)[d.ProductType] = Device{
Name: d.ProductName,
Description: d.ProductDescription,
Boards: make(map[string]Board),
MemClass: d.DevicePerformanceMemoryClass,
SDKPlatform: d.SDKPlatform,
}
} else {
(*devs)[d.ProductType] = Device{
Name: d.ProductName,
Boards: make(map[string]Board),
MemClass: d.DevicePerformanceMemoryClass,
SDKPlatform: d.SDKPlatform,
}
}
}
proc := getProcessor(d.Platform)
if len(proc.Name) == 0 {
log.Errorf("no processor for %s for board %s: %s", d.Platform, bc, d.ProductName)
}
(*devs)[d.ProductType].Boards[mLBTypeToBoardConfig(bc, d.MLBType)] = Board{
CPU: proc.Name,
Platform: d.Platform,
PlatformName: d.PlatformName,
ChipID: d.ChipID,
CpuISA: proc.CPUISA,
Arch: d.KernelMachOArchitecture,
BoardID: d.BoardID,
BasebandChipID: d.BasebandChipID,
KernelCacheType: d.KernelCacheType,
ResearchSupported: d.ResearchSupported,
}
} else {
log.Debugf("Board %s has no product type", bc)
}
}
+10 -9
View File
@@ -144,17 +144,17 @@ func (i *Info) String() string {
devices, err := xcode.GetDevices()
if err == nil {
for _, device := range devices {
if device.ProductType == dt.Model {
if device.ProductType == dt.ProductType {
prodName = device.ProductDescription
break
}
}
} else {
prodName = dt.Model
prodName = dt.ProductType
}
}
iStr += fmt.Sprintf("\n%s\n", prodName)
iStr += fmt.Sprintf(" > %s_%s_%s\n", dt.Model, strings.ToUpper(dt.BoardConfig), i.Plists.BuildManifest.ProductBuildVersion)
iStr += fmt.Sprintf(" > %s_%s_%s\n", dt.ProductType, strings.ToUpper(dt.BoardConfig), i.Plists.BuildManifest.ProductBuildVersion)
if len(kcs[strings.ToLower(dt.BoardConfig)]) > 0 {
iStr += fmt.Sprintf(" - KernelCache: %s\n", kcs[strings.ToLower(dt.BoardConfig)])
}
@@ -169,7 +169,7 @@ func (i *Info) String() string {
if len(bls[strings.ToLower(dt.BoardConfig)]) > 0 {
iStr += fmt.Sprintf(" - BootLoaders\n")
for _, bl := range bls[strings.ToLower(dt.BoardConfig)] {
if _, key, err := getApFirmwareKey(dt.Model, i.Plists.BuildManifest.ProductBuildVersion, filepath.Base(bl)); err != nil {
if _, key, err := getApFirmwareKey(dt.ProductType, i.Plists.BuildManifest.ProductBuildVersion, filepath.Base(bl)); err != nil {
iStr += fmt.Sprintf(" * %s\n", filepath.Base(bl))
} else {
iStr += fmt.Sprintf(" * %s 🔑 -> %s\n", filepath.Base(bl), key)
@@ -191,7 +191,7 @@ func (i *Info) GetFolder() string {
var devs []string
for _, dtree := range i.DeviceTrees {
dt, _ := dtree.Summary()
devs = append(devs, dt.Model)
devs = append(devs, dt.ProductType)
}
devs = utils.SortDevices(utils.Unique(devs))
return fmt.Sprintf("%s__%s", i.Plists.BuildManifest.ProductBuildVersion, getAbbreviatedDevList(devs))
@@ -202,7 +202,7 @@ func (i *Info) GetFolders() []string {
var folders []string
for _, dtree := range i.DeviceTrees {
dt, _ := dtree.Summary()
folders = append(folders, fmt.Sprintf("%s_%s_%s", dt.Model, strings.ToUpper(dt.BoardConfig), i.Plists.BuildManifest.ProductBuildVersion))
folders = append(folders, fmt.Sprintf("%s_%s_%s", dt.ProductType, strings.ToUpper(dt.BoardConfig), i.Plists.BuildManifest.ProductBuildVersion))
}
return folders
}
@@ -214,7 +214,7 @@ func (i *Info) GetFolderForFile(fileName string) string {
dt, _ := dtree.Summary()
for _, file := range files[strings.ToLower(dt.BoardConfig)] {
if strings.Contains(fileName, filepath.Base(file)) {
return fmt.Sprintf("%s_%s_%s", dt.Model, strings.ToUpper(dt.BoardConfig), i.Plists.BuildManifest.ProductBuildVersion)
return fmt.Sprintf("%s_%s_%s", dt.ProductType, strings.ToUpper(dt.BoardConfig), i.Plists.BuildManifest.ProductBuildVersion)
}
}
}
@@ -247,7 +247,7 @@ func (i *Info) getFolders() []folder {
for _, dtree := range i.DeviceTrees {
dt, _ := dtree.Summary()
fs = append(fs, folder{
Name: fmt.Sprintf("%s_%s_%s", dt.Model, strings.ToUpper(dt.BoardConfig), i.Plists.BuildManifest.ProductBuildVersion),
Name: fmt.Sprintf("%s_%s_%s", dt.ProductType, strings.ToUpper(dt.BoardConfig), i.Plists.BuildManifest.ProductBuildVersion),
KernelCaches: kcs[strings.ToLower(dt.BoardConfig)],
})
}
@@ -285,7 +285,7 @@ func (i *Info) GetDevicesForKernelCache(kc string) []string {
for _, dtree := range i.DeviceTrees {
dt, _ := dtree.Summary()
if strings.ToLower(bconf) == strings.ToLower(dt.BoardConfig) {
devices = append(devices, dt.Model)
devices = append(devices, dt.ProductType)
}
}
}
@@ -341,6 +341,7 @@ func Parse(ipswPath string) (*Info, error) {
// ParseZipFiles parses plist files and devicetree in a remote zip file
func ParseZipFiles(files []*zip.File) (*Info, error) {
var err error
i := &Info{}
i.Plists, err = plist.ParseZipFiles(files)
+77
View File
@@ -17,6 +17,20 @@ type BuildManifest struct {
SupportedProductTypes []string `plist:"SupportedProductTypes,omitempty"`
}
func (b *BuildManifest) String() string {
var out string
out += "BuildManifest:\n"
out += fmt.Sprintf(" ManifestVersion: %d\n", b.ManifestVersion)
out += fmt.Sprintf(" ProductBuildVersion: %s\n", b.ProductBuildVersion)
out += fmt.Sprintf(" ProductVersion: %s\n", b.ProductVersion)
out += fmt.Sprintf(" SupportedProductTypes: %v\n", b.SupportedProductTypes)
out += " BuildIdentities:\n"
for _, bID := range b.BuildIdentities {
out += fmt.Sprintf(" -\n%s", bID.String())
}
return out
}
type buildIdentity struct {
ApBoardID string
ApChipID string
@@ -42,6 +56,23 @@ type buildIdentity struct {
EUICCChipID int `plist:"eUICC,ChipID,omitempty"`
}
func (i buildIdentity) String() string {
var out string
out += fmt.Sprintf(" ProductMarketingVersion: %s\n", i.ProductMarketingVersion)
out += fmt.Sprintf(" ApBoardID: %s\n", i.ApBoardID)
out += fmt.Sprintf(" ApChipID: %s\n", i.ApChipID)
out += fmt.Sprintf(" ApSecurityDomain: %s\n", i.ApSecurityDomain)
out += fmt.Sprintf(" BbChipID: %s\n", i.BbChipID)
out += fmt.Sprintf(" Info:\n%s", i.Info.String())
out += fmt.Sprintf(" Manifest:\n")
for k, v := range i.Manifest {
if len(v.Info.Path) > 0 {
out += fmt.Sprintf(" %s: %s\n", k, v.String())
}
}
return out
}
type buildIdentityInfo struct {
BuildNumber string
CodeName string `plist:"BuildTrain,omitempty"`
@@ -56,6 +87,27 @@ type buildIdentityInfo struct {
VariantContents map[string]string
}
func (i buildIdentityInfo) String() string {
return fmt.Sprintf(
" BuildNumber: %s\n"+
" CodeName: %s\n"+
" DeviceClass: %s\n"+
" FDRSupport: %t\n"+
" MinimumSystemPartition: %d\n"+
" MobileDeviceMinVersion: %s\n"+
" RestoreBehavior: %s\n"+
" Variant: %s\n",
i.BuildNumber,
i.CodeName,
i.DeviceClass,
i.FDRSupport,
i.MinimumSystemPartition,
i.MobileDeviceMinVersion,
i.RestoreBehavior,
i.Variant,
)
}
type buildIdentityManifest struct {
Digest []byte
BuildString string `plist:"BuildString,omitempty"`
@@ -63,6 +115,14 @@ type buildIdentityManifest struct {
Trusted bool
}
func (m buildIdentityManifest) String() string {
var bs string
if len(m.BuildString) > 0 {
bs = fmt.Sprintf(" (%s)", m.BuildString)
}
return fmt.Sprintf("%s%s", m.Info.Path, bs)
}
type buildIdentityManifestInfo struct {
IsFTAB bool
IsFUDFirmware bool `plist:"IsFUDFirmware,omitempty"`
@@ -95,6 +155,18 @@ func (b *BuildManifest) GetKernelCaches() map[string][]string {
return kernelCaches
}
func (b *BuildManifest) GetKernelForModel(model string) []string {
kcs := b.GetKernelCaches()
if v, ok := kcs[model]; ok {
return v
} else if len(kcs) == 1 {
for _, v := range kcs {
return v
}
}
return nil
}
func (b *BuildManifest) GetBootLoaders() map[string][]string {
bootLoaders := make(map[string][]string, len(b.BuildIdentities))
for _, bID := range b.BuildIdentities {
@@ -118,6 +190,11 @@ func (b *BuildManifest) GetBootLoaders() map[string][]string {
bootLoaders[bID.Info.DeviceClass] = append(bootLoaders[bID.Info.DeviceClass], bID.Manifest["LLB"].Info.Path)
}
}
if !utils.StrSliceHas(bootLoaders[bID.Info.DeviceClass], bID.Manifest["SEP"].Info.Path) {
if len(bID.Manifest["SEP"].Info.Path) > 0 {
bootLoaders[bID.Info.DeviceClass] = append(bootLoaders[bID.Info.DeviceClass], bID.Manifest["SEP"].Info.Path)
}
}
}
return bootLoaders
}
+6 -4
View File
@@ -17,6 +17,7 @@ import (
// Plists IPSW/OTA plists object
type Plists struct {
Type string
*BuildManifest
*Restore
*AssetDataInfo
@@ -116,7 +117,7 @@ func Parse(path string) (*Plists, error) {
// ParseZipFiles parses plists in remote ipsw zip
func ParseZipFiles(files []*zip.File) (*Plists, error) {
ipsw := &Plists{}
ipsw := &Plists{Type: "IPSW"}
for _, f := range files {
if regexp.MustCompile(`.*plist$`).MatchString(f.Name) {
@@ -143,6 +144,7 @@ func ParseZipFiles(files []*zip.File) (*Plists, error) {
return nil, err
}
case strings.HasSuffix(f.Name, "AssetData/Info.plist"):
ipsw.Type = "OTA"
dat, err := readZipFile(f)
if err != nil {
return nil, fmt.Errorf("failed to read plist file: %s", err)
@@ -152,6 +154,7 @@ func ParseZipFiles(files []*zip.File) (*Plists, error) {
return nil, err
}
case strings.EqualFold(f.Name, "Info.plist"):
ipsw.Type = "OTA"
dat, err := readZipFile(f)
if err != nil {
return nil, fmt.Errorf("failed to read plist file: %s", err)
@@ -168,11 +171,10 @@ func ParseZipFiles(files []*zip.File) (*Plists, error) {
}
func (p *Plists) GetOSType() string {
if len(p.BuildManifest.BuildIdentities[0].Info.VariantContents["OS"]) > 0 {
return p.BuildManifest.BuildIdentities[0].Info.VariantContents["OS"]
}
if p.OTAInfo != nil {
return p.OTAInfo.MobileAssetProperties.ReleaseType
} else if len(p.BuildManifest.BuildIdentities[0].Info.VariantContents["OS"]) > 0 {
return p.BuildManifest.BuildIdentities[0].Info.VariantContents["OS"]
}
return ""
}
+36
View File
@@ -84,3 +84,39 @@ func GetDevices() ([]Device, error) {
return devices, nil
}
// GetDeviceForProd returns the device matching a given product type
func GetDeviceForProd(prod string) (*Device, error) {
var devices []Device
err := json.Unmarshal(traitsData, &devices)
if err != nil {
return nil, err
}
for _, device := range devices {
if device.ProductType == prod {
return &device, nil
}
}
return nil, fmt.Errorf("device not found")
}
// GetDeviceForModel returns the device matching a given model
func GetDeviceForModel(model string) (*Device, error) {
var devices []Device
err := json.Unmarshal(traitsData, &devices)
if err != nil {
return nil, err
}
for _, device := range devices {
if device.Target == model {
return &device, nil
}
}
return nil, fmt.Errorf("device not found")
}