Files
2023-05-13 22:42:24 -06:00

167 lines
3.5 KiB
Go

package utils
import (
"fmt"
"os"
"github.com/AlecAivazis/survey/v2"
"github.com/AlecAivazis/survey/v2/terminal"
"github.com/apex/log"
"github.com/blacktop/ipsw/pkg/usb"
"github.com/blacktop/ipsw/pkg/usb/lockdownd"
"github.com/blacktop/ipsw/pkg/usb/mount"
)
func PickDevice() (*lockdownd.DeviceValues, error) {
var deets []*lockdownd.DeviceValues
conn, err := usb.NewConn()
if err != nil {
return nil, fmt.Errorf("failed to connect to usbmuxd: %w", err)
}
defer conn.Close()
devices, err := conn.ListDevices()
if err != nil {
return nil, fmt.Errorf("failed to list devices: %w", err)
}
if len(devices) == 0 {
return nil, fmt.Errorf("no devices found")
}
for _, device := range devices {
ldc, err := lockdownd.NewClient(device.SerialNumber)
if err != nil {
return nil, err
}
deet, err := ldc.GetValues()
if err != nil {
return nil, err
}
deets = append(deets, deet)
ldc.Close()
}
if len(deets) == 1 {
return deets[0], nil
}
selected := make(map[string]*lockdownd.DeviceValues, len(deets))
for _, d := range deets {
selected[fmt.Sprintf("%s_%s_%s", d.ProductType, d.HardwareModel, d.BuildVersion)] = d
}
if len(selected) == 1 {
return deets[0], nil // can happen if device setup to connect via network
}
var choices []string
for s := range selected {
choices = append(choices, s)
}
var picked string
prompt := &survey.Select{
Message: "Select what iDevice to connect to:",
Options: choices,
}
if err := survey.AskOne(prompt, &picked); err == terminal.InterruptErr {
log.Warn("Exiting...")
os.Exit(0)
}
return selected[picked], nil
}
func PickDevices() ([]*lockdownd.DeviceValues, error) {
var deets []*lockdownd.DeviceValues
conn, err := usb.NewConn()
if err != nil {
return nil, fmt.Errorf("failed to connect to usbmuxd: %w", err)
}
defer conn.Close()
devices, err := conn.ListDevices()
if err != nil {
return nil, fmt.Errorf("failed to list devices: %w", err)
}
if len(devices) == 0 {
return nil, fmt.Errorf("no devices found")
}
for _, device := range devices {
ldc, err := lockdownd.NewClient(device.SerialNumber)
if err != nil {
return nil, err
}
deet, err := ldc.GetValues()
if err != nil {
return nil, err
}
deets = append(deets, deet)
ldc.Close()
}
if len(deets) == 1 {
return deets, nil
} else {
var choices []string
for _, d := range deets {
choices = append(choices, fmt.Sprintf("%s_%s_%s", d.ProductType, d.HardwareModel, d.BuildVersion))
}
selected := []int{}
prompt := &survey.MultiSelect{
Message: "Select what iDevices to connect to:",
Options: choices,
}
if err := survey.AskOne(prompt, &selected); err == terminal.InterruptErr {
log.Warn("Exiting...")
os.Exit(0)
}
// filter based on selection
var picked []*lockdownd.DeviceValues
for _, idx := range selected {
picked = append(picked, deets[idx])
}
return picked, nil
}
}
func IsDeveloperModeEnabled(udid string) (bool, error) {
cli, err := lockdownd.NewClient(udid)
if err != nil {
return false, fmt.Errorf("failed to connect to lockdownd: %w", err)
}
defer cli.Close()
return cli.DeveloperModeEnabled()
}
func IsDeveloperImageMounted(udid string) error {
cli, err := mount.NewClient(udid)
if err != nil {
return fmt.Errorf("failed to connect to mobile_image_mounter: %w", err)
}
defer cli.Close()
images, err := cli.ListImages()
if err != nil {
return fmt.Errorf("failed to list images: %w", err)
}
if len(images) == 0 {
return fmt.Errorf("mount the Developer image with the `ipsw idev img mount` command or by opening Xcode")
}
return nil
}