apns

package
v0.0.0-...-3bed8bd Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 17, 2024 License: AGPL-3.0 Imports: 35 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrResponseChannelClosed = errors.New("response channel closed")
	ErrNilConnection         = errors.New("nil connection")
	ErrNotConnectedToAPNS    = errors.New("not connected to APNS")
)
View Source
var (
	ErrAPNSAckTooLarge error = &UnexpectedAPNSAckError{Code: []byte{0x03}}
	ErrAPNSAckTooEarly error = &UnexpectedAPNSAckError{Code: []byte{0x80}}
)
View Source
var TopicHashMap = map[[20]byte]Topic{}

Functions

func GetCourierHostPort

func GetCourierHostPort(ctx context.Context) (string, int, error)

func Marshal

func Marshal(payload any) ([]byte, error)

func Unmarshal

func Unmarshal(data []byte, into any) error

Types

type CommandID

type CommandID uint8
const (
	CommandConnect         CommandID = 7
	CommandConnectAck      CommandID = 8
	CommandFilterTopics    CommandID = 9
	CommandSendMessage     CommandID = 10
	CommandSendMessageAck  CommandID = 11
	CommandKeepAlive       CommandID = 12
	CommandKeepAliveAck    CommandID = 13
	CommandFilterTopicsAck CommandID = 14 // uncertain
	CommandSetState        CommandID = 20
)

type ConnectAckCommand

type ConnectAckCommand struct {
	Status           []byte `apns:"1"` // 0 for success, 2 for error
	Token            []byte `apns:"3"`
	MaxMessageSize   uint16 `apns:"4"`  // uint16, usually 4 KiB
	Unknown5         []byte `apns:"5"`  // AAI=
	Capabilities     []byte `apns:"6"`  // AAAw==
	LargeMessageSize uint16 `apns:"8"`  // uint16, usually 15 KiB
	ServerTimestamp  uint64 `apns:"10"` // unix milliseconds
}

type ConnectCommand

type ConnectCommand struct {
	DeviceToken []byte         `apns:"1"`
	State       []byte         `apns:"2"`
	Flags       ConnectionFlag `apns:"5"`

	Cert      []byte `apns:"12"`
	Nonce     []byte `apns:"13"`
	Signature []byte `apns:"14"`
}

type Connection

type Connection struct {
	MaxMessageSize      int
	MaxLargeMessageSize int

	NoAutoFlush bool
	// Don't run anything in unchecked background goroutines
	NoAsyncWork bool

	CourierHostnameOverride string

	MessageHandler      func(ctx context.Context, payload *SendMessagePayload) (bool, error)
	ConnectHandler      func(ctx context.Context)
	ConnectErrorHandler func(ctx context.Context, status []byte)
	// contains filtered or unexported fields
}

func NewConnection

func NewConnection(log *zerolog.Logger, privateKey *rsa.PrivateKey, deviceCert *x509.Certificate) *Connection

func (*Connection) CancelResponseID

func (c *Connection) CancelResponseID(requestID uint32)

func (*Connection) CancelResponseUUID

func (c *Connection) CancelResponseUUID(requestID uuid.UUID)

func (*Connection) Close

func (c *Connection) Close() error

func (*Connection) Connect

func (c *Connection) Connect(ctx context.Context, root bool, token []byte) error

func (*Connection) Filter

func (c *Connection) Filter(topics ...Topic) error

func (*Connection) GetConnection

func (c *Connection) GetConnection() net.Conn

func (*Connection) GetCourierHostname

func (c *Connection) GetCourierHostname() string

func (*Connection) GetToken

func (c *Connection) GetToken() []byte

func (*Connection) Run

func (c *Connection) Run(ctx context.Context) error

func (*Connection) SendAck

func (c *Connection) SendAck(id []byte)

func (*Connection) SendMessage

func (c *Connection) SendMessage(topic Topic, payload, id []byte) error

func (*Connection) SetPushKey

func (c *Connection) SetPushKey(key *rsa.PrivateKey, cert *x509.Certificate)

func (*Connection) SetSocksProxy

func (c *Connection) SetSocksProxy(proxyUrl string) error

func (*Connection) SetState

func (c *Connection) SetState(state uint8) error

func (*Connection) WaitResponseID

func (c *Connection) WaitResponseID(requestID uint32) <-chan *SendMessagePayload

func (*Connection) WaitResponseUUID

func (c *Connection) WaitResponseUUID(requestID uuid.UUID) <-chan *SendMessagePayload

type ConnectionFlag

type ConnectionFlag uint32
const (
	BaseConnectionFlags ConnectionFlag = 0b1000001
	RootConnection      ConnectionFlag = 0b100
)

func (ConnectionFlag) MarshalBinary

func (c ConnectionFlag) MarshalBinary() ([]byte, error)

func (ConnectionFlag) ToBytes

func (c ConnectionFlag) ToBytes() []byte

type EncryptionType

type EncryptionType string
const (
	EncryptionTypePair   EncryptionType = "pair"
	EncryptionTypePairEC EncryptionType = "pair-ec"
)

type Field

type Field struct {
	ID    FieldID
	Value []byte
}

type FieldID

type FieldID uint8

type FilterTopicsAckCommand

type FilterTopicsAckCommand struct {
	Token []byte `apns:"1"`
}

type FilterTopicsCommand

type FilterTopicsCommand struct {
	Token  []byte   `apns:"1"`
	Topics [][]byte `apns:"2"`
}

type IDSMessagePayload

type IDSMessagePayload struct {
	Command MessageType `json:"c,omitempty"`
	Message string      `json:"m,omitempty"`
	Type    string      `json:"t,omitempty"`
}

type IncomingSendMessageCommand

type IncomingSendMessageCommand struct {
	MessageID  []byte `apns:"4"`
	Token      []byte `apns:"1"`
	Topic      []byte `apns:"2"`
	Payload    []byte `apns:"3"`
	Expiration []byte `apns:"5"` // uint32, seconds, always 2^32-1 (0xffffffff)?
	Timestamp  []byte `apns:"6"` // uint64, unix nanoseconds
	Unknown7   []byte `apns:"7"` // always 0x02?
}

type KeepAliveCommand

type KeepAliveCommand struct{}

type MessageType

type MessageType uint64
const (
	MessageTypeIDSReregister        MessageType = 32
	MessageTypeIDSDevicesUpdated    MessageType = 34
	MessageTypeIDSHandlesUpdated    MessageType = 66
	MessageTypeIDSError             MessageType = 92 // Sent via the IDS topic, contains at least iMessage activation error descriptions
	MessageTypeHTTPRequest          MessageType = 96
	MessageTypeHTTPResponse         MessageType = 97
	MessageTypeIMessage             MessageType = 100
	MessageTypeDeliveryReceipt      MessageType = 101
	MessageTypeReadReceipt          MessageType = 102
	MessageTypeIMessageAsync        MessageType = 104
	MessageTypePlayedReceipt        MessageType = 105
	MessageTypeSavedReceipt         MessageType = 106
	MessageTypeReflectedDelivery    MessageType = 107
	MessageTypeCertifiedDelivery    MessageType = 109
	MessageTypeMarkUnread           MessageType = 111
	MessageTypeUnknown112           MessageType = 112 // seen in the wild, haven't seen locally so no idea about the content
	MessageTypeUnknown116           MessageType = 116
	MessageTypeIMessageEdit         MessageType = 118
	MessageTypeDeliveryFailure      MessageType = 120
	MessageTypePeerCacheInvalidate  MessageType = 130
	MessageTypeProfileShare         MessageType = 131
	MessageTypeIncomingSMS          MessageType = 140
	MessageTypeIncomingMMS          MessageType = 141
	MessageTypeSMSEnableRequestCode MessageType = 142
	MessageTypeReflectedSMS         MessageType = 143
	MessageTypeReflectedMMS         MessageType = 144
	MessageTypeSMSForwardingToggled MessageType = 145
	MessageTypeSMSSuccess           MessageType = 146
	MessageTypeSMSRead              MessageType = 147
	MessageTypeSMSFailed            MessageType = 149
	MessageTypeMMCSUpload           MessageType = 150
	MessageTypeMMCSDownload         MessageType = 151
	MessageTypeFlushQueue           MessageType = 160 // officially known as OfflineMessagePendingStorageCheck
	MessageTypeSettings             MessageType = 180
	MessageTypeDeleteSync           MessageType = 181
	MessageTypeUndeleteSync         MessageType = 182
	MessageTypeIMessageGroupMeta    MessageType = 190
	MessageTypeLinkPreviewEdit      MessageType = 196
	MessageTypeIMessageAck          MessageType = 255
)

func (MessageType) MarshalJSON

func (mt MessageType) MarshalJSON() ([]byte, error)

func (MessageType) String

func (mt MessageType) String() string

type OutgoingSendMessageCommand

type OutgoingSendMessageCommand struct {
	MessageID []byte `apns:"4"`
	Token     []byte `apns:"2"`
	Topic     []byte `apns:"1"`
	Payload   []byte `apns:"3"`
}

type Payload

type Payload struct {
	ID     CommandID
	Fields []Field
}

func (*Payload) FindField

func (p *Payload) FindField(fieldID uint8) []byte

func (*Payload) MarshalBinary

func (p *Payload) MarshalBinary() ([]byte, error)

func (*Payload) ToBytes

func (p *Payload) ToBytes() []byte

func (*Payload) UnmarshalBinary

func (p *Payload) UnmarshalBinary(data []byte) error

func (*Payload) UnmarshalBinaryStream

func (p *Payload) UnmarshalBinaryStream(reader io.Reader) error

type SendMessageAckCommand

type SendMessageAckCommand struct {
	Token     []byte `apns:"1"`
	MessageID []byte `apns:"4"`
	NullByte  []byte `apns:"8"`

	MaybeError []byte `apns:"6"`
}

type SendMessagePayload

type SendMessagePayload struct {
	Raw           []byte `plist:"-" json:"-"`
	APNSMessageID []byte `plist:"-" json:"-"`
	APNSTopic     Topic  `plist:"-" json:"-"`

	HTTPURL          string            `plist:"u,omitempty" json:",omitempty"`
	HTTPBody         []byte            `plist:"b,omitempty" json:",omitempty"`
	HTTPContentType  string            `plist:"cT,omitempty" json:",omitempty"`
	HTTPHeaders      map[string]string `plist:"h,omitempty" json:",omitempty"`
	HTTPStatus       int               `plist:"hs,omitempty" json:",omitempty"`
	HTTPErrorMessage string            `plist:"hr,omitempty" json:",omitempty"`
	ResponseStatus   types.IDSStatus   `plist:"s,omitempty" json:",omitempty"`

	MMCSOwnerID       string `plist:"mO,omitempty" json:",omitempty"`
	MMCSFileSignature []byte `plist:"mS,omitempty" json:",omitempty"`
	MMCSFileLength    int    `plist:"mL,omitempty" json:",omitempty"`
	MMCSAuthToken     string `plist:"mA,omitempty" json:",omitempty"`
	MMCSAuthURL       string `plist:"mR,omitempty" json:",omitempty"`
	MMCSAuthID        string `plist:"mU,omitempty" json:",omitempty"`

	ContentVersion int    `plist:"cV,omitempty" json:",omitempty"`
	ContentHeaders string `plist:"cH,omitempty" json:",omitempty"`
	ContentBody    []byte `plist:"cB,omitempty" json:",omitempty"`

	EncryptionType    EncryptionType      `plist:"E,omitempty" json:",omitempty"`
	Payload           []byte              `plist:"P,omitempty" json:",omitempty"`
	MessageID         uint32              `plist:"i,omitempty" json:",omitempty"`
	MessageUUID       plistuuid.ByteUUID  `plist:"U,omitempty" json:",omitempty"`
	Command           MessageType         `plist:"c,omitempty" json:",omitempty"`
	OriginalCommand   MessageType         `plist:"oC,omitempty" json:",omitempty"`
	Timestamp         *plisttime.UnixNano `plist:"e,omitempty" json:",omitempty"`
	IsTrustedSender   bool                `plist:"htu,omitempty" json:",omitempty"`
	SenderID          *uri.ParsedURI      `plist:"sP,omitempty" json:",omitempty"`
	Token             []byte              `plist:"t,omitempty" json:",omitempty"`
	SessionToken      []byte              `plist:"sT,omitempty" json:",omitempty"`
	DestinationID     *uri.ParsedURI      `plist:"tP,omitempty" json:",omitempty"`
	Version           int                 `plist:"v,omitempty" json:",omitempty"`
	DeliveryStatus    *bool               `plist:"D,omitempty" json:",omitempty"`
	ExpirationSeconds *int                `plist:"eX,omitempty" json:",omitempty"`
	NoResponseNeeded  *bool               `plist:"nr,omitempty" json:",omitempty"`

	CertifiedDeliveryVersion int    `plist:"cdv,omitempty" json:",omitempty"`
	CertifiedDeliveryRts     []byte `plist:"cdr,omitempty" json:",omitempty"`

	UserAgent string `plist:"ua,omitempty" json:",omitempty"`

	FanoutChunkNumber int `plist:"fcn,omitempty" json:",omitempty"`

	DTL []SendMessagePayload `plist:"dtl,omitempty" json:",omitempty"` // dstIdTokenList?

	// Failures
	FailText                   string              `plist:"aDI,omitempty" json:",omitempty"` // uncertain
	FailReason                 int                 `plist:"fR,omitempty" json:",omitempty"`
	FailMessageID              *plistuuid.ByteUUID `plist:"fU,omitempty" json:",omitempty"`
	FailMessageIDString        *plistuuid.UUID     `plist:"fM,omitempty" json:",omitempty"`
	FailReasonMessage          string              `plist:"fRM,omitempty" json:",omitempty"`
	FailDownloadAttachmentSize int                 `plist:"fFS,omitempty" json:",omitempty"`
	FailUploadAttachmentSize   int                 `plist:"fS,omitempty" json:",omitempty"`
}

type SetStateCommand

type SetStateCommand struct {
	State    uint8  `apns:"1"`
	FieldTwo uint32 `apns:"2"`
}

type Topic

type Topic string
const (
	TopicMadrid                       Topic = "com.apple.madrid"
	TopicAlloySMS                     Topic = "com.apple.private.alloy.sms"
	TopicAlloyGelato                  Topic = "com.apple.private.alloy.gelato"
	TopicAlloyBiz                     Topic = "com.apple.private.alloy.biz"
	TopicAlloySafetyMonitor           Topic = "com.apple.private.alloy.safetymonitor"
	TopicAlloySafetyMonitorOwnAccount Topic = "com.apple.private.alloy.safetymonitor.ownaccount"
	TopicAlloyGamecenteriMessage      Topic = "com.apple.private.alloy.gamecenter.imessage"
	TopicAlloyFitnessFriendsiMessage  Topic = "com.apple.private.alloy.fitnessfriends.imessage"
	TopicAlloyAskTo                   Topic = "com.apple.private.alloy.askto"
	TopicIDS                          Topic = "com.apple.private.ids"
)

type UnexpectedAPNSAckError

type UnexpectedAPNSAckError struct {
	Code []byte
}

func (*UnexpectedAPNSAckError) Error

func (e *UnexpectedAPNSAckError) Error() string

func (*UnexpectedAPNSAckError) Is

func (e *UnexpectedAPNSAckError) Is(other error) bool

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL