diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 4c62bbce5..e5358c8ad 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -121,6 +121,8 @@ set(NET_SOURCES net/Download.h net/FileSink.cpp net/FileSink.h + net/Head.cpp + net/Head.h net/HttpMetaCache.cpp net/HttpMetaCache.h net/MetaCacheSink.cpp diff --git a/launcher/minecraft/auth/custom/steps/CustomAuthStep.cpp b/launcher/minecraft/auth/custom/steps/CustomAuthStep.cpp index 15e94693b..3166fe19a 100644 --- a/launcher/minecraft/auth/custom/steps/CustomAuthStep.cpp +++ b/launcher/minecraft/auth/custom/steps/CustomAuthStep.cpp @@ -18,6 +18,8 @@ #include "CustomAuthStep.h" +#include + #include "Application.h" #include "Logging.h" #include "net/NetUtils.h" @@ -77,7 +79,11 @@ QString CustomAuthStep::requestTemplate() { "accessToken": "%1", "clientToken": "%2", - "requestUser": false + "requestUser": false, + "selectedProfile": { + "id": "%3", + "name": "%4" + } } )XXX"; } @@ -88,7 +94,8 @@ QString CustomAuthStep::fillRequest() if (m_action == AuthFlow::Action::Login) { return requestTemplate().arg(m_data->accountLogin, m_password, clientID()); } else { - return requestTemplate().arg(m_data->yggdrasilToken.token, m_data->clientID); + return requestTemplate().arg(m_data->yggdrasilToken.token, m_data->clientID, m_data->minecraftProfile.id, + m_data->minecraftProfile.name); } } @@ -106,9 +113,43 @@ bool CustomAuthStep::parseResponse() m_data->clientID = jsonResponse["clientToken"].toString(); - auto profile = jsonResponse["selectedProfile"].toObject(); - m_data->minecraftProfile.id = profile["id"].toString(); - m_data->minecraftProfile.name = profile["name"].toString(); + if (!jsonResponse["selectedProfile"].isNull()) { + auto profile = jsonResponse["selectedProfile"].toObject(); + m_data->minecraftProfile.id = profile["id"].toString(); + m_data->minecraftProfile.name = profile["name"].toString(); + } + + const QJsonArray profiles = jsonResponse["availableProfiles"].toArray(); + if (profiles.size() > 1) { + const auto profileName = [](const auto& profile) { + auto obj = profile.toObject(); + return obj["name"].toString(); + }; + + QStringList list; + std::ranges::transform(profiles, std::back_inserter(list), profileName); + + bool ok = false; + QString selectedProfileName = + QInputDialog::getItem(nullptr, tr("Select profile"), tr("Select profile for this account"), list, 0, false, &ok); + + if (!ok) { + return false; + } + + const auto it = std::ranges::find(profiles, selectedProfileName, profileName); + if (it != profiles.end()) { + auto profileObj = it->toObject(); + m_data->minecraftProfile = MinecraftProfile{ .id = profileObj["id"].toString(), .name = profileObj["name"].toString() }; + } else { + return false; + } + } + + if (profiles.size() == 1 && m_data->minecraftProfile.id.isEmpty()) { + auto profileObj = profiles.first().toObject(); + m_data->minecraftProfile = MinecraftProfile{ .id = profileObj["id"].toString(), .name = profileObj["name"].toString() }; + } return true; } @@ -121,4 +162,4 @@ void CustomAuthStep::onRequestDone() return; } emit finished(AccountTaskState::STATE_WORKING, tr("Got authorization for %1 account").arg(authType())); -} \ No newline at end of file +} diff --git a/launcher/net/Head.cpp b/launcher/net/Head.cpp new file mode 100644 index 000000000..36d1a33ae --- /dev/null +++ b/launcher/net/Head.cpp @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Freesm Launcher - Minecraft Launcher + * Copyright (C) 2026 so5iso4ka + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "ByteArraySink.h" + +#include "Head.h" + + +Net::Head::Ptr Net::Head::makeHeaderPairs(QUrl url, Options options) +{ + auto dl = makeShared(); + dl->m_url = url; + dl->setObjectName(QString("HEAD:") + url.toString()); + dl->m_options = options; + dl->m_sink = std::make_unique(std::make_shared()); + return dl; +} + +QNetworkReply* Net::Head::getReply(QNetworkRequest& request) +{ + return m_network->head(request); +} diff --git a/launcher/net/Head.h b/launcher/net/Head.h new file mode 100644 index 000000000..b9c62497e --- /dev/null +++ b/launcher/net/Head.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Freesm Launcher - Minecraft Launcher + * Copyright (C) 2026 so5iso4ka + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "net/NetRequest.h" + +namespace Net { +class Head : public NetRequest { + Q_OBJECT + public: + using Ptr = shared_qobject_ptr; + Head() { logCat = taskDownloadLogC; } + + static Ptr makeHeaderPairs(QUrl url, Options options = Option::NoOptions); + + protected: + QNetworkReply* getReply(QNetworkRequest& request) override; +}; +} // namespace Net diff --git a/launcher/ui/dialogs/CustomLoginDialog.cpp b/launcher/ui/dialogs/CustomLoginDialog.cpp index b53ffdda1..6d576afc6 100644 --- a/launcher/ui/dialogs/CustomLoginDialog.cpp +++ b/launcher/ui/dialogs/CustomLoginDialog.cpp @@ -61,9 +61,7 @@ void CustomLoginDialog::accept() setUserInputsEnabled(false); ui->progressBar->setVisible(true); - m_response = std::make_shared(); - - m_requestTask = Net::Download::makeByteArray(url, m_response); + m_requestTask = Net::Head::makeHeaderPairs(url); m_requestTask->setNetwork(APPLICATION->network()); connect(m_requestTask.get(), &Task::finished, this, &CustomLoginDialog::onUrlResolving); diff --git a/launcher/ui/dialogs/CustomLoginDialog.h b/launcher/ui/dialogs/CustomLoginDialog.h index b720e2b5f..e9495bcc1 100644 --- a/launcher/ui/dialogs/CustomLoginDialog.h +++ b/launcher/ui/dialogs/CustomLoginDialog.h @@ -18,7 +18,7 @@ #include #include "minecraft/auth/custom/CustomAccount.h" -#include "net/Download.h" +#include "net/Head.h" #include "tasks/Task.h" namespace Ui { @@ -56,6 +56,5 @@ class CustomLoginDialog : public QDialog { Ui::CustomLoginDialog* ui; CustomAccountPtr m_account; Task::Ptr m_loginTask; - Net::Download::Ptr m_requestTask; - std::shared_ptr m_response; + Net::Head::Ptr m_requestTask; };