Files
BiLauncher/doc/cpp/AuthService.md
T

88 lines
5.6 KiB
Markdown
Raw Normal View History

2026-09-03 09:16:56 +03:00
# AuthService
2026-10-11 22:32:13 +03:00
`authservice.h`, `authservice.cpp`
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
Вход через Ely.by, офлайн-профиль и загрузка `authlib-injector`. Вход через Microsoft живёт
отдельно, в [MsaAuthService](MsaAuthService.md), но отдаёт результат в той же структуре
`AuthResult`. Поэтому запуск игры дальше идёт одинаково, как бы игрок ни вошёл.
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
Экземпляр создаёт и держит [LauncherBackend](LauncherBackend.md). Сервис ничего не пишет на диск,
кроме скачанного jar: токены между запусками сохраняет бэкенд в `profiles.json`.
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
## AuthResult
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
Каждое поле соответствует подстановке в аргументах запуска.
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
| Поле | Подстановка / смысл |
|------|---------------------|
| `ok` | вход удался |
| `twoFactorRequired` | Ely.by требует одноразовый код |
| `licenseMissing` | Microsoft: вход прошёл, но игры на аккаунте нет. Отдельный флаг, потому что повторный вход тут не поможет |
| `error` | текст ошибки, если `ok == false` |
| `playerName` | `${auth_player_name}` |
| `uuid` | `${auth_uuid}`, hex без дефисов |
| `accessToken` | `${auth_access_token}` |
| `clientToken` | `${clientid}` |
| `userType` | `${user_type}`: `legacy` (офлайн), `ELYBY`, `msa` |
| `refreshToken` | только Microsoft: продление сессии без пароля |
| `xuid` | только Microsoft: `${auth_xuid}` |
| `expiresAt` | только Microsoft: когда истекает `accessToken`, UTC |
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
## Офлайн
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
`static AuthResult offline(nickname)` работает без сети. UUID считается так же, как в самом
Minecraft: MD5 от `OfflinePlayer:<ник>`, после чего выставляются биты версии 3 и варианта RFC 4122.
Значит, у одного ника всегда один UUID, и на офлайн-сервере игрок не теряет инвентарь. В
`accessToken` и `clientToken` записывается `"0"`.
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
Пустой ник — ошибка.
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
## Ely.by
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
Сервер — `https://authserver.ely.by`, протокол Yggdrasil, JSON по HTTPS.
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
`loginElyBy(login, password, clientToken, accessToken, callback)` старается не спрашивать пароль:
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
1. Если сохранённого `accessToken` нет, сразу `/auth/authenticate` с паролем.
2. Если есть, `/auth/validate`. Ответ 200 — токен рабочий, вход закончен.
3. Иначе `/auth/refresh`. Если продлить удалось, приходят новый токен, ник и UUID.
4. Если и это не вышло, `/auth/authenticate` с паролем.
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
Если сервер недоступен (статус 0 и сетевая ошибка), цепочка обрывается с ошибкой, без попытки войти
по паролю.
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
Второй фактор Ely.by не сообщает отдельным кодом. Сервис ищет в тексте ошибки подстроку
`two factor` и выставляет `twoFactorRequired`. Тогда бэкенд спрашивает код у игрока и вызывает
`loginElyByWithTotp(login, password, totp, clientToken, callback)`, который отправляет пароль в виде
`пароль:код`, как требует Ely.by.
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
`clientToken` генерируется один раз на профиль (`generateClientToken()`, случайный UUID) и хранится
вместе с ним: Yggdrasil привязывает выданный `accessToken` к этому значению.
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
По ходу работы испускается `progress(message)`. Бэкенд пересылает его в `launchProgress`.
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
## authlib-injector
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
Без него игра пойдёт проверять сессию на серверы Mojang, и токен Ely.by окажется недействительным.
Jar подключается к JVM через `-javaagent` (см. [GameLauncher](GameLauncher.md)).
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
`ensureAuthlibInjector(targetDir, callback)`:
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
- если `<targetDir>/authlib-injector.jar` уже есть, сразу отдаёт путь. Версия не проверяется, и
обновить файл можно, только удалив его;
- иначе читает `https://authlib-injector.yushi.moe/artifact/latest.json`, скачивает jar по
`download_url` и, если в манифесте есть `checksums.sha256`, сверяет хеш.
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
Колбэк получает либо путь, либо текст ошибки. `targetDir` — это `<root>/runtime`.
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
## Как вызываются колбэки
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
Все сетевые методы асинхронные, колбэк вызывается один раз в GUI-потоке. Если сервис удалить во
время запроса, менеджер сети уйдёт вместе с ним, и колбэк не вызовется вообще. Бэкенд к тому же
проверяет в каждом колбэке, не отменили ли запуск, пока шёл запрос.
2026-09-03 09:16:56 +03:00
2026-10-11 22:32:13 +03:00
Повторных попыток при сетевых ошибках нет.
2026-09-03 09:16:56 +03:00
---
При создании этого документа использовался ИИ.