mirror of
https://github.com/nihilvux/bancho.py.git
synced 2025-09-17 02:58:39 -07:00
Add files via upload
This commit is contained in:
167
tools/proxy.py
Normal file
167
tools/proxy.py
Normal file
@@ -0,0 +1,167 @@
|
||||
# like budget wireshark for osu! server stuff
|
||||
# usage: enable http://localhost:8080 proxy in windows,
|
||||
# (https://i.cmyui.xyz/DNnqifKHyBSA9X8NEHg.png)
|
||||
# and run this with `mitmdump -qs tools/proxy.py`
|
||||
from __future__ import annotations
|
||||
|
||||
domain = "cmyui.xyz" # XXX: put your domain here
|
||||
|
||||
import re
|
||||
import struct
|
||||
import sys
|
||||
from enum import IntEnum
|
||||
from enum import unique
|
||||
|
||||
from mitmproxy import http
|
||||
|
||||
|
||||
@unique
|
||||
class ServerPackets(IntEnum):
|
||||
USER_ID = 5
|
||||
SEND_MESSAGE = 7
|
||||
PONG = 8
|
||||
HANDLE_IRC_CHANGE_USERNAME = 9 # unused
|
||||
HANDLE_IRC_QUIT = 10
|
||||
USER_STATS = 11
|
||||
USER_LOGOUT = 12
|
||||
SPECTATOR_JOINED = 13
|
||||
SPECTATOR_LEFT = 14
|
||||
SPECTATE_FRAMES = 15
|
||||
VERSION_UPDATE = 19
|
||||
SPECTATOR_CANT_SPECTATE = 22
|
||||
GET_ATTENTION = 23
|
||||
NOTIFICATION = 24
|
||||
UPDATE_MATCH = 26
|
||||
NEW_MATCH = 27
|
||||
DISPOSE_MATCH = 28
|
||||
TOGGLE_BLOCK_NON_FRIEND_DMS = 34
|
||||
MATCH_JOIN_SUCCESS = 36
|
||||
MATCH_JOIN_FAIL = 37
|
||||
FELLOW_SPECTATOR_JOINED = 42
|
||||
FELLOW_SPECTATOR_LEFT = 43
|
||||
ALL_PLAYERS_LOADED = 45
|
||||
MATCH_START = 46
|
||||
MATCH_SCORE_UPDATE = 48
|
||||
MATCH_TRANSFER_HOST = 50
|
||||
MATCH_ALL_PLAYERS_LOADED = 53
|
||||
MATCH_PLAYER_FAILED = 57
|
||||
MATCH_COMPLETE = 58
|
||||
MATCH_SKIP = 61
|
||||
UNAUTHORIZED = 62 # unused
|
||||
CHANNEL_JOIN_SUCCESS = 64
|
||||
CHANNEL_INFO = 65
|
||||
CHANNEL_KICK = 66
|
||||
CHANNEL_AUTO_JOIN = 67
|
||||
BEATMAP_INFO_REPLY = 69
|
||||
PRIVILEGES = 71
|
||||
FRIENDS_LIST = 72
|
||||
PROTOCOL_VERSION = 75
|
||||
MAIN_MENU_ICON = 76
|
||||
MONITOR = 80 # unused
|
||||
MATCH_PLAYER_SKIPPED = 81
|
||||
USER_PRESENCE = 83
|
||||
RESTART = 86
|
||||
MATCH_INVITE = 88
|
||||
CHANNEL_INFO_END = 89
|
||||
MATCH_CHANGE_PASSWORD = 91
|
||||
SILENCE_END = 92
|
||||
USER_SILENCED = 94
|
||||
USER_PRESENCE_SINGLE = 95
|
||||
USER_PRESENCE_BUNDLE = 96
|
||||
USER_DM_BLOCKED = 100
|
||||
TARGET_IS_SILENCED = 101
|
||||
VERSION_UPDATE_FORCED = 102
|
||||
SWITCH_SERVER = 103
|
||||
ACCOUNT_RESTRICTED = 104
|
||||
RTX = 105 # unused
|
||||
MATCH_ABORT = 106
|
||||
SWITCH_TOURNAMENT_SERVER = 107
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<{self.name} ({self.value})>"
|
||||
|
||||
|
||||
BYTE_ORDER_SUFFIXES = ["B", "KB", "MB", "GB"]
|
||||
|
||||
|
||||
def fmt_bytes(n: int | float) -> str:
|
||||
suffix = None
|
||||
for suffix in BYTE_ORDER_SUFFIXES:
|
||||
if n < 1024:
|
||||
break
|
||||
n /= 1024
|
||||
return f"{n:,.2f}{suffix}"
|
||||
|
||||
|
||||
DOMAIN_RGX = re.compile(
|
||||
rf"^(?P<subdomain>osu|c[e4]?|a|s|b|assets)\.(?:ppy\.sh|{re.escape(domain)})$",
|
||||
)
|
||||
|
||||
PACKET_HEADER_FMT = struct.Struct("<HxI") # header gives us packet id & data length
|
||||
|
||||
print(f"\x1b[0;92mListening (ppy.sh & {domain})\x1b[0m\n")
|
||||
|
||||
|
||||
def response(flow: http.HTTPFlow) -> None:
|
||||
r_match = DOMAIN_RGX.match(flow.request.host)
|
||||
if not r_match:
|
||||
return # unrelated request
|
||||
|
||||
body = flow.response.content
|
||||
if not body:
|
||||
return # empty resp
|
||||
|
||||
sys.stdout.write(f"\x1b[0;93m[{flow.request.method}] {flow.request.url}\x1b[0m\n")
|
||||
body_view = memoryview(body)
|
||||
body_len = len(body)
|
||||
|
||||
if r_match["subdomain"] in ("c", "ce", "c4", "c5", "c6"):
|
||||
if flow.request.method == "POST":
|
||||
packet_num = 1
|
||||
while body_view:
|
||||
# read header
|
||||
_pid, plen = PACKET_HEADER_FMT.unpack_from(body_view)
|
||||
pid = ServerPackets(_pid)
|
||||
body_view = body_view[7:]
|
||||
|
||||
# read data
|
||||
pdata = str(body_view[:plen].tobytes())[2:-1] # remove b''
|
||||
body_view = body_view[plen:]
|
||||
|
||||
sys.stdout.write(f"[{packet_num}] \x1b[0;95m{pid!r}\x1b[0m {pdata}\n")
|
||||
|
||||
packet_num += 1
|
||||
|
||||
if packet_num % 5: # don't build up too much in ram
|
||||
sys.stdout.flush()
|
||||
sys.stdout.write("\n")
|
||||
else: # format varies per request
|
||||
if ( # todo check host
|
||||
(
|
||||
# jfif, jpe, jpeg, jpg graphics file
|
||||
body_view[:4] == b"\xff\xd8\xff\xe0"
|
||||
and body_view[6:11] == b"JFIF\x00"
|
||||
)
|
||||
or (
|
||||
# exif digital jpg
|
||||
body_view[:4] == b"\xff\xd8\xff\xe1"
|
||||
and body_view[6:11] == b"Exif\x00"
|
||||
)
|
||||
or (
|
||||
# spiff still picture jpg
|
||||
body_view[:4] == b"\xff\xd8\xff\xe8"
|
||||
and body_view[6:12] == b"SPIFF\x00"
|
||||
)
|
||||
):
|
||||
sys.stdout.write(f"[{fmt_bytes(body_len)} jpeg file]\n\n")
|
||||
elif (
|
||||
body_view[:8] == b"\x89PNG\r\n\x1a\n"
|
||||
and body_view[-8:] == b"\x49END\xae\x42\x60\x82"
|
||||
):
|
||||
sys.stdout.write(f"[{fmt_bytes(body_len)} png file]\n\n")
|
||||
elif body_view[:6] in (b"GIF87a", b"GIF89a") and body_view[-2:] == b"\x00\x3b":
|
||||
sys.stdout.write(f"[{fmt_bytes(body_len)} gif file]\n\n")
|
||||
else:
|
||||
sys.stdout.write(f"{str(body)[2:-1]}\n\n") # remove b''
|
||||
|
||||
sys.stdout.flush()
|
Reference in New Issue
Block a user