revert add launcher folder and some checks to it
This commit is contained in:
2026-08-22 23:39:46 +00:00
parent af4230500e
commit 2c51c4736a
13 changed files with 169 additions and 328 deletions
+53 -73
View File
@@ -13,8 +13,7 @@
namespace {
const QString kAuthServer = QStringLiteral("https://authserver.ely.by");
const QString kInjectorManifest = QStringLiteral(
"https://authlib-injector.yushi.moe/artifact/latest.json");
const QString kInjectorManifest = QStringLiteral("https://authlib-injector.yushi.moe/artifact/latest.json");
const QString kInjectorFileName = QStringLiteral("authlib-injector.jar");
// Ely.by отдаёт UUID без дефисов, вручную введённый мог прийти и с ними.
@@ -39,7 +38,8 @@ QString describeElyError(const QJsonObject &response, int status)
AuthService::AuthService(QObject *parent)
: QObject(parent)
, m_network(new QNetworkAccessManager(this))
{}
{
}
AuthResult AuthService::offline(const QString &nickname)
{
@@ -49,11 +49,10 @@ AuthResult AuthService::offline(const QString &nickname)
return result;
}
QByteArray digest
= QCryptographicHash::hash(QStringLiteral("OfflinePlayer:%1").arg(nickname).toUtf8(),
QCryptographicHash::Md5);
digest[6] = static_cast<char>((digest[6] & 0x0f) | 0x30); // версия UUID = 3
digest[8] = static_cast<char>((digest[8] & 0x3f) | 0x80); // вариант RFC 4122
QByteArray digest = QCryptographicHash::hash(
QStringLiteral("OfflinePlayer:%1").arg(nickname).toUtf8(), QCryptographicHash::Md5);
digest[6] = static_cast<char>((digest[6] & 0x0f) | 0x30); // версия UUID = 3
digest[8] = static_cast<char>((digest[8] & 0x3f) | 0x80); // вариант RFC 4122
result.ok = true;
result.playerName = nickname;
@@ -69,17 +68,17 @@ QString AuthService::generateClientToken()
return QUuid::createUuid().toString(QUuid::WithoutBraces);
}
void AuthService::postJson(const QString &endpoint,
const QJsonObject &body,
std::function<void(int, const QJsonObject &, const QString &)> handler)
void AuthService::postJson(
const QString &endpoint,
const QJsonObject &body,
std::function<void(int, const QJsonObject &, const QString &)> handler)
{
QNetworkRequest request{QUrl(kAuthServer + endpoint)};
request.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/json"));
request.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
QNetworkRequest::NoLessSafeRedirectPolicy);
QNetworkReply *reply = m_network->post(request,
QJsonDocument(body).toJson(QJsonDocument::Compact));
QNetworkReply *reply = m_network->post(request, QJsonDocument(body).toJson(QJsonDocument::Compact));
connect(reply, &QNetworkReply::finished, this, [reply, handler = std::move(handler)]() {
reply->deleteLater();
@@ -119,9 +118,8 @@ void AuthService::loginElyBy(const QString &login,
emit progress(tr("Проверка сохранённого токена Ely.by…"));
postJson(QStringLiteral("/auth/validate"),
{{QStringLiteral("accessToken"), accessToken}},
[this, login, password, token, accessToken, callback](int status,
const QJsonObject &,
const QString &transportError) {
[this, login, password, token, accessToken, callback](
int status, const QJsonObject &, const QString &transportError) {
if (!transportError.isEmpty()) {
AuthResult result;
result.error = tr("Нет связи с authserver.ely.by: %1").arg(transportError);
@@ -145,21 +143,17 @@ void AuthService::loginElyBy(const QString &login,
{{QStringLiteral("accessToken"), accessToken},
{QStringLiteral("clientToken"), token},
{QStringLiteral("requestUser"), true}},
[this, login, password, token, callback](int refreshStatus,
const QJsonObject &response,
const QString &error) {
[this, login, password, token, callback](
int refreshStatus, const QJsonObject &response, const QString &error) {
if (error.isEmpty() && refreshStatus == 200) {
AuthResult result;
result.ok = true;
result.accessToken = response.value(QStringLiteral("accessToken"))
.toString();
result.accessToken = response.value(QStringLiteral("accessToken")).toString();
result.clientToken = token;
const QJsonObject profile
= response.value(QStringLiteral("selectedProfile")).toObject();
result.playerName = profile.value(QStringLiteral("name"))
.toString();
result.uuid = normalizeUuid(
profile.value(QStringLiteral("id")).toString());
const QJsonObject profile =
response.value(QStringLiteral("selectedProfile")).toObject();
result.playerName = profile.value(QStringLiteral("name")).toString();
result.uuid = normalizeUuid(profile.value(QStringLiteral("id")).toString());
result.userType = QStringLiteral("ELYBY");
callback(result);
return;
@@ -200,14 +194,12 @@ void AuthService::authenticate(const QString &login,
{QStringLiteral("password"), password},
{QStringLiteral("clientToken"), clientToken},
{QStringLiteral("requestUser"), true}},
[clientToken,
callback](int status, const QJsonObject &response, const QString &transportError) {
[clientToken, callback](int status, const QJsonObject &response, const QString &transportError) {
AuthResult result;
result.clientToken = clientToken;
if (!transportError.isEmpty()) {
result.error = AuthService::tr("Нет связи с authserver.ely.by: %1")
.arg(transportError);
result.error = AuthService::tr("Нет связи с authserver.ely.by: %1").arg(transportError);
callback(result);
return;
}
@@ -218,29 +210,27 @@ void AuthService::authenticate(const QString &login,
result.twoFactorRequired = message.contains(QStringLiteral("two factor"),
Qt::CaseInsensitive);
result.error = result.twoFactorRequired
? AuthService::tr(
"Аккаунт защищён двухфакторной аутентификацией")
? AuthService::tr("Аккаунт защищён двухфакторной аутентификацией")
: message;
callback(result);
return;
}
const QJsonObject profile = response.value(QStringLiteral("selectedProfile"))
.toObject();
const QJsonObject profile = response.value(QStringLiteral("selectedProfile")).toObject();
result.playerName = profile.value(QStringLiteral("name")).toString();
result.uuid = normalizeUuid(profile.value(QStringLiteral("id")).toString());
result.accessToken = response.value(QStringLiteral("accessToken")).toString();
result.userType = QStringLiteral("ELYBY");
result.ok = !result.accessToken.isEmpty() && !result.playerName.isEmpty();
if (!result.ok)
result.error = AuthService::tr(
"Ely.by не вернул игровой профиль для этого аккаунта");
result.error = AuthService::tr("Ely.by не вернул игровой профиль для этого аккаунта");
callback(result);
});
}
void AuthService::ensureAuthlibInjector(
const QString &targetDir, std::function<void(const QString &, const QString &)> callback)
const QString &targetDir,
std::function<void(const QString &, const QString &)> callback)
{
QDir().mkpath(targetDir);
const QString jarPath = targetDir + u'/' + kInjectorFileName;
@@ -258,9 +248,8 @@ void AuthService::ensureAuthlibInjector(
connect(manifestReply, &QNetworkReply::finished, this, [this, manifestReply, jarPath, callback]() {
manifestReply->deleteLater();
if (manifestReply->error() != QNetworkReply::NoError) {
callback({},
tr("Не удалось получить сведения об authlib-injector: %1")
.arg(manifestReply->errorString()));
callback({}, tr("Не удалось получить сведения об authlib-injector: %1")
.arg(manifestReply->errorString()));
return;
}
@@ -279,39 +268,30 @@ void AuthService::ensureAuthlibInjector(
jarRequest.setAttribute(QNetworkRequest::RedirectPolicyAttribute,
QNetworkRequest::NoLessSafeRedirectPolicy);
QNetworkReply *jarReply = m_network->get(jarRequest);
connect(jarReply,
&QNetworkReply::finished,
this,
[jarReply, jarPath, expectedSha256, callback]() {
jarReply->deleteLater();
if (jarReply->error() != QNetworkReply::NoError) {
callback({},
AuthService::tr("Не удалось скачать authlib-injector: %1")
.arg(jarReply->errorString()));
return;
}
connect(jarReply, &QNetworkReply::finished, this, [jarReply, jarPath, expectedSha256, callback]() {
jarReply->deleteLater();
if (jarReply->error() != QNetworkReply::NoError) {
callback({}, AuthService::tr("Не удалось скачать authlib-injector: %1").arg(jarReply->errorString()));
return;
}
const QByteArray payload = jarReply->readAll();
if (!expectedSha256.isEmpty()) {
const QString actual = QString::fromLatin1(
QCryptographicHash::hash(payload, QCryptographicHash::Sha256).toHex());
if (actual != expectedSha256) {
callback({},
AuthService::tr(
"Контрольная сумма authlib-injector не совпала"));
return;
}
}
const QByteArray payload = jarReply->readAll();
if (!expectedSha256.isEmpty()) {
const QString actual = QString::fromLatin1(
QCryptographicHash::hash(payload, QCryptographicHash::Sha256).toHex());
if (actual != expectedSha256) {
callback({}, AuthService::tr("Контрольная сумма authlib-injector не совпала"));
return;
}
}
QFile file(jarPath);
if (!file.open(QIODevice::WriteOnly) || file.write(payload) != payload.size()) {
callback({},
AuthService::tr("Не удалось сохранить %1")
.arg(QDir::toNativeSeparators(jarPath)));
return;
}
file.close();
callback(jarPath, {});
});
QFile file(jarPath);
if (!file.open(QIODevice::WriteOnly) || file.write(payload) != payload.size()) {
callback({}, AuthService::tr("Не удалось сохранить %1").arg(QDir::toNativeSeparators(jarPath)));
return;
}
file.close();
callback(jarPath, {});
});
});
}