diff --git a/cmd/ipsw/cmd/download/download_ota.go b/cmd/ipsw/cmd/download/download_ota.go index d159114bd..6e300c64b 100644 --- a/cmd/ipsw/cmd/download/download_ota.go +++ b/cmd/ipsw/cmd/download/download_ota.go @@ -245,7 +245,7 @@ var otaDLCmd = &cobra.Command{ DeviceBlackList: doNotDownload, Proxy: proxy, Insecure: insecure, - TimeoutSeconds: 90, + Timeout: 90, }) if err != nil { return fmt.Errorf("failed to parse remote OTA XML: %v", err) diff --git a/hack/make/json_mini b/hack/make/json_mini index a3a97489c..6a6d0517e 100755 --- a/hack/make/json_mini +++ b/hack/make/json_mini @@ -1,7 +1,7 @@ #!/bin/sh set -e -files=($(find -E ./pkg -type f -name '*.json')) +files=($(find -f ./pkg -f ./internal/download -- -type f -name '*.json')) for item in ${files[*]}; do printf "Minimizing JSON: %s\n" $item diff --git a/internal/download/data/audiences.gz b/internal/download/data/audiences.gz new file mode 100644 index 000000000..af1a62a08 Binary files /dev/null and b/internal/download/data/audiences.gz differ diff --git a/internal/download/data/audiences.json b/internal/download/data/audiences.json new file mode 100644 index 000000000..7d17b3098 --- /dev/null +++ b/internal/download/data/audiences.json @@ -0,0 +1 @@ +{"ios":{"release":"01c1d682-6e8f-4908-b724-5501fe3f5e5c","internal":"ce9c2203-903b-4fb3-9f03-040dc2202694","generic":"0c88076f-c292-4dad-95e7-304db9d29d34","security":"c724cb61-e974-42d3-a911-ffd4dce11eda","versions":{"11":{"developer-beta":"b7580fda-59d3-43ae-9488-a81b825e3c73","appleseed-beta":"f23050eb-bdfa-4b23-9eca-453e3b1a247c","public-beta":"5839f7cf-9610-483a-980f-6c4266a22f17"},"12":{"developer-beta":"ef473147-b8e7-4004-988e-0ae20e2532ef","public-beta":"94bf0742-38e6-4379-adf9-ec9995dde586"},"13":{"developer-beta":"d8ab8a45-ee39-4229-891e-9d3ca78a87ca","public-beta":"98bcaac1-66ed-4691-80e4-739f8ed5bb19"},"14":{"developer-beta":"dbbb0481-d521-4cdf-a2a4-5358affc224b","appleseed-beta":"84da8706-e267-4554-8207-865ae0c3a120","public-beta":"1506c359-28af-4ee1-a043-42df9d496d38"},"15":{"developer-beta":"ce48f60c-f590-4157-a96f-41179ca08278","appleseed-beta":"a98cc469-7f15-4e60-aca5-11a26d60f1e7","public-beta":"9e12a7a5-36ac-4583-b4fb-484736c739a8"},"16":{"developer-beta":"a6050bca-50d8-4e45-adc2-f7333396a42c","appleseed-beta":"817ce601-f365-4294-8982-b00f547bbe4a","public-beta":"7466521f-cc37-4267-8f46-78033fa700c2"}}},"tvos":{"release":"356d9da0-eee4-4c6c-bbe5-99b60eadddf0","generic":"fe6f26f9-ec98-46d2-8faf-565375a83ba7","versions":{"11":{"developer-beta":"ebd90ea1-6216-4a7c-920e-666faccb2d50"},"12":{"developer-beta":"5b220c65-fe50-460b-bac5-b6774b2ff475"},"13":{"developer-beta":"975af5cb-019b-42db-9543-20327280f1b2","appleseed-beta":"B79E95A7-1E51-4A6D-94F8-2BC2F9DBB000"},"14":{"developer-beta":"65254ac3-f331-4c19-8559-cbe22f5bc1a6","appleseed-beta":"a46c2f97-0afb-4a36-bcf6-8c0d74ec21be"},"15":{"developer-beta":"4d0dcdf7-12f2-4ebf-9672-ac4a4459a8bc","appleseed-beta":"3565d2d0-06b5-450d-9c01-7086cdd13f97"},"16":{"developer-beta":"d6bac98b-9e2a-4f87-9aba-22c898b25d84","appleseed-beta":"305f5233-93ed-45a4-9c91-985789b6506b"}}},"watchos":{"release":"b82fcf9c-c284-41c9-8eb2-e69bf5a5269f","generic":"fe4c7f1c-f44c-4c00-b3df-eef225a1ac9d","versions":{"4":{"developer-beta":"f659e06d-86a2-4bab-bcbb-61b7c60969ce"},"5":{"developer-beta":"e841259b-ad2e-4046-b80f-ca96bc2e17f3"},"6":{"developer-beta":"d08cfd47-4a4a-4825-91b5-3353dfff194f"},"7":{"developer-beta":"ff6df985-3cbe-4d54-ba5f-50d02428d2a3","public-beta":"6ac47c79-d0c4-42dc-b499-baa45e363c40"},"8":{"developer-beta":"b407c130-d8af-42fc-ad7a-171efea5a3d0","public-beta":"f755ea49-3d47-4829-9cdf-87aa76456282"},"9":{"developer-beta":"341f2a17-0024-46cd-968d-b4444ec3699f","public-beta":"4935cf61-2a58-437a-be3f-4db423970e43"}}},"audioos":{"release":"0322d49d-d558-4ddf-bdff-c0443d0e6fac","generic":"33c017cc-b820-4b88-8917-6776d7f42b66","versions":{"14":{"appleseed-beta":"b05ddb59-b26d-4c89-9d09-5fda15e99207"},"15":{"appleseed-beta":"58ff8d56-1d77-4473-ba88-ee1690475e40"},"16":{"appleseed-beta":"59377047-7b3f-45b9-8e99-294c0daf3c85"}}},"macos":{"release":"60b55e25-a8ed-4f45-826c-c1495a4ccc65","generic":"02d8e57e-dd1c-4090-aa50-b4ed2aef0062","versions":{"11":{"developer-beta":"ca60afc6-5954-46fd-8cb9-60dde6ac39fd","appleseed-beta":"215447a0-bb03-4e18-8598-7b6b6e7d34fd","public-beta":"902eb66c-8e37-451f-b0f2-ffb3e878560b"},"12":{"developer-beta":"298e518d-b45e-4d36-94be-34a63d6777ec","appleseed-beta":"a3799e8a-246d-4dee-b418-76b4519a15a2","public-beta":"9f86c787-7c59-45a7-a79a-9c164b00f866"},"13":{"developer-beta":"683e9586-8a82-4e5f-b0e7-767541864b8b","appleseed-beta":"3c45c074-41be-4b5b-a511-8592336e6783","public-beta":"800034a9-994c-4ecc-af4d-7b3b2ee0a5a6"}}}} diff --git a/internal/download/ota.go b/internal/download/ota.go index 79be75fac..e75adc8f1 100644 --- a/internal/download/ota.go +++ b/internal/download/ota.go @@ -2,8 +2,10 @@ package download import ( "bytes" + "compress/gzip" "context" "crypto/tls" + _ "embed" "encoding/base64" "encoding/json" "fmt" @@ -11,6 +13,7 @@ import ( "math/rand" "net/http" "sort" + "strconv" "strings" "time" @@ -43,6 +46,9 @@ const ( iOS14OtaPublicURL = "https://mesu.apple.com/assets/iOS14PublicSeed/com_apple_MobileAsset_SoftwareUpdate/com_apple_MobileAsset_SoftwareUpdate.xml" ) +//go:embed data/audiences.gz +var audienceData []byte // CREDIT: Siguza + type assetType string const ( @@ -56,61 +62,6 @@ const ( accessorySoftwareUpdate assetType = "com.apple.MobileAsset.DarwinAccessoryUpdate.A2525" ) -type assetAudienceID string - -const ( // CREDIT: Siguza - iOSRelease assetAudienceID = "01c1d682-6e8f-4908-b724-5501fe3f5e5c" // iOS release - iOSUnknown assetAudienceID = "0c88076f-c292-4dad-95e7-304db9d29d34" // iOS unknown - iOSInternal assetAudienceID = "ce9c2203-903b-4fb3-9f03-040dc2202694" // iOS internal (not publicly accessible) - iOS11Beta assetAudienceID = "b7580fda-59d3-43ae-9488-a81b825e3c73" // iOS 11 beta - iOS12Beta assetAudienceID = "ef473147-b8e7-4004-988e-0ae20e2532ef" // iOS 12 beta - iOS13Beta assetAudienceID = "d8ab8a45-ee39-4229-891e-9d3ca78a87ca" // iOS 13 beta - iOS14CustomerBeta assetAudienceID = "84da8706-e267-4554-8207-865ae0c3a120" // iOS 14 customer beta - iOS14DeveloperBeta assetAudienceID = "dbbb0481-d521-4cdf-a2a4-5358affc224b" // iOS 14 public beta - iOS14SecurityUpdates assetAudienceID = "c724cb61-e974-42d3-a911-ffd4dce11eda" // iOS 14 security updates - iOS15CustomerBeta assetAudienceID = "a98cc469-7f15-4e60-aca5-11a26d60f1e7" // iOS 15 customer beta - iOS15DeveloperBeta assetAudienceID = "ce48f60c-f590-4157-a96f-41179ca08278" // iOS 15 developer beta - iOS15PublicBeta assetAudienceID = "9e12a7a5-36ac-4583-b4fb-484736c739a8" // iOS 15 public beta - iOS16CustomerBeta assetAudienceID = "817ce601-f365-4294-8982-b00f547bbe4a" // iOS 16 customer beta - iOS16DeveloperBeta assetAudienceID = "a6050bca-50d8-4e45-adc2-f7333396a42c" // iOS 16 developer beta - iOS16PublicBeta assetAudienceID = "7466521f-cc37-4267-8f46-78033fa700c2" // iOS 16 public beta - - tvOSRelease assetAudienceID = "356d9da0-eee4-4c6c-bbe5-99b60eadddf0" // tvOS release - tvOS11Beta assetAudienceID = "ebd90ea1-6216-4a7c-920e-666faccb2d50" // tvOS 11 beta (returns 404) - tvOS12Beta assetAudienceID = "5b220c65-fe50-460b-bac5-b6774b2ff475" // tvOS 12 beta - tvOS13Beta assetAudienceID = "975af5cb-019b-42db-9543-20327280f1b2" // tvOS 13 beta - tvOS14Beta assetAudienceID = "65254ac3-f331-4c19-8559-cbe22f5bc1a6" // tvOS 14 beta - tvOS15Beta assetAudienceID = "4d0dcdf7-12f2-4ebf-9672-ac4a4459a8bc" // tvOS 15 beta - tvOS16Beta assetAudienceID = "d6bac98b-9e2a-4f87-9aba-22c898b25d84" // tvOS 16 beta - - watchOSRelease assetAudienceID = "b82fcf9c-c284-41c9-8eb2-e69bf5a5269f" // watchOS release - watchOS4Beta assetAudienceID = "f659e06d-86a2-4bab-bcbb-61b7c60969ce" // watchOS 4 beta (returns 404) - watchOS5Beta assetAudienceID = "e841259b-ad2e-4046-b80f-ca96bc2e17f3" // watchOS 5 beta - watchOS6Beta assetAudienceID = "d08cfd47-4a4a-4825-91b5-3353dfff194f" // watchOS 6 beta - watchOS7Beta assetAudienceID = "ff6df985-3cbe-4d54-ba5f-50d02428d2a3" // watchOS 7 beta - watchOS8Beta assetAudienceID = "b407c130-d8af-42fc-ad7a-171efea5a3d0" // watchOS 8 beta - watchOS9Beta assetAudienceID = "341f2a17-0024-46cd-968d-b4444ec3699f" // watchOS 9 beta - - audioOSRelease assetAudienceID = "0322d49d-d558-4ddf-bdff-c0443d0e6fac" // audioOS release - audioOS14Beta assetAudienceID = "b05ddb59-b26d-4c89-9d09-5fda15e99207" // audioOS 14 beta - audioOS15Beta assetAudienceID = "58ff8d56-1d77-4473-ba88-ee1690475e40" // audioOS 15 beta - audioOS16Beta assetAudienceID = "59377047-7b3f-45b9-8e99-294c0daf3c85" // audioOS 16 beta - - macOSRelease assetAudienceID = "60b55e25-a8ed-4f45-826c-c1495a4ccc65" // macOS release - macOS11CustomerBeta assetAudienceID = "215447a0-bb03-4e18-8598-7b6b6e7d34fd" // macOS 11 customer beta - macOS11DeveloperBeta assetAudienceID = "ca60afc6-5954-46fd-8cb9-60dde6ac39fd" // macOS 11 developer beta - macOS11PublicBeta assetAudienceID = "902eb66c-8e37-451f-b0f2-ffb3e878560b" // macOS 11 public beta - macOS12CustomerBeta assetAudienceID = "a3799e8a-246d-4dee-b418-76b4519a15a2" // macOS 12 customer beta - macOS12DeveloperBeta assetAudienceID = "298e518d-b45e-4d36-94be-34a63d6777ec" // macOS 12 developer beta - macOS12PublicBeta assetAudienceID = "9f86c787-7c59-45a7-a79a-9c164b00f866" // macOS 12 public beta - macOS13CustomerBeta assetAudienceID = "3c45c074-41be-4b5b-a511-8592336e6783" // macOS 13 customer beta - macOS13DeveloperBeta assetAudienceID = "683e9586-8a82-4e5f-b0e7-767541864b8b" // macOS 13 developer beta - macOS13PublicBeta assetAudienceID = "800034a9-994c-4ecc-af4d-7b3b2ee0a5a6" // macOS 13 public beta - - displayIOSRelease assetAudienceID = macOSRelease // studio display iOS release - displayIOSBeta assetAudienceID = macOS12DeveloperBeta // studio display iOS beta -) - // Ota is an OTA object type Ota struct { ota @@ -132,25 +83,25 @@ type OtaConf struct { DeviceBlackList []string Proxy string Insecure bool - TimeoutSeconds time.Duration + Timeout time.Duration } type pallasRequest struct { - ClientVersion int `json:"ClientVersion"` - AssetType assetType `json:"AssetType"` - AssetAudience assetAudienceID `json:"AssetAudience"` - CertIssuanceDay string `json:"CertIssuanceDay"` - ProductType string `json:"ProductType"` - HWModelStr string `json:"HWModelStr"` - ProductVersion string `json:"ProductVersion"` - BuildVersion string `json:"BuildVersion"` - Build string `json:"Build,omitempty"` - RequestedProductVersion string `json:"RequestedProductVersion,omitempty"` - Supervised bool `json:"Supervised,omitempty"` - DelayRequested bool `json:"DelayRequested,omitempty"` - CompatibilityVersion int `json:"CompatibilityVersion,omitempty"` - ReleaseType string `json:"ReleaseType,omitempty"` - RestoreVersion string `json:"RestoreVersion,omitempty"` + ClientVersion int `json:"ClientVersion"` + AssetType assetType `json:"AssetType"` + AssetAudience string `json:"AssetAudience"` + CertIssuanceDay string `json:"CertIssuanceDay"` + ProductType string `json:"ProductType"` + HWModelStr string `json:"HWModelStr"` + ProductVersion string `json:"ProductVersion"` + BuildVersion string `json:"BuildVersion"` + Build string `json:"Build,omitempty"` + RequestedProductVersion string `json:"RequestedProductVersion,omitempty"` + Supervised bool `json:"Supervised,omitempty"` + DelayRequested bool `json:"DelayRequested,omitempty"` + CompatibilityVersion int `json:"CompatibilityVersion,omitempty"` + ReleaseType string `json:"ReleaseType,omitempty"` + RestoreVersion string `json:"RestoreVersion,omitempty"` } type ota struct { @@ -173,6 +124,62 @@ type transformations struct { Measurement string `json:"_Measurement"` } +// AssetAudienceIDs is a collection of OTA asset audience IDs +type AssetAudienceIDs map[string]AssetAudienceID + +func (a AssetAudienceIDs) GetVersions(platform string) []string { + var versions []string + for version := range a[platform].Versions { + versions = append(versions, version) + } + sort.Slice(versions, func(i, j int) bool { + in, _ := strconv.Atoi(versions[i]) + jn, _ := strconv.Atoi(versions[j]) + return in < jn + }) + return versions +} + +func (a AssetAudienceIDs) LatestVersion(platform string) string { + var versions []int + for version, _ := range a[platform].Versions { + i, err := strconv.Atoi(version) + if err != nil { + continue + } + versions = append(versions, i) + } + sort.Ints(versions) + return strconv.Itoa(versions[len(versions)-1]) +} + +// AssetAudienceID is an OTA asset audience ID +type AssetAudienceID struct { + Release string `json:"release"` + Generic string `json:"generic"` + Versions map[string]struct { + DeveloperBeta string `json:"developer-beta,omitempty"` + AppleSeedBeta string `json:"appleseed-beta,omitempty"` + PublicBeta string `json:"public-beta,omitempty"` + } +} + +func GetAssetAudienceIDs() (AssetAudienceIDs, error) { + var db AssetAudienceIDs + + zr, err := gzip.NewReader(bytes.NewReader(audienceData)) + if err != nil { + return nil, err + } + defer zr.Close() + + if err := json.NewDecoder(zr).Decode(&db); err != nil { + return nil, fmt.Errorf("failed unmarshaling audiences data: %w", err) + } + + return db, nil +} + // NewOTA downloads and parses the itumes plist for iOS14 release/developer beta OTAs func NewOTA(as *AssetSets, conf OtaConf) (*Ota, error) { @@ -247,118 +254,13 @@ func (o *Ota) getRequestAssetTypes() ([]assetType, error) { return nil, fmt.Errorf("unsupported platform %s", o.Config.Platform) } -func (o *Ota) getRequestAudienceIDs() ([]assetAudienceID, error) { +func (o *Ota) getRequestAudienceIDs() ([]string, error) { + assetAudienceDB, err := GetAssetAudienceIDs() + if err != nil { + return nil, err + } + switch o.Config.Platform { - case "ios": - if o.Config.Beta { - if o.Config.Version != nil { - segs := o.Config.Version.Segments() - if len(segs) == 0 { - return nil, fmt.Errorf("invalid version %s (must be in semver format; i.e. 1.1.1)", o.Config.Version) - } - switch segs[0] { // MAJOR - case 0: // empty version - return []assetAudienceID{iOS16DeveloperBeta, iOS16CustomerBeta, iOS16PublicBeta}, nil - case 11: - return []assetAudienceID{iOS11Beta}, nil - case 12: - return []assetAudienceID{iOS12Beta}, nil - case 13: - return []assetAudienceID{iOS13Beta}, nil - case 14: - return []assetAudienceID{iOS14DeveloperBeta, iOS14CustomerBeta}, nil - case 15: - return []assetAudienceID{iOS15DeveloperBeta, iOS15CustomerBeta}, nil - case 16: - return []assetAudienceID{iOS16DeveloperBeta, iOS16CustomerBeta}, nil - default: - return nil, fmt.Errorf("invalid version %s (must be 11.x, 12.x, 13.x, 14.x, 15.x or 16.x)", o.Config.Version) - } - } - } else { - return []assetAudienceID{iOSRelease, iOS14SecurityUpdates, displayIOSRelease}, nil - } - case "watchos": - if o.Config.Beta { - if o.Config.Version != nil { - segs := o.Config.Version.Segments() - if len(segs) == 0 { - return nil, fmt.Errorf("invalid version %s (must be in semver format; i.e. 1.1.1)", o.Config.Version) - } - switch segs[0] { // MAJOR - case 0: // empty version - return []assetAudienceID{watchOS9Beta}, nil - case 4: - return []assetAudienceID{watchOS4Beta}, nil - case 5: - return []assetAudienceID{watchOS5Beta}, nil - case 6: - return []assetAudienceID{watchOS6Beta}, nil - case 7: - return []assetAudienceID{watchOS7Beta}, nil - case 8: - return []assetAudienceID{watchOS8Beta}, nil - case 9: - return []assetAudienceID{watchOS9Beta}, nil - default: - return nil, fmt.Errorf("invalid version %s (must be 4.x, 5.x, 6.x, 7.x, 8.x or 9.x)", o.Config.Version) - } - } - } else { - return []assetAudienceID{watchOSRelease}, nil - } - case "tvos": - if o.Config.Beta { - if o.Config.Version != nil { - segs := o.Config.Version.Segments() - if len(segs) == 0 { - return nil, fmt.Errorf("invalid version %s (must be in semver format; i.e. 1.1.1)", o.Config.Version) - } - switch segs[0] { // MAJOR - case 0: // empty version - return []assetAudienceID{tvOS16Beta}, nil - case 11: - return []assetAudienceID{tvOS11Beta}, nil - case 12: - return []assetAudienceID{tvOS12Beta}, nil - case 13: - return []assetAudienceID{tvOS13Beta}, nil - case 14: - return []assetAudienceID{tvOS14Beta}, nil - case 15: - return []assetAudienceID{tvOS15Beta}, nil - case 16: - return []assetAudienceID{tvOS16Beta}, nil - default: - return nil, fmt.Errorf("invalid version %s (must be 11.x, 12.x, 13.x, 14.x, 15.x or 16.x)", o.Config.Version) - } - } - } else { - return []assetAudienceID{tvOSRelease}, nil - } - case "audioos": - if o.Config.Beta { - if o.Config.Version != nil { - segs := o.Config.Version.Segments() - if len(segs) == 0 { - return nil, fmt.Errorf("invalid version %s (must be in semver format; i.e. 1.1.1)", o.Config.Version) - } - switch segs[0] { // MAJOR - case 0: // empty version - return []assetAudienceID{audioOS16Beta}, nil - case 14: - return []assetAudienceID{audioOS14Beta}, nil - case 15: - return []assetAudienceID{audioOS15Beta}, nil - case 16: - return []assetAudienceID{audioOS16Beta}, nil - default: - return nil, fmt.Errorf("invalid version %s (must be 14.x, 15.x or 16.x)", o.Config.Version) - } - } - } else { - return []assetAudienceID{audioOSRelease}, nil - } case "accessory", "recovery", "macos": if o.Config.Beta { if o.Config.Version != nil { @@ -366,27 +268,66 @@ func (o *Ota) getRequestAudienceIDs() ([]assetAudienceID, error) { if len(segs) == 0 { return nil, fmt.Errorf("invalid version %s (must be in semver format; i.e. 1.1.1)", o.Config.Version) } - switch segs[0] { // MAJOR - case 0: // empty version - return []assetAudienceID{macOS13DeveloperBeta, macOS13CustomerBeta, macOS13PublicBeta, macOS12CustomerBeta}, nil - case 11: - return []assetAudienceID{macOS11DeveloperBeta, macOS11CustomerBeta, macOS11PublicBeta}, nil - case 12: - return []assetAudienceID{macOS12DeveloperBeta, macOS12CustomerBeta, macOS12PublicBeta}, nil - case 13: - return []assetAudienceID{macOS13DeveloperBeta, macOS13CustomerBeta, macOS13PublicBeta}, nil - default: - return nil, fmt.Errorf("invalid version %s (must be 11.x, 12.x or 13.x)", o.Config.Version) + if segs[0] == 0 { // empty version + latest := assetAudienceDB.LatestVersion("macos") + return []string{ + assetAudienceDB["macos"].Versions[latest].DeveloperBeta, + assetAudienceDB["macos"].Versions[latest].AppleSeedBeta, + assetAudienceDB["macos"].Versions[latest].PublicBeta, + assetAudienceDB["macos"].Generic}, nil + } + // looup major version in DB + if v, ok := assetAudienceDB["macos"].Versions[strconv.Itoa(segs[0])]; ok { + return []string{ + v.DeveloperBeta, + v.AppleSeedBeta, + v.PublicBeta}, nil + } else { + return nil, fmt.Errorf( + "invalid version %s (must be one of %s)", + o.Config.Version, + strings.Join(utils.StrSliceAddSuffix(assetAudienceDB.GetVersions("macos"), ".x"), ", ")) } } } else { - return []assetAudienceID{macOSRelease}, nil + return []string{assetAudienceDB["ios"].Release, assetAudienceDB["ios"].Generic}, nil + } + default: + if o.Config.Beta { + if o.Config.Version != nil { + segs := o.Config.Version.Segments() + if len(segs) == 0 { + return nil, fmt.Errorf("invalid version %s (must be in semver format; i.e. 1.1.1)", o.Config.Version) + } + if segs[0] == 0 { // empty version + latest := assetAudienceDB.LatestVersion(o.Config.Platform) + return []string{ + assetAudienceDB[o.Config.Platform].Versions[latest].DeveloperBeta, + assetAudienceDB[o.Config.Platform].Versions[latest].AppleSeedBeta, + assetAudienceDB[o.Config.Platform].Versions[latest].PublicBeta, + assetAudienceDB[o.Config.Platform].Generic}, nil + } + // looup major version in DB + if v, ok := assetAudienceDB[o.Config.Platform].Versions[strconv.Itoa(segs[0])]; ok { + return []string{ + v.DeveloperBeta, + v.AppleSeedBeta, + v.PublicBeta}, nil + } else { + return nil, fmt.Errorf( + "invalid version %s (must be one of %s)", + o.Config.Version, + strings.Join(utils.StrSliceAddSuffix(assetAudienceDB.GetVersions(o.Config.Platform), ".x"), ", ")) + } + } + } else { + return []string{assetAudienceDB["ios"].Release, assetAudienceDB["ios"].Generic}, nil } } return nil, fmt.Errorf("unsupported platform %s", o.Config.Platform) } -func (o *Ota) getRequests(atype assetType, audienceID assetAudienceID) (reqs []pallasRequest, err error) { +func (o *Ota) getRequests(atype assetType, audienceID string) (reqs []pallasRequest, err error) { req := pallasRequest{ ClientVersion: clientVersion, @@ -471,11 +412,13 @@ func (o *Ota) buildPallasRequests() (reqs []pallasRequest, err error) { for _, atype := range assetTypes { for _, audienceID := range audienceIDs { - rr, err := o.getRequests(atype, audienceID) - if err != nil { - return nil, fmt.Errorf("failed to get %s pallas requests: %v", o.Config.Platform, err) + if len(audienceID) > 0 { + rr, err := o.getRequests(atype, audienceID) + if err != nil { + return nil, fmt.Errorf("failed to get %s pallas requests: %v", o.Config.Platform, err) + } + reqs = append(reqs, rr...) } - reqs = append(reqs, rr...) } } @@ -496,7 +439,7 @@ func sendPostAsync(body []byte, rc chan *http.Response, config *OtaConf) error { Proxy: GetProxy(config.Proxy), TLSClientConfig: &tls.Config{InsecureSkipVerify: config.Insecure}, }, - Timeout: config.TimeoutSeconds * time.Second, + Timeout: config.Timeout * time.Second, } resp, err := client.Do(req) @@ -517,7 +460,6 @@ func (o *Ota) GetPallasOTAs() ([]types.Asset, error) { return nil, fmt.Errorf("failed to build the pallas requests: %v", err) } - rand.Seed(time.Now().UnixNano()) c := make(chan *http.Response, 1) g, _ := errgroup.WithContext(context.Background()) diff --git a/internal/utils/utils.go b/internal/utils/utils.go index d07704f3c..545bf543a 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -186,6 +186,14 @@ func Uint64SliceContains(slice []uint64, item uint64) bool { return false } +func StrSliceAddSuffix(slice []string, suffix string) []string { + var out []string + for _, s := range slice { + out = append(out, s+suffix) + } + return out +} + // Unique returns a slice with only unique elements func Unique[T comparable](s []T) []T { inResult := make(map[T]bool) diff --git a/pkg/xcode/device_traits.gz b/pkg/xcode/data/device_traits.gz similarity index 100% rename from pkg/xcode/device_traits.gz rename to pkg/xcode/data/device_traits.gz diff --git a/pkg/xcode/device_traits.json b/pkg/xcode/data/device_traits.json similarity index 100% rename from pkg/xcode/device_traits.json rename to pkg/xcode/data/device_traits.json diff --git a/pkg/xcode/xcode.go b/pkg/xcode/xcode.go index 6f016217b..99786650a 100644 --- a/pkg/xcode/xcode.go +++ b/pkg/xcode/xcode.go @@ -12,7 +12,7 @@ import ( "github.com/blacktop/ipsw/internal/utils" ) -//go:embed device_traits.gz +//go:embed data/device_traits.gz var traitsData []byte // Device object