«Юртогонки» — это почти как популярный когда-то сайт «Клавогонки»: вы соревнуетесь с противником в скорости и точности печати на клавиатуре. Здесь, правда, вы соревнуетесь не с компьютером, а с человеком. И компьютер хорош — следовательно, придётся хитрить.
Можно было воспользоваться каким-нибудь средством для автоматизации пользовательского ввода — например, библиотекой pyautogui
. Но это бы не сработало, потому что клиентская часть игры проверяла скорость ввода и не давала печатать быстрее компьютера:
const handlePress = e => {
e.preventDefault();
now = Date.now()
// 6 ms is the world record. no way a user types faster
if (now - lastInput < 6) {
alert("Обнаружена попытка накрутки скорости печати. Игра всё.");
socket.close();
}
lastInput = now;
socket.send(e.charCode);
};
Функция handlePress
объявлена константой, и переопределить на ходу её нельзя. Но можно скачать фронтенд игры к себе, отредактировать код как вздумается, и запустить его — здорово, если сработает.
Изучив исходники игры, видим, что общение между клиентом и сервером происходит через WebSockets. Нетрдуно проследить, как именно:
- клиент по каждому нажатию клавиши на клавиатуре передаёт код соответствующего символа;
- сервер отвечает состоянием игры в формате JSON.
Осталось только свой клиент, который решает игру во мгновение ока. Возьмём для этих целей модную асинхронную библиотеку aiohttp:
import aiohttp
import asyncio
async def solve():
url = 'wss://urtracing.s.2021.ugractf.ru/token/ws'
async with aiohttp.ClientSession() as s:
async with s.ws_connect(url) as ws:
# получаем текст
text = (await ws.receive_json())['text']
# отправляем его посимвольно назад
for c in text + " ":
await ws.send_str(str(ord(c)))
# проверяем ответы сервера на наличие приза-флага
async for msg in ws:
if flag := msg.json()['prize']:
print(flag)
asyncio.run(solve())
Флаг: ugra_etot_paren_byl_iz_teh_842386f02628a069