mirror of
https://github.com/blacktop/ipsw.git
synced 2026-06-07 12:27:36 +00:00
190 lines
3.6 KiB
Go
190 lines
3.6 KiB
Go
package usb
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"net"
|
|
|
|
"github.com/blacktop/go-plist"
|
|
)
|
|
|
|
type Client struct {
|
|
tlsConn *tls.Conn
|
|
conn net.Conn
|
|
udid string
|
|
deviceID int
|
|
pairRecord *PairRecord
|
|
}
|
|
|
|
func NewClient(udid string, port int) (*Client, error) {
|
|
conn, err := NewConn()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
devices, err := conn.ListDevices()
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to list devices: %v", err)
|
|
}
|
|
|
|
deviceID := -1
|
|
for _, device := range devices {
|
|
if device.SerialNumber == udid {
|
|
deviceID = device.DeviceID
|
|
break
|
|
}
|
|
}
|
|
|
|
if deviceID < 0 {
|
|
return nil, fmt.Errorf("unable to find device with udid: %v", udid)
|
|
}
|
|
|
|
pairRecord, err := conn.ReadPairRecord(udid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if err := conn.Dial(deviceID, port); err != nil {
|
|
return nil, fmt.Errorf("failed to dial device %d on port %d: %v", deviceID, port, err)
|
|
}
|
|
|
|
return &Client{
|
|
conn: conn,
|
|
pairRecord: pairRecord,
|
|
udid: udid,
|
|
deviceID: deviceID,
|
|
}, nil
|
|
}
|
|
|
|
func (c *Client) EnableSSL() error {
|
|
cert, err := tls.X509KeyPair(c.pairRecord.HostCertificate, c.pairRecord.HostPrivateKey)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to load host certificate from pair record: %v", err)
|
|
}
|
|
|
|
c.tlsConn = tls.Client(c.conn, &tls.Config{
|
|
Certificates: []tls.Certificate{cert},
|
|
ClientAuth: tls.NoClientCert,
|
|
InsecureSkipVerify: true,
|
|
})
|
|
if err := c.tlsConn.Handshake(); err != nil {
|
|
return fmt.Errorf("failed to perform tls handshake: %v", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) DisableSSL() {
|
|
c.tlsConn = nil
|
|
}
|
|
|
|
func (c *Client) Request(req, resp any) error {
|
|
if err := c.Send(req); err != nil {
|
|
return err
|
|
}
|
|
|
|
return c.Recv(resp)
|
|
}
|
|
|
|
func (c *Client) Send(req any) error {
|
|
data, err := plist.Marshal(req, plist.XMLFormat)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := binary.Write(c.Conn(), binary.BigEndian, uint32(len(data))); err != nil {
|
|
return err
|
|
}
|
|
|
|
return binary.Write(c.Conn(), binary.BigEndian, data)
|
|
}
|
|
|
|
func (c Client) Recv(resp any) error {
|
|
data, err := c.RecvBytes()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if _, err := plist.Unmarshal(data, resp); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (c *Client) RecvBytes() ([]byte, error) {
|
|
size := uint32(0)
|
|
if err := binary.Read(c.Conn(), binary.BigEndian, &size); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
data := make([]byte, size)
|
|
if _, err := io.ReadFull(c.Conn(), data); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return data, nil
|
|
}
|
|
|
|
func (c *Client) RecvByte() (byte, error) {
|
|
var b byte
|
|
if err := binary.Read(c.Conn(), binary.BigEndian, &b); err != nil {
|
|
return byte(0), err
|
|
}
|
|
return b, nil
|
|
}
|
|
|
|
func (c *Client) UDID() string {
|
|
return c.udid
|
|
}
|
|
|
|
func (c *Client) DeviceID() int {
|
|
return c.deviceID
|
|
}
|
|
|
|
func (c *Client) Conn() net.Conn {
|
|
if c.tlsConn != nil {
|
|
return c.tlsConn
|
|
}
|
|
|
|
return c.conn
|
|
}
|
|
|
|
func (c *Client) PairRecord() *PairRecord {
|
|
return c.pairRecord
|
|
}
|
|
|
|
func (c Client) Close() error {
|
|
return c.Conn().Close()
|
|
}
|
|
|
|
func (c *Client) DeviceLinkHandshake() ([]any, error) {
|
|
var versionExchange []any
|
|
if err := c.Recv(&versionExchange); err != nil {
|
|
return nil, err
|
|
}
|
|
reply := []any{"DLMessageVersionExchange", "DLVersionsOk", versionExchange[1]}
|
|
if err := c.Send(reply); err != nil {
|
|
return nil, err
|
|
}
|
|
var ready []any
|
|
if err := c.Recv(&ready); err != nil {
|
|
return nil, err
|
|
}
|
|
return ready, nil
|
|
}
|
|
|
|
func (c *Client) DeviceLinkSend(msg any) error {
|
|
return c.Send([]any{"DLMessageProcessMessage", msg})
|
|
}
|
|
|
|
func (c *Client) DeviceLinkRecv() (any, error) {
|
|
var dlMsg []any
|
|
if err := c.Recv(&dlMsg); err != nil {
|
|
return nil, err
|
|
}
|
|
return dlMsg[1], nil
|
|
}
|