// Package notification_proxy implementiert Apple's `com.apple.mobile.notification_proxy` // für PostNotification-calls. Diese sind nötig vor mobilebackup2-Restore // damit iOS den Restore als "legitimate iTunes-style sync" akzeptiert. // // Reverse-engineered aus TechLockdown's safesurfer.go calls — TL ruft // postNotification VOR + NACH dem mobilebackup2-Restore-Block. // // Wire-Format: 4-byte BE length-prefix + XML plist (dict). package notification_proxy import ( "encoding/binary" "fmt" ios "github.com/danielpaulus/go-ios/ios" ) const serviceName = "com.apple.mobile.notification_proxy" // Apple's standard sync notifications die iOS während iTunes-style sync erwartet. const ( SyncWillStart = "com.apple.itunes-mobdev.syncWillStart" SyncDidStart = "com.apple.itunes-mobdev.syncDidStart" SyncLockRequest = "com.apple.itunes-mobdev.syncLockRequest" SyncDidFinish = "com.apple.itunes-mobdev.syncDidFinish" BackupDomainChanged = "com.apple.mobile.backup.domain_changed" ) type Client struct { conn ios.DeviceConnectionInterface codec ios.PlistCodec } // Open startet die notification-proxy session via Lockdown. func Open(device ios.DeviceEntry) (*Client, error) { conn, err := ios.ConnectToService(device, serviceName) if err != nil { return nil, fmt.Errorf("notification_proxy: connect: %w", err) } return &Client{ conn: conn, codec: ios.NewPlistCodec(), }, nil } func (c *Client) Close() error { if c.conn != nil { return c.conn.Close() } return nil } // PostOnce — convenience: open NP, send PostNotification, close. Vermeidet // connection-sharing-issues mit anderen Services über usbmuxd-socket. func PostOnce(device ios.DeviceEntry, name string) error { c, err := Open(device) if err != nil { return err } defer c.Close() return c.PostNotification(name) } // PostNotification triggert eine system-weite Notification auf iOS. // iOS-Subsystems die diese Notification subscribed haben werden geweckt. func (c *Client) PostNotification(name string) error { msg := map[string]interface{}{ "Command": "PostNotification", "Name": name, } encoded, err := c.codec.Encode(msg) if err != nil { return fmt.Errorf("notification_proxy: encode: %w", err) } // Apple's NP-service erwartet 4-byte BE length-prefix + plist-bytes hdr := make([]byte, 4) binary.BigEndian.PutUint32(hdr, uint32(len(encoded))) if err := c.conn.Send(hdr); err != nil { return fmt.Errorf("notification_proxy: send header: %w", err) } if err := c.conn.Send(encoded); err != nil { return fmt.Errorf("notification_proxy: send payload: %w", err) } return nil }