// SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2023 Evan Goode * * 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 "AuthlibInjectorLoginDialog.h" #include "ui/dialogs/CustomMessageBox.h" #include "ui_AuthlibInjectorLoginDialog.h" #include "CreateAuthlibInjectorAccount.h" #include AuthlibInjectorLoginDialog::AuthlibInjectorLoginDialog(QWidget* parent) : QDialog(parent), ui(new Ui::AuthlibInjectorLoginDialog) { ui->setupUi(this); ui->loadingLabel->setVisible(false); ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); setAcceptDrops(true); connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } AuthlibInjectorLoginDialog::~AuthlibInjectorLoginDialog() { delete ui; } QString AuthlibInjectorLoginDialog::fixUrl(QString url) { QString fixed{ url }; fixed = fixed.trimmed(); if (!fixed.contains("://")) { fixed.prepend("https://"); } if (fixed.endsWith("/")) { fixed = fixed.left(fixed.size() - 1); } return fixed; } QUrl AuthlibInjectorLoginDialog::extractAuthlibInjectorUrl(const QMimeData* mimeData) { if (mimeData->hasText()) { const auto& text = mimeData->text().toStdString(); const std::string authlib_injector_uri_prefix{ "authlib-injector:yggdrasil-server:" }; if (text.rfind(authlib_injector_uri_prefix, 0) == 0) { const auto& url_str = text.substr(authlib_injector_uri_prefix.length()); const auto& url = QUrl(QUrl::fromPercentEncoding(url_str.c_str())); if (url.isValid()) { return url; } } } return {}; } void AuthlibInjectorLoginDialog::dragEnterEvent(QDragEnterEvent* event) { if (extractAuthlibInjectorUrl(event->mimeData()).isValid()) { event->acceptProposedAction(); } } void AuthlibInjectorLoginDialog::dropEvent(QDropEvent* event) { const auto& url = extractAuthlibInjectorUrl(event->mimeData()); if (url.isValid()) { ui->authlibInjectorTextBox->setText(url.toString()); } event->acceptProposedAction(); } // Stage 1: User interaction void AuthlibInjectorLoginDialog::accept() { auto fixedAuthlibInjectorUrl = AuthlibInjectorLoginDialog::fixUrl(ui->authlibInjectorTextBox->text()); auto response = CustomMessageBox::selectable(this, QObject::tr("Confirm account creation"), QObject::tr("Warning: you are about to send the username and password you entered to an " "unofficial, third-party authentication server:\n" "%1\n\n" "Never use your Mojang or Microsoft password for a third-party account!\n\n" "Are you sure you want to proceed?") .arg(fixedAuthlibInjectorUrl), QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) ->exec(); if (response != QMessageBox::Yes) return; setUserInputsEnabled(false); ui->loadingLabel->setVisible(true); // Get the authlib-injector API root auto netJob = NetJob::Ptr(new NetJob("Get authlib-injector API root", APPLICATION->network())); netJob->setAskRetry(false); auto username = ui->userTextBox->text(); m_createAuthlibInjectorAccountTask = CreateAuthlibInjectorAccount::make(fixedAuthlibInjectorUrl, m_account, username); netJob->addNetAction(m_createAuthlibInjectorAccountTask); m_createAuthlibInjectorAccountNetJob.reset(netJob); connect(netJob.get(), &NetJob::succeeded, this, &AuthlibInjectorLoginDialog::onUrlTaskSucceeded); connect(netJob.get(), &NetJob::failed, this, &AuthlibInjectorLoginDialog::onTaskFailed); m_createAuthlibInjectorAccountNetJob->start(); } void AuthlibInjectorLoginDialog::setUserInputsEnabled(bool enable) { ui->userTextBox->setEnabled(enable); ui->passTextBox->setEnabled(enable); ui->authlibInjectorTextBox->setEnabled(enable); ui->buttonBox->setEnabled(enable); } // Enable the OK button only when all textboxes contain something. void AuthlibInjectorLoginDialog::on_userTextBox_textEdited(const QString& newText) { ui->buttonBox->button(QDialogButtonBox::Ok) ->setEnabled(!newText.isEmpty() && !ui->passTextBox->text().isEmpty() && !ui->authlibInjectorTextBox->text().isEmpty()); } void AuthlibInjectorLoginDialog::on_passTextBox_textEdited(const QString& newText) { ui->buttonBox->button(QDialogButtonBox::Ok) ->setEnabled(!newText.isEmpty() && !ui->passTextBox->text().isEmpty() && !ui->authlibInjectorTextBox->text().isEmpty()); } void AuthlibInjectorLoginDialog::on_authlibInjectorTextBox_textEdited(const QString& newText) { ui->buttonBox->button(QDialogButtonBox::Ok) ->setEnabled(!newText.isEmpty() && !ui->passTextBox->text().isEmpty() && !ui->authlibInjectorTextBox->text().isEmpty()); } void AuthlibInjectorLoginDialog::onTaskFailed(const QString& reason) { // Set message auto lines = reason.split('\n'); QString processed; for (auto line : lines) { if (line.size()) { processed += "" + line + "
"; } else { processed += "
"; } } ui->label->setText(processed); // Re-enable user-interaction setUserInputsEnabled(true); ui->loadingLabel->setVisible(false); } void AuthlibInjectorLoginDialog::onUrlTaskSucceeded() { m_account = m_createAuthlibInjectorAccountTask->getAccount(); m_loginTask = m_account->login(false, ui->passTextBox->text()); connect(m_loginTask.get(), &Task::failed, this, &AuthlibInjectorLoginDialog::onTaskFailed); connect(m_loginTask.get(), &Task::succeeded, this, &AuthlibInjectorLoginDialog::onTaskSucceeded); connect(m_loginTask.get(), &Task::status, this, &AuthlibInjectorLoginDialog::onTaskStatus); m_loginTask->start(); } void AuthlibInjectorLoginDialog::onTaskSucceeded() { QDialog::accept(); } void AuthlibInjectorLoginDialog::onTaskStatus(const QString& status) { ui->label->setText(status); } // Public interface MinecraftAccountPtr AuthlibInjectorLoginDialog::newAccount(QWidget* parent, QString msg) { AuthlibInjectorLoginDialog dlg(parent); dlg.ui->label->setText(msg); if (dlg.exec() == QDialog::Accepted) { return dlg.m_account; } return nullptr; }