diff --git a/.gitignore b/.gitignore index 9f8f6bf..b402efd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ -# APNS -push.crt -push.key -token +# IDS +ids.key +ids.crt # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/apns.py b/apns.py index cf104d2..3db8618 100644 --- a/apns.py +++ b/apns.py @@ -14,17 +14,17 @@ class APNSConnection: #print(self.sock.closed) #print("QUEUE: Waiting for payload...") #self.sock.read(1) - print("QUEUE: Got payload?") + #print("QUEUE: Got payload?") payload = _deserialize_payload(self.sock) #print("QUEUE: Got payload?") if payload is not None: - print("QUEUE: Received payload: " + str(payload)) + #print("QUEUE: Received payload: " + str(payload)) self.incoming_queue.append(payload) - print("QUEUE: Thread ended") + #print("QUEUE: Thread ended") def _pop_by_id(self, id: int) -> tuple[int, list[tuple[int, bytes]]] | None: - print("QUEUE: Looking for id " + str(id) + " in " + str(self.incoming_queue)) + #print("QUEUE: Looking for id " + str(id) + " in " + str(self.incoming_queue)) for i in range(len(self.incoming_queue)): if self.incoming_queue[i][0] == id: return self.incoming_queue.pop(i) @@ -81,9 +81,12 @@ class APNSConnection: self.sock.write(payload) - def send_message(self, topic: str, payload: str): + def send_message(self, topic: str, payload: str, id = None): + if id is None: + id = random.randbytes(4) + payload = _serialize_payload(0x0a, - [(4, random.randbytes(4)), + [(4, id), (1, sha1(topic.encode()).digest()), (2, self.token), (3, payload)]) @@ -93,9 +96,13 @@ class APNSConnection: payload = self.wait_for_packet(0x0b) + if payload[1][0][1] != 0x00.to_bytes(): + raise Exception("Failed to send message") + #raise Exception("Failed to send message, got error code " + str(payload[1][1].hex())) + #payload = _deserialize_payload(self.sock) - print(payload) + #print(payload) def set_state(self, state: int): self.sock.write(_serialize_payload(0x14, [(1, state.to_bytes(1)), (2, 0x7FFFFFFF.to_bytes(4))])) diff --git a/demo.py b/demo.py index 8c7eb1c..a12d12e 100644 --- a/demo.py +++ b/demo.py @@ -1,7 +1,7 @@ import apns from base64 import b64decode, b64encode from hashlib import sha1 -import plistlib +import plistlib, zlib conn1 = apns.APNSConnection() conn1.connect() @@ -10,55 +10,5 @@ conn1.set_state(0x01) conn1.filter([]) conn1.connect(False) conn1.filter(["com.apple.madrid"]) -conn1.send_message("com.apple.madrid", b'bplist00\xd9\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x1dRsPSfcnQcQERuaQvQiSdtlQU_\x10\x1amailto:jjgill07@icloud.com\x10\x01\x10\xf2Wpair-ec_\x10#[macOS,13.2.1,22D68,MacBookPro18,3]\x10\x08\x12$\x01\xe0c\xa1\x12\xd5\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1cRtPQDRsTQPQt_\x10\x1amailto:jjgill07@icloud.com\x08O\x10"\x06\x01r\x00b4\x99\xa5\xd9\xfaf\xda\xabUX\x8f\xf3\x98o\xe6 \xfb\xa2\xd4\xeeH{W.\xc6\xbc\xb1\x184O\x11\x019\n\xc8\x01\x9e\xea^S\x9fFy"\x0e\xa8zi\xee\xa9\x11^\xa3\x1ee]\xae{\xf8@~\xb0p\x07\xb8\xf9\xd2+\x15\x7fy\x8a\x1d\x9b]V\x8cG6\x94\xdf4\xa7\x1e\xe7\xddR]\xe2\x9f\xda\xbf\x927RD]\xb9\x04\xc6U\xa6\xfe!D\x9f\xfd\xa1\xac?X\xc0l\x08\nv\x1b\xc2\xbf\xd8a\x1d\xc6\x99G\xaeV\xbd\xaa\x7f\x91*\xc6\xffvC\x9c9>\x93\xe1\x04\xc2\xc3\xcc-\xd6\xac1j\xc5\x1cR\xbf)Zp\xf4\xbd\x04\xaa\xa5\x7f5e\xf9\x1dq%T\xb2\xdf\xa4{\xa8A\x97\x87\\=|s\x87o\x14\xbe\xd6\xd7\x0e\x81\x91G\x9f\xbe\xedRU\x86.\xd0i\xdd\x80\xcep#\xb01Mv\x97\x9e\x89\'\xb4\x08DUYv\xd5\xaa\xb5\xb14\xc9L\x0c\xdf\x04\x85\x1bK\xfd\xc1\xee\x12 n\xb0\xd1\x92\x16\xfd\xb8\x1e\xc3J\xd9*\x11\x84\xea3\xc5s\xed\xd5\xe3\x16\xc8\x90\xb6t\\\x9b\x87\xe4)\xc3\x1a@\x8f\xa0\xeb\x01\x84\xce7#\x86\x92\x82\xaa\xac\t\x07\xcf\x1b\xfa\xeeZb\xdf\x1a#\xd0_\x12#f\xdc\xef{\x9f\xf7\x1b\xb0\xd9\x17\x01\xe6\x8c$\x1d[\xca\xeb\x1fV3\x842Z\xcb\xa8G\xce\x00\xc5\xc2n\x8e\xd8\x8ck\x9a\x06\x07\rlF\xdc!\xb3\x0cO\x10 \x13\xd4\'\x15\x87\xcf\x8dk\xe1\xde\x17\xba^\x9d\xed\xffy\xf8\xa9H\xda\xbc\xf8\x89S\r;\x92\xc3\xcf\x88\xb6O\x10\x10\xe3\x89E\xdd\xcc|B\x11\xac\x86\x95vl\xc2\x01\xa0\x00\x08\x00\x1b\x00\x1e\x00"\x00$\x00&\x00)\x00+\x00-\x001\x003\x00P\x00R\x00T\x00\\\x00\x82\x00\x84\x00\x89\x00\x8b\x00\x96\x00\x99\x00\x9b\x00\x9e\x00\xa0\x00\xa2\x00\xbf\x00\xc0\x00\xe5\x02"\x02E\x00\x00\x00\x00\x00\x00\x02\x01\x00\x00\x00\x00\x00\x00\x00\x1e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02X') - -print(plistlib.loads(b'bplist00\xda\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x0c\x126RsPSfcnQcQERuaQvQiScdvSdtlQU_\x10\x10tel:+16106632676\x10\x01\x10dWpair-ec_\x10#[macOS,13.2.1,22D68,MacBookPro18,3]\x10\x08\x12iPy\xdc\xa5\x13\x1e$*0\xd5\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1dRtPQDRsTQPQt_\x10\x1amailto:jjgill07@icloud.com\tO\x10$\x06\x01ieR\x01\x88\x1d\xe7\xe4\x141\xbc\x00\xd2\xb7\x89\x86\x8b\xd1t\x87\x99&\rv\xbf}q\x00\xbe\xb0Q\xee\xf4\x05O\x11\x01e\n\xf4\x01y\xd9\xb0\xa6\x96\xad\xac\xfa\x86\x8b\n\x1b\xbb\xf5\x90\x050:\x12\xcc\'\xe9\xed\xd0f\xcc\x97\xa4`\xa7\xb6\xe7F\xf4!\xa4&my\xefYB\xc3\xca=u&\xb0\x06\xe3\xe6\xf5s\xc2o\xb8<\xf6d\x02\x03\x15\x80\x95\xf3\x98\xb6u\x90\xc4\xefbX\x95\x16\x03/\xb3\xbe\xa7\xda\x1f\xaa\xc37\xb5\xe1\xad\xe6\xdcAI\xa9\x83~h\x04H#V\xc7W\x15\x92\xaaK\xb7eo\x1dv\x10\xa5=\xef"\x0bA\xde\xa9\tj\x97\xe4|\xa3\xa1\x01\xf1\xc2i\x85\x06\xfb\xa4>h\xfa\xc22\xdf\xacG\xaa\x0f\n\xf0\xc4\xb5\xbc\xd4:\xb6\xe0\xbcK,\xe0\xcc\x06\x83\xa9\xc1\x07\x82S\x98\x9c\x87~\xe5\x88#i\x867\xf1|~b\xae@\xca\xee\x86\xfc \xb9\x0b\xf4[\x08\xd4}\xf7\xe0k\x9f0s\xf5X\r\xe9Fk\x07k\x1e[=O\x99\xe1^C\x8b\x03O\xd0K\x9f\x85\x7fS\x9f!o\xe1\xc64\xb7\xb2\x9c\xbe\xbc\x12\xe8L \x12\xca\'\x95\x12 `\xb1\xb3\x03\xd6\x84\x11y\x1c\x13\x1eh\xa10\x9b[\x00Ld\xd4\xdeX\x90\\\x08\xb7\xa7\xa0?\x82\'\xd4\x1a@]\xc6D\xd3\x7f\t`d#\x8b\xb7[{\x80A\xc6\xe1Z\x91\xe0\xa4+\xfd\x17\x12\x83\xd9\xa3f\x8b\xd75\xea\xc70\xd6\x8b\xd9\xc1\xfa\xc8Z\x9fv\xf5S\xa8\xc6\x9cY.`\xc4\xb26\x03\xeb)\\# @\x85C\x9a\x06\x07\rlF\xdc!\xb3\x0cO\x10 \x13\xd4\'\x15\x87\xcf\x8dk\xe1\xde\x17\xba^\x9d\xed\xffy\xf8\xa9H\xda\xbc\xf8\x89S\r;\x92\xc3\xcf\x88\xb6\xd5\x14\x15\x16\x17\x18\x1f\x1a!"#_\x10\x1amailto:jjgill07@icloud.com\tO\x10$\x06\x01\x97\xebO\x04\xc3\xfc\x96\xd0N$\x06\xd6\x12\xaal\x07|\xd1\x17P\xcc\xffI\xead\x03\xb7\xa6N\x9d\xc8\xa3\x7fNO\x11\x01e\n\xf4\x01\x82NpzC\x8c\x9c\x97B\xce\x0eY\xe6q\x892\x99F\x93"\xcdY\xbe\xc2\x8a\xcb\xcf\xc0\x82\xa9\xa3\x05\x82\x9d\xb6}\x06\x02\x85\xfa\x7f\x91\xd5kk\x9afY\xfe~\xdf\x83\xa5{E\xdf|\x98\x99\xe4\x81\x10\xee\xbb\x7f\x8d|]\xb6Z\xf1\xf5}\x14\x00#\xf2\x8a]\xfc\xc8m\x95x<,\x89\xe4JN\n\x9b1/\x18\xb6D\xcc=\xa6\xe5}\xff\x9bQ\x85\xb5\xb3\xe6\xa3#\xe6\x14\xd1\x88\xf7\xc3N:\xed\x8c.\xc0\xb0\x9fn%\x9c\x12/\xe2W\\\xc0\xfb\xa2:g\xc1\xf7\xd1g\xa4\xa6\xe3\x11\xd0O\x1c@]\xff\xab\xc6IA\xc1\x15\xb8sI\xb7\x13\xcf\xfdh\xc8\xb95\xd0\xb8\x16\x1e\x15\xb90\x0cy\xcej\xabOyX\xe1"\x87\x02\xb6\xbf$\x1dtA\x8fI\xd2\x1e\x18\xf1.K\xf9\xd3\xda\xe5\xaaD\x08\x87s\xbe\xffe\x14[~\x1a@\xfa\x00\xd4)\xe3\x1b\x82\xc9!\x15\x8f\xd0\xfa\xf0\x14F9\xd2\xecV\xb7\x8f\xd1\x92\x82\xc9$\x95|\xfbM\xd7\xd7\xd2\x8d\xd6\x12\xac|\xdc\x85@4\xe1\xb9@6\xe6rs\x16\xb5\xab\x82N\x03\xa7\xcb\xb5\xd0\xa9C\x81\xcd\x9a\x06\x07\rl\rl\x06.\x0cO\x10 \xe5^\xc0c\xe8\xa4\x1e\xbe\x03\x89\'\xea\xd5m\x94\x05\xae\xf5\x1bqK\x1aJTH\xa4\xeb8\xb8<\xd7)\xd5\x14\x15\x16\x17\x18%&\'()_\x10\x10tel:+16106632676\x08O\x10$\x06\x01\x10\xd1"\xc7$\x99\x88ZP|\xe9rF\xab\x9b\x8b\xa3\x93\xafYL\xea\x91\x07\x02\x83\x95\x88\x9d\xb71\x8dB5O\x11\x01e\n\xf4\x01z\xdf\x1d\xcf\x1aO\xad5#\x92\x12\xbd\xd3\xcb.se\xc3O\x7f\xcd\r\xb6\x1a\xa0/\x83\x9d-RcQ\xcf\x8d\xa2\x85F3g\x12\x8feW/\xb9oQO\xe6\xdfqj\xb6\xf1q\xc6k\xf7\x92\x1bK;\x95\xff\x95TG*z\xa0\xbd\xb57W\xc3\xe7\xfe\x8e\xc3\xfe\xed\x93\xab\xc9\xaaW\xb2\xf5\x83\x18\x10|EG.\xc5&\xd9\x14W\xff\xf3\x0f\x81}\xfe\x87\xed\x13#\x9e\xe0\ny27\x1b\xe9\xb4P\x06AeE\xb2\xdc\xb0sC\'\x81\xd3R\xc1&\xd5\xf1\'\x969\x89\xc7\xd9\xd2\xc7Z,.\xec\xc0\xf2G?(\x90\xcdM\xd3\x99\x03d\xe9|a?\xeb\x91M\x99J\xed&*S\xcd\xf7@]Hc\x81\x92,,e\x87`\xc9\xa0$M5\xcd*\xa7\xa0\x99T\xbb\x9d}\xa4\xdf\xc3\x85\x93&\xd4\xf5\x15}\xd3O\xc9%4\xd9\x01@\x89B\xc7\xee&\x0c\xdf\x14A]r\xbcST\x98\xdb^xS\x8c<\xb7<\x8a\x13\x12 K\xae\xc2\x1b\xd2\xf7 DB\x1b\xa7~\xb3\xa9\xae\xb9\x14\x89v\x10oF\xd4\x88\xfeS\x1bua\xd4e=\x1a@\xc9M\xb8\xef1\x1b\x8a\x80L\x06\x941\xd7Q\x1a\xcc1V\x8dFD\xc3k\xd5\xf1V\x99\x99\xc2\x83=<\xff\x1bX\x1bD>\xfd\x02\xefXx\xeb\x9c\xce\xc3\xb9\xab\x01i<\xee\xdfiWo\xff\x93~\xa5\xd0\x00\xc9\x9a\x06\x07\rlF\xdc!\xb3\x0cO\x10 \x13\xd4\'\x15\x87\xcf\x8dk\xe1\xde\x17\xba^\x9d\xed\xffy\xf8\xa9H\xda\xbc\xf8\x89S\r;\x92\xc3\xcf\x88\xb6\xd5\x14\x15\x16\x17\x18+\x1a-./_\x10\x1amailto:jjgill07@icloud.com\tO\x10$\x06\x01\xc0\xaf\xc0\x90\xa5{\xf2\x15\xa8\xb8\x8e\xf0\xf5\xbfL\x15\xc1\xef\x1cJ<\xa5<\x97\xdd\xa1\x0eU6j%Z\x99\xd0O\x11\x01e\n\xf4\x01m\xfaV\x03\xce\x81{S\x86\xf9\t\x04\x04\xe0o\x86\xcf\xec\xb8*\xe3\xabLH\xa2\xb9X7h\xc2P`\xec4\xd5\x03`._*\x93q\x0eW-\xf9?\x19\xc5\x04\xa4\xe7\x9cA\x03\xffgY\xe4\xd4\x1dUs\xf6\x8550Ut;~\xa3`Tm\xb96f\xc84\x1a\xa5zN\xa8\x8a\xf4\x94[\x08u5\xb2\xae\xf8\x19\x7f\x82\xe1\xec\xa2y\xd79:\xd5\xac!\x02\r\x9c\x9d\xed\xa5\xc6\x84\xfe\xccC\xf4\xb0\x96\x04r&\xa2-\xa1W\xde\xe7\xe6\xad\xfa})g\xadw\xda\xf3\x9e\xd2\xd1\x82\xf1i\xa1W\x9a{po`\x93\x15\xe1\xae\xa4\xfa[\xda\x1d\t\xe1\xea\xd4>De\xccy\xa1\xdd\x8ds\xa6t\x9be\xe3{\xd39\x84\xa3AYd\x159\xbcrLm\x93\x17\xed\xb3:\x153\xafb\x08kb\t\xe2\xc8\xf4\x92\xc9\xde\xeb<:"\x0e\x04\x12.\x9cj\nX\xe5\xce\x90\xd9o\x05\xdbus\rq\'\x19]\xc35\xac\xbb\x12 \xa4&k\xd6+k+\x9e\x01-\x8b\xc0b\x8c|\x13{a\xc2+\x16\xdcM\x18\xb7\xddq\x15A}\xd9k\x1a@\xa1\xb2\x02\xdakBMlH\x14\\\xf4\x11\x9c\x15]\xfa0\xe6\xdf\xe4\xbcI0\xc3-4\xdf\x9b\x95\x08\x97\x96\x88\x10BL\xef)\xf8\xff[\x10*B(\'\xbc\xa7\xadG$\x11\x14]\xae\xab\x9a$\xeb\xbf\xfd\x9aY\x9a\x06\x07\rl\rl\xad\xbd\x0cO\x10 \x9c\x1e\x96b\xa5\x15`\xec@C\t\x12\xb4,\xfam\x88\xaeTJ\xae\xb8\xb0\xa6Ypf\xab\xb9\xf3\xe2\x84\xd5\x14\x15\x16\x17\x181&345_\x10\x10tel:+16106632676\x08O\x10$\x06\x01\x96\x7f\x87\xce\xb5P:\xe8\xea\xe3\xdf\xdb\xff\xe2"`\xd9\n\x80\x94\xb6,K#\xd2\xcah\xb7\'\xac4\x9agMO\x11\x01e\n\xf4\x01\xdc7f\xe9g\xd8\xe1\xf5\x82;\xae\xf3\xe7\xfaa^\x91\x94\xf9\x9c,\x92\xd7\x1c\x8b\x07y\x0e\xfa\x18v\xcb\x83!\x11\x96\xd9\x8f\x88\x97\xc4\x97\x86\x9b \x7f:\xcf|%-\xd9\xaa\xf6n\xa5H\xc8r\t\x04!\x89\x10\xefU\t\x0b\x99\x13\xd0\xd9\xbb\x8f^%\x06\xc0+~\x08\xc4\x8b\xbc\x1brP\x02\x8a\x8dD\xf7\x12 \x1cQ\xcb\xe5IQ\x16\xf2\x01%\xaf\x17kR\x04x\x0c\xf2\t\x972_\'4\xf6\xb0\x07F\x12\xddz\xad\x1a@i\x00\xe3\x9d\xe7"\x03\r\x8e\xa3\xa0\xd4\xf8"\xfc\xa4e|\x87\xdds\xf0n\xfc\xd7\xc6\x04\x86\r\xe3 Se\xa3\xe9\x06&\x13\xd1\x8eX\x91d9\x99\xf9\xbcv\xf87hE.#\xe57=\xe5M\x95\xaa>\xd6)\x9a\x06\x07\rl\rl\xad\xbd\x0cO\x10 \x9c\x1e\x96b\xa5\x15`\xec@C\t\x12\xb4,\xfam\x88\xaeTJ\xae\xb8\xb0\xa6Ypf\xab\xb9\xf3\xe2\x84O\x10\x10\\i\x17\x1f\xaa\x82N\x96\xa5Z\xdb\xe6\x16\x91\x01\x17\x00\x08\x00\x1d\x00 \x00$\x00&\x00(\x00+\x00-\x00/\x003\x007\x009\x00L\x00N\x00P\x00X\x00~\x00\x80\x00\x85\x00\x8b\x00\x96\x00\x99\x00\x9b\x00\x9e\x00\xa0\x00\xa2\x00\xbf\x00\xc0\x00\xe7\x02P\x02s\x02~\x02\x9b\x02\x9c\x02\xc3\x04,\x04O\x04Z\x04m\x04n\x04\x95\x05\xfe\x06!\x06,\x06I\x06J\x06q\x07\xda\x07\xfd\x08\x08\x08\x1b\x08\x1c\x08C\t\xac\t\xcf\x00\x00\x00\x00\x00\x00\x02\x01\x00\x00\x00\x00\x00\x00\x007\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\t\xe2')) -# #print(f"Push Token 1: {b64encode(conn1.token).decode()}") - -# #while True: -# # pass -# #conn1.filter([]) -# conn1.connect(False) -# print(f"User Token 1: {b64encode(conn1.token).decode()}") - -# # conn2 = apns.APNSConnection() -# # conn2.connect() -# # conn2.filter([]) -# # print(f"Push Token 2: {b64encode(conn2.token).decode()}") -# # conn2.connect(False) -# # print(f"User Token 2: {b64encode(conn2.token).decode()}") - -# conn1.filter(["com.apple.madrid"]) -# # conn2.filter(["com.apple.madrid"]) - -# conn1.send_message(b"\xe5^\xc0c\xe8\xa4\x1e\xbe\x03\x89'\xea\xd5m\x94\x05\xae\xf5\x1bqK\x1aJTH\xa4\xeb8\xb8<\xd7)", "com.apple.madrid", b'bplist00\xdd\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x13\x17\x18\x19ScdrRtPRgdQiRsPRnrQcQUQtScdvRuaRqHQvM\x08\xd6\xf3\xe6\x8d\x04\x18\x95\xfd\xea\xe9\xf50_\x10\x10tel:+16106632676\t\x12=\x12c&_\x10\x1amailto:jjgill07@icloud.com\x10\x01\x10mO\x10\x10UC>\x9f\xce\xa4N\xe0\xba\xe9\xad\x8e_h\xd7hO\x10 \xe5^\xc0c\xe8\xa4\x1e\xbe\x03\x89\'\xea\xd5m\x94\x05\xae\xf5\x1bqK\x1aJTH\xa4\xeb8\xb8<\xd7)_\x10#[macOS,13.2.1,22D68,MacBookPro18,3]O\x10!\x01\x97\xca\\"\xcaI\x82\x0c\xb66C\xa7\x89h\x91\xcd\x18Ozj"\x06u;9\x96\xebrQs|=\x10\x08\x00\x08\x00#\x00\'\x00*\x00-\x00/\x002\x005\x007\x009\x00;\x00?\x00B\x00E\x00G\x00U\x00h\x00i\x00n\x00\x8b\x00\x8d\x00\x8f\x00\xa2\x00\xc5\x00\xeb\x01\x0f\x00\x00\x00\x00\x00\x00\x02\x01\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x11') - - -# while True: -# print(conn1.expect_message()) - #print(conn2.expect_message()) -#print(conn1.expect_message()) -#print(conn2.expect_message()) -# #print(sha1(b"com.apple.madrid").digest()) -# # Send a notification -# # expiry timestamp in UNIX epoch -# expiry = 1680761868 -# expiry = expiry.to_bytes(4, "big") - -# # Current time in UNIX nano epoch -# import time -# now = int(time.time() * 1000).to_bytes(8, "big") - -# payload = apns.Payload(0x0a, apns.Fields({1: sha1(b"com.apple.madrid").digest(), 2: conn2.token, 3: b"Hello World!", 4: 0x00.to_bytes(), 5: expiry, 6: now, 7: 0x00.to_bytes()})) -# conn1.sock.write(payload.to_bytes()) - -# print("Waiting for response...") - -# # Check if the notification was sent -# resp = apns.Payload.from_stream(conn1.sock) -# print(resp) - -# # Read the message from the other connection -# resp = apns.Payload.from_stream(conn2.sock) -# print(resp) \ No newline at end of file +# See ids.py for something useful \ No newline at end of file diff --git a/ids.py b/ids.py new file mode 100644 index 0000000..65101bd --- /dev/null +++ b/ids.py @@ -0,0 +1,108 @@ +import requests +import plistlib +from base64 import b64encode, b64decode +from datetime import datetime +import random +from hashlib import sha1 +import zlib + +USER_AGENT = "com.apple.madrid-lookup [macOS,13.2.1,22D68,MacBookPro18,3]" +PUSH_TOKEN = "5V7AY+ikHr4DiSfq1W2UBa71G3FLGkpUSKTrOLg81yk=" + +# Nonce Format: +# 01000001876bd0a2c0e571093967fce3d7 +# 01 # version +# 000001876d008cc5 # unix time +# r1r2r3r4r5r6r7r8 # random bytes +def generate_nonce() -> bytes: + return b"\x01" + int(datetime.now().timestamp() * 1000).to_bytes(8, "big") + random.randbytes(8) + +def load_keys() -> tuple[str, str]: + # Load the private key and certificate from files + with open("ids.key", "r") as f: + ids_key = f.read() + with open("ids.crt", "r") as f: + ids_cert = f.read() + + return ids_key, ids_cert + +def _create_payload(bag_key: str, query_string: str, push_token: str, payload: bytes) -> tuple[str, bytes]: + # Generate the nonce + nonce = generate_nonce() + push_token = b64decode(push_token) + + return nonce + len(bag_key).to_bytes(4) + bag_key.encode() + len(query_string).to_bytes(4) + query_string.encode() + len(payload).to_bytes(4) + payload + len(push_token).to_bytes(4) + push_token, nonce + + +def sign_payload(private_key: str, bag_key: str, query_string: str, push_token: str, payload: bytes) -> tuple[str, bytes]: + from cryptography.hazmat.primitives import serialization + from cryptography.hazmat.primitives.asymmetric import padding + from cryptography.hazmat.primitives import hashes + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives.asymmetric import utils + + # Load the private key + key = serialization.load_pem_private_key(private_key.encode(), password=None, backend=default_backend()) + + payload, nonce = _create_payload(bag_key, query_string, push_token, payload) + sig = key.sign(payload, padding.PKCS1v15(), hashes.SHA1()) + + sig = b"\x01\x01" + sig + sig = b64encode(sig).decode() + + return sig, nonce + +body = {'uris': ['mailto:jjtech@jjtech.dev']} +body = plistlib.dumps(body) +body = zlib.compress(body, wbits=16 + zlib.MAX_WBITS) + +key, cert = load_keys() +signature, nonce = sign_payload(key, 'id-query', '', PUSH_TOKEN, body) + +headers = { + 'x-id-cert': cert.replace("-----BEGIN CERTIFICATE-----", "").replace("-----END CERTIFICATE-----", "").replace("\n", ""), + 'x-id-nonce': b64encode(nonce).decode(), + 'x-id-sig': signature, + 'x-push-token': PUSH_TOKEN, + 'x-id-self-uri': 'mailto:jjtech@jjtech.dev', + 'User-Agent': USER_AGENT, + 'x-protocol-version': '1630', +} + +# We have to send it over APNs +import apns + +conn1 = apns.APNSConnection() +conn1.connect() +conn1.keep_alive() +conn1.set_state(0x01) +conn1.filter([]) +conn1.connect(False) +conn1.filter(["com.apple.madrid"]) +print(conn1.token) + +to_send = {'cT': 'application/x-apple-plist', + 'U': b'\x16%D\xd5\xcd:D1\xa1\xa7z6\xa9\xe2\xbc\x8f', # Just random bytes? + 'c': 96, + 'ua': '[macOS,13.2.1,22D68,MacBookPro18,3]', + 'u': 'https://query.ess.apple.com/WebObjects/QueryService.woa/wa/query', + 'h': headers, + 'v': 2, # breaks lookup + 'b': body +} + +conn1.send_message("com.apple.madrid", plistlib.dumps(to_send, fmt=plistlib.FMT_BINARY)) + +response = conn1.wait_for_packet(0x0a) + +response = apns._get_field(response[1], 3) + +response = plistlib.loads(response) + +print(f"Status code: {response['hs']}") + +body = response['b'] +body = zlib.decompress(body, 16 + zlib.MAX_WBITS) +body = plistlib.loads(body) + +print(f"Body: {body}") \ No newline at end of file