Skip to content

Commit

Permalink
fix: add support for --offline profiles via `ipsw appstore profile …
Browse files Browse the repository at this point in the history
…create` cmd
  • Loading branch information
blacktop committed Feb 6, 2025
1 parent b31d219 commit 1817795
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 65 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ www/docs/static/releases*.json
*.unstripped
*.bndb
*.lock
*.mobileprovision
internal/commands/ida/dscu/data/dscu.py
internal/download/data/proto
venv/
Expand Down
8 changes: 7 additions & 1 deletion cmd/ipsw/cmd/appstore/appstore_profile_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ func init() {
ASProfileCreateCmd.Flags().StringP("bundle-id", "b", "", "Board ID")
ASProfileCreateCmd.Flags().StringSliceP("certs", "c", []string{}, "Certificate IDs")
ASProfileCreateCmd.Flags().StringSliceP("devices", "d", []string{}, "Device IDs")
ASProfileCreateCmd.Flags().Bool("offline", false, "Enable profile with 'Offline Support' (7 day validity)")
ASProfileCreateCmd.Flags().StringP("output", "o", "", "Folder to download profile to")
ASProfileCreateCmd.MarkFlagDirname("output")
viper.BindPFlag("appstore.profile.create.type", ASProfileCreateCmd.Flags().Lookup("type"))
viper.BindPFlag("appstore.profile.create.bundle-id", ASProfileCreateCmd.Flags().Lookup("bundle-id"))
viper.BindPFlag("appstore.profile.create.certs", ASProfileCreateCmd.Flags().Lookup("certs"))
viper.BindPFlag("appstore.profile.create.devices", ASProfileCreateCmd.Flags().Lookup("devices"))
viper.BindPFlag("appstore.profile.create.offline", ASProfileCreateCmd.Flags().Lookup("offline"))
viper.BindPFlag("appstore.profile.create.output", ASProfileCreateCmd.Flags().Lookup("output"))
}

Expand Down Expand Up @@ -80,6 +82,7 @@ var ASProfileCreateCmd = &cobra.Command{
bid := viper.GetString("appstore.profile.create.bundle-id")
certs := viper.GetStringSlice("appstore.profile.create.certs")
devices := viper.GetStringSlice("appstore.profile.create.devices")
offline := viper.GetBool("appstore.profile.create.offline")
// Validate flags
if (viper.GetString("appstore.p8") == "" || viper.GetString("appstore.iss") == "" || viper.GetString("appstore.kid") == "") && viper.GetString("appstore.jwt") == "" {
return fmt.Errorf("you must provide (--p8, --iss and --kid) OR --jwt")
Expand Down Expand Up @@ -127,6 +130,9 @@ var ASProfileCreateCmd = &cobra.Command{
if err != nil {
return err
}
if len(cs) == 0 {
return fmt.Errorf("no certificates found")
}

var choices []string
for _, c := range cs {
Expand Down Expand Up @@ -182,7 +188,7 @@ var ASProfileCreateCmd = &cobra.Command{
"devices": devices,
}).Debug("Creating profile")

resp, err := as.CreateProfile(args[0], viper.GetString("appstore.profile.create.type"), bid, certs, devices)
resp, err := as.CreateProfile(args[0], viper.GetString("appstore.profile.create.type"), bid, certs, devices, offline)
if err != nil {
return fmt.Errorf("failed to create profile: %v", err)
}
Expand Down
5 changes: 4 additions & 1 deletion cmd/ipsw/cmd/appstore/appstore_profile_renew.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ var ASProfileRenewCmd = &cobra.Command{
certs = append(certs, cert.ID)
}
pDevs, err := as.GetProfileDevices(profile.ID)
if err != nil {
return err
}
for _, dev := range pDevs {
devices = append(devices, dev.ID)
}
Expand All @@ -173,7 +176,7 @@ var ASProfileRenewCmd = &cobra.Command{
"devices": devices,
}).Debug("Creating profile")

resp, err := as.CreateProfile(profile.Attributes.Name, profile.Attributes.ProfileType, bid, certs, devices)
resp, err := as.CreateProfile(profile.Attributes.Name, string(profile.Attributes.ProfileType), bid, certs, devices, profile.Attributes.OfflineProfile)
if err != nil {
return fmt.Errorf("failed to create profile: %v", err)
}
Expand Down
71 changes: 36 additions & 35 deletions pkg/appstore/cert.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,45 +15,49 @@ import (
type certificateType string

const (
CT_IOS_DEVELOPMENT certificateType = "IOS_DEVELOPMENT"
CT_IOS_DISTRIBUTION certificateType = "IOS_DISTRIBUTION"
CT_MAC_APP_DISTRIBUTION certificateType = "MAC_APP_DISTRIBUTION"
CT_MAC_INSTALLER_DISTRIBUTION certificateType = "MAC_INSTALLER_DISTRIBUTION"
CT_MAC_APP_DEVELOPMENT certificateType = "MAC_APP_DEVELOPMENT"
CT_DEVELOPER_ID_KEXT certificateType = "DEVELOPER_ID_KEXT"
CT_DEVELOPER_ID_APPLICATION certificateType = "DEVELOPER_ID_APPLICATION"
CT_DEVELOPMENT certificateType = "DEVELOPMENT"
CT_DISTRIBUTION certificateType = "DISTRIBUTION"
CT_PASS_TYPE_ID certificateType = "PASS_TYPE_ID"
CT_PASS_TYPE_ID_WITH_NFC certificateType = "PASS_TYPE_ID_WITH_NFC"
CT_IOS_DEVELOPMENT certificateType = "IOS_DEVELOPMENT"
CT_IOS_DISTRIBUTION certificateType = "IOS_DISTRIBUTION"
CT_MAC_APP_DISTRIBUTION certificateType = "MAC_APP_DISTRIBUTION"
CT_MAC_INSTALLER_DISTRIBUTION certificateType = "MAC_INSTALLER_DISTRIBUTION"
CT_MAC_APP_DEVELOPMENT certificateType = "MAC_APP_DEVELOPMENT"
CT_DEVELOPER_ID_KEXT certificateType = "DEVELOPER_ID_KEXT"
CT_DEVELOPER_ID_KEXT_G2 certificateType = "DEVELOPER_ID_KEXT_G2"
CT_DEVELOPER_ID_APPLICATION certificateType = "DEVELOPER_ID_APPLICATION"
CT_DEVELOPER_ID_APPLICATION_G2 certificateType = "DEVELOPER_ID_APPLICATION_G2"
CT_DEVELOPMENT certificateType = "DEVELOPMENT"
CT_DISTRIBUTION certificateType = "DISTRIBUTION"
CT_PASS_TYPE_ID certificateType = "PASS_TYPE_ID"
CT_PASS_TYPE_ID_WITH_NFC certificateType = "PASS_TYPE_ID_WITH_NFC"
)

var CertTypes = []string{
"IOS_DEVELOPMENT",
"IOS_DISTRIBUTION",
"MAC_APP_DISTRIBUTION",
"MAC_INSTALLER_DISTRIBUTION",
"MAC_APP_DEVELOPMENT",
"DEVELOPER_ID_KEXT",
"DEVELOPER_ID_APPLICATION",
"DEVELOPMENT",
"DISTRIBUTION",
"PASS_TYPE_ID",
"PASS_TYPE_ID_WITH_NFC",
string(CT_IOS_DEVELOPMENT),
string(CT_IOS_DISTRIBUTION),
string(CT_MAC_APP_DISTRIBUTION),
string(CT_MAC_INSTALLER_DISTRIBUTION),
string(CT_MAC_APP_DEVELOPMENT),
string(CT_DEVELOPER_ID_KEXT),
string(CT_DEVELOPER_ID_KEXT_G2),
string(CT_DEVELOPER_ID_APPLICATION),
string(CT_DEVELOPER_ID_APPLICATION_G2),
string(CT_DEVELOPMENT),
string(CT_DISTRIBUTION),
string(CT_PASS_TYPE_ID),
string(CT_PASS_TYPE_ID_WITH_NFC),
}

type Certificate struct {
Type string `json:"type"`
ID string `json:"id"`
Type string `json:"type"`
Attributes struct {
SerialNumber string `json:"serialNumber"`
CertificateContent []byte `json:"certificateContent"`
DisplayName string `json:"displayName"`
Name string `json:"name"`
CsrContent any `json:"csrContent"`
Platform string `json:"platform"`
ExpirationDate Date `json:"expirationDate"`
CertificateType string `json:"certificateType"`
CertificateContent []byte `json:"certificateContent"`
DisplayName string `json:"displayName"`
ExpirationDate Date `json:"expirationDate"`
Name string `json:"name"`
Platform string `json:"platform"`
SerialNumber string `json:"serialNumber"`
CertificateType certificateType `json:"certificateType"`
CsrContent any `json:"csrContent"`
} `json:"attributes"`
Links Links `json:"links"`
}
Expand Down Expand Up @@ -128,10 +132,7 @@ func (as *AppStore) GetCertificates() ([]Certificate, error) {

certificateDataList := make([]Certificate, 0)
for _, v := range certsResp.Data {
if v.Type == "certificates" &&
(v.Attributes.CertificateType == "IOS_DEVELOPMENT" ||
v.Attributes.CertificateType == "MAC_APP_DEVELOPMENT" ||
v.Attributes.CertificateType == "DEVELOPMENT") {
if v.Type == "certificates" {
certificateDataList = append(certificateDataList, v)
}
}
Expand Down
60 changes: 32 additions & 28 deletions pkg/appstore/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,34 +32,35 @@ const (
)

var ProfileTypes = []string{
"IOS_APP_DEVELOPMENT",
"IOS_APP_STORE",
"IOS_APP_ADHOC",
"IOS_APP_INHOUSE",
"MAC_APP_DEVELOPMENT",
"MAC_APP_STORE",
"MAC_APP_DIRECT",
"TVOS_APP_DEVELOPMENT",
"TVOS_APP_STORE",
"TVOS_APP_ADHOC",
"TVOS_APP_INHOUSE",
"MAC_CATALYST_APP_DEVELOPMENT",
"MAC_CATALYST_APP_STORE",
"MAC_CATALYST_APP_DIRECT",
string(IOS_APP_DEVELOPMENT),
string(IOS_APP_STORE),
string(IOS_APP_ADHOC),
string(IOS_APP_INHOUSE),
string(MAC_APP_DEVELOPMENT),
string(MAC_APP_STORE),
string(MAC_APP_DIRECT),
string(TVOS_APP_DEVELOPMENT),
string(TVOS_APP_STORE),
string(TVOS_APP_ADHOC),
string(TVOS_APP_INHOUSE),
string(MAC_CATALYST_APP_DEVELOPMENT),
string(MAC_CATALYST_APP_STORE),
string(MAC_CATALYST_APP_DIRECT),
}

type Profile struct {
ID string `json:"id"`
Type ProfileType `json:"type"` // profiles
Attributes struct {
ProfileState string `json:"profileState"`
CreatedDate Date `json:"createdDate"`
ProfileType string `json:"profileType"`
Name string `json:"name"`
ProfileContent []byte `json:"profileContent"`
UUID string `json:"uuid"`
Platform string `json:"platform"`
ExpirationDate Date `json:"expirationDate"`
Name string `json:"name"`
CreatedDate Date `json:"createdDate"`
ExpirationDate Date `json:"expirationDate"`
ProfileContent []byte `json:"profileContent"`
ProfileState string `json:"profileState"`
ProfileType ProfileType `json:"profileType"`
UUID string `json:"uuid"`
Platform string `json:"platform"`
OfflineProfile bool `json:"isOfflineProfile"`
} `json:"attributes"`
Relationships struct {
BundleID struct {
Expand Down Expand Up @@ -116,16 +117,18 @@ func (p Profile) IsExpired() bool {
}

type Data struct {
ID string `json:"id"`
Type string `json:"type"`
ID string `json:"id,omitempty"`
Type string `json:"type,omitempty"`
}

type ProfileCreateRequest struct {
Data struct {
Type string `json:"type"` // profiles
Attributes struct {
Name string `json:"name"`
ProfileType string `json:"profileType"`
Name string `json:"name"`
ProfileType ProfileType `json:"profileType"`
TemplateName string `json:"templateName,omitempty"`
OfflineProfile bool `json:"isOfflineProfile,omitempty"`
} `json:"attributes"`
Relationships struct {
BundleID struct {
Expand Down Expand Up @@ -378,15 +381,16 @@ func (as *AppStore) GetProfileCerts(id string) ([]Certificate, error) {
}

// CreateProfile creates a new profile
func (as *AppStore) CreateProfile(name string, ptype string, bundleID string, cerIDs, devicesIDs []string) (*ProfileResponse, error) {
func (as *AppStore) CreateProfile(name string, ptype string, bundleID string, cerIDs, devicesIDs []string, offline bool) (*ProfileResponse, error) {
if err := as.createToken(defaultJWTLife); err != nil {
return nil, fmt.Errorf("failed to create token: %v", err)
}

var profileCreateRequest ProfileCreateRequest
profileCreateRequest.Data.Type = "profiles"
profileCreateRequest.Data.Attributes.ProfileType = ptype
profileCreateRequest.Data.Attributes.Name = name
profileCreateRequest.Data.Attributes.ProfileType = ProfileType(ptype)
profileCreateRequest.Data.Attributes.OfflineProfile = offline
profileCreateRequest.Data.Relationships.BundleID.Data.Type = "bundleIds"
profileCreateRequest.Data.Relationships.BundleID.Data.ID = bundleID
for _, cerID := range cerIDs {
Expand Down

0 comments on commit 1817795

Please sign in to comment.