Created
May 3, 2020 22:31
-
-
Save socram8888/12e96619a809d248a480d5ca65950f55 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import asyncio | |
import websockets | |
import json | |
import uuid | |
import httpx | |
# I got these by MitM'ing a valid client! | |
DEVICE_TOKEN = None | |
TITLE_TOKEN = None | |
USER_TOKEN = None | |
assert(DEVICE_TOKEN) | |
assert(TITLE_TOKEN) | |
assert(USER_TOKEN) | |
xbl_token = None | |
xbl_auth = None | |
sess_id = str(uuid.uuid4()) | |
rta_conn = None | |
conn_id = None | |
member_count = None | |
async def get_xbl_token(): | |
global xbl_token | |
global xbl_auth | |
print('Requesting XBL token') | |
renew_req = { | |
"Properties": { | |
"DeviceToken": DEVICE_TOKEN, | |
"SandboxId": "RETAIL", | |
"TitleToken": TITLE_TOKEN, | |
"UserTokens": [ | |
USER_TOKEN | |
] | |
}, | |
"RelyingParty": "http://xboxlive.com", | |
"TokenType": "JWT" | |
} | |
reply = httpx.post('https://xsts.auth.xboxlive.com/xsts/authorize', json=renew_req) | |
if reply.status_code != 200: | |
raise Exception('Received an error trying to fetch XBL token') | |
xbl_auth = reply.json() | |
xbl_token = 'XBL3.0 x=%s;%s' % (xbl_auth['DisplayClaims']['xui'][0]['uhs'], xbl_auth['Token']) | |
print('Succeeded') | |
async def rta_open(): | |
global rta_conn | |
global conn_id | |
uri = "wss://rta.xboxlive.com/connect" | |
rta_conn = await websockets.connect(uri, extra_headers={'Authorization': xbl_token}) | |
print('Requesting session data') | |
await rta_conn.send('[1,1,"https://sessiondirectory.xboxlive.com/connections/"]') | |
sess_data = json.loads(await rta_conn.recv()) | |
print('Got session data: %s' % repr(sess_data)) | |
conn_id = sess_data[4]['ConnectionId'] | |
async def rta_keepalive(): | |
print('Keeping alive the session') | |
async for message in rta_conn: | |
print('Received message: %s' % repr(message)) | |
await update_member_count() | |
async def update_member_count(): | |
global member_count | |
client = httpx.AsyncClient() | |
client.headers['Authorization'] = xbl_token | |
client.headers['x-xbl-contract-version'] = '107' | |
print('Getting member count') | |
reply = await client.get('https://sessiondirectory.xboxlive.com/serviceconfigs/4fc10100-5f7a-4470-899b-280835760c07/sessionTemplates/MinecraftLobby/sessions/' + sess_id) | |
if reply.status_code != 200: | |
print('Oops, error fetching member count: ' % reply.text) | |
return | |
reply = reply.json() | |
new_member_count = reply['membersInfo']['count'] | |
print('Members: %d' % new_member_count) | |
if member_count != new_member_count: | |
member_count = new_member_count | |
print('Updating member count') | |
join_req = {"members":{"me":{"properties":{"system":{"active":True,"connection":conn_id}}}},"properties":{"custom":{"MemberCount":member_count}}} | |
reply = await client.put('https://sessiondirectory.xboxlive.com/serviceconfigs/4fc10100-5f7a-4470-899b-280835760c07/sessionTemplates/MinecraftLobby/sessions/' + sess_id, json=join_req) | |
print(reply.text) | |
async def sess_publish(): | |
client = httpx.AsyncClient() | |
client.headers['Authorization'] = xbl_token | |
client.headers['x-xbl-contract-version'] = '107' | |
publish_req = { | |
"members": { | |
"me": { | |
"constants": { | |
"system": { | |
"initialize": True, | |
"xuid": xbl_auth['DisplayClaims']['xui'][0]['xid'] | |
} | |
}, | |
"properties": { | |
"system": { | |
"active": True, | |
"connection": conn_id, | |
"secureDeviceAddress": "", | |
"subscription": { | |
"changeTypes": [ "everything" ], | |
"id": conn_id | |
} | |
} | |
} | |
} | |
}, | |
"properties": { | |
"custom": { | |
"BroadcastSetting": 3, | |
"Joinability": "joinable_by_friends", | |
"LanGame": True, | |
"MaxMemberCount": 10, | |
"MemberCount": 0, | |
"OnlineCrossPlatformGame": True, | |
"SupportedConnections": [ | |
{ | |
"ConnectionType": 1, | |
"HostIpAddress": "192.168.0.245", | |
"HostPort": 19132, | |
"RakNetGUID": "" | |
}, | |
{ | |
"ConnectionType": 3, | |
"HostIpAddress": "81.202.155.93", | |
"HostPort": 19132, | |
"RakNetGUID": "" | |
} | |
], | |
"hostName": xbl_auth['DisplayClaims']['xui'][0]['gtg'], | |
"levelId": "wx+aXvsoDwI=", | |
"ownerId": xbl_auth['DisplayClaims']['xui'][0]['xid'], | |
"protocol": 390, | |
"rakNetGUID": "9395016890158178779", | |
"version": "1.14.60", | |
"worldName": "¡A fregar!", | |
"worldType": "Survival" | |
}, | |
"system": { | |
"closed": False, | |
"joinRestriction": "followed", | |
"readRestriction": "followed" | |
} | |
} | |
} | |
print('Publishing service') | |
reply = await client.put('https://sessiondirectory.xboxlive.com/serviceconfigs/4fc10100-5f7a-4470-899b-280835760c07/sessionTemplates/MinecraftLobby/sessions/' + sess_id, json=publish_req, timeout=3) | |
print(reply.text) | |
await asyncio.sleep(1) | |
print('Checking handle') | |
handles_req = {"sessionRef":{"name":sess_id,"scid":"4fc10100-5f7a-4470-899b-280835760c07","templateName":"MinecraftLobby"},"type":"activity","version":1} | |
reply = await client.post('https://sessiondirectory.xboxlive.com/handles', json=handles_req) | |
print(reply.text) | |
await asyncio.sleep(1) | |
while True: | |
client.headers['Authorization'] = xbl_token | |
await update_member_count() | |
await asyncio.sleep(120) | |
async def presence(): | |
client = httpx.AsyncClient() | |
client.headers['Authorization'] = xbl_token | |
client.headers['x-xbl-contract-version'] = '3' | |
while True: | |
client.headers['Authorization'] = xbl_token | |
print('Keeping alive presence') | |
keepalive = {'state': 'active'} | |
xid = xbl_auth['DisplayClaims']['xui'][0]['xid'] | |
reply = await client.post('https://userpresence.xboxlive.com/users/xuid(%s)/devices/current/titles/current' % xid, json=keepalive) | |
if reply.status_code == 200: | |
print('Presence OK') | |
else: | |
print('Presence error:' + reply.text) | |
await asyncio.sleep(60) | |
async def renew_token(): | |
while True: | |
await asyncio.sleep(10 * 60) | |
await get_xbl_token() | |
loop = asyncio.get_event_loop() | |
loop.run_until_complete(get_xbl_token()) | |
loop.run_until_complete(rta_open()) | |
loop.create_task(rta_keepalive()) | |
loop.create_task(sess_publish()) | |
loop.create_task(presence()) | |
loop.create_task(renew_token()) | |
loop.run_forever() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment