aboutsummaryrefslogtreecommitdiff
path: root/launcher
diff options
context:
space:
mode:
authorLenny McLennington <lennymclennington@protonmail.com>2022-05-11 21:44:06 +0100
committerLenny McLennington <lennymclennington@protonmail.com>2022-05-21 17:28:22 +0100
commit35f71f5793ee91a71e00464932ff95eb5e5e4d5e (patch)
tree8924109e69d861f9995c901111888de5f00b5474 /launcher
parent9a0d6124f3f6ec6d68fb25aa7df6eb9e226bc201 (diff)
downloadPrismLauncher-35f71f5793ee91a71e00464932ff95eb5e5e4d5e.tar.gz
PrismLauncher-35f71f5793ee91a71e00464932ff95eb5e5e4d5e.tar.bz2
PrismLauncher-35f71f5793ee91a71e00464932ff95eb5e5e4d5e.zip
Support paste.gg, hastebin, and mclo.gs
Diffstat (limited to 'launcher')
-rw-r--r--launcher/Application.cpp33
-rw-r--r--launcher/net/PasteUpload.cpp165
-rw-r--r--launcher/net/PasteUpload.h28
-rw-r--r--launcher/ui/GuiUtil.cpp5
-rw-r--r--launcher/ui/pages/global/APIPage.cpp51
-rw-r--r--launcher/ui/pages/global/APIPage.h1
-rw-r--r--launcher/ui/pages/global/APIPage.ui62
7 files changed, 271 insertions, 74 deletions
diff --git a/launcher/Application.cpp b/launcher/Application.cpp
index ce62c41a..b36fd89a 100644
--- a/launcher/Application.cpp
+++ b/launcher/Application.cpp
@@ -36,6 +36,7 @@
#include "Application.h"
#include "BuildConfig.h"
+#include "net/PasteUpload.h"
#include "ui/MainWindow.h"
#include "ui/InstanceWindow.h"
@@ -671,8 +672,36 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
m_settings->registerSetting("UpdateDialogGeometry", "");
- // pastebin URL
- m_settings->registerSetting("PastebinURL", "https://0x0.st");
+ // This code feels so stupid is there a less stupid way of doing this?
+ {
+ m_settings->registerSetting("PastebinURL", "");
+ QString pastebinURL = m_settings->get("PastebinURL").toString();
+
+ // If PastebinURL hasn't been set before then use the new default: mclo.gs
+ if (pastebinURL == "") {
+ m_settings->registerSetting("PastebinType", PasteUpload::PasteType::Mclogs);
+ m_settings->registerSetting("PastebinCustomAPIBase", "");
+ }
+ // Otherwise: use 0x0.st
+ else {
+ // The default custom endpoint would usually be "" (meaning there is no custom endpoint specified)
+ // But if the user had customised the paste URL then that should be carried over into the custom endpoint.
+ QString defaultCustomEndpoint = (pastebinURL == "https://0x0.st") ? "" : pastebinURL;
+ m_settings->registerSetting("PastebinType", PasteUpload::PasteType::NullPointer);
+ m_settings->registerSetting("PastebinCustomAPIBase", defaultCustomEndpoint);
+
+ m_settings->reset("PastebinURL");
+ }
+
+ bool ok;
+ unsigned int pasteType = m_settings->get("PastebinType").toUInt(&ok);
+ // If PastebinType is invalid then reset the related settings.
+ if (!ok || !(PasteUpload::PasteType::First <= pasteType && pasteType <= PasteUpload::PasteType::Last))
+ {
+ m_settings->reset("PastebinType");
+ m_settings->reset("PastebinCustomAPIBase");
+ }
+ }
m_settings->registerSetting("CloseAfterLaunch", false);
m_settings->registerSetting("QuitAfterGameStop", false);
diff --git a/launcher/net/PasteUpload.cpp b/launcher/net/PasteUpload.cpp
index 3d106c92..d583216d 100644
--- a/launcher/net/PasteUpload.cpp
+++ b/launcher/net/PasteUpload.cpp
@@ -42,8 +42,22 @@
#include <QJsonDocument>
#include <QFile>
-PasteUpload::PasteUpload(QWidget *window, QString text, QString url) : m_window(window), m_uploadUrl(url), m_text(text.toUtf8())
+std::array<PasteUpload::PasteTypeInfo, 4> PasteUpload::PasteTypes = {
+ {{"0x0", "https://0x0.st", ""},
+ {"hastebin", "https://hastebin.com", "/documents"},
+ {"paste (paste.gg)", "https://paste.gg", "/api/v1/pastes"},
+ {"mclogs", "https://api.mclo.gs", "/1/log"}}};
+
+PasteUpload::PasteUpload(QWidget *window, QString text, QString baseUrl, PasteType pasteType) : m_window(window), m_baseUrl(baseUrl), m_pasteType(pasteType), m_text(text.toUtf8())
{
+ if (m_baseUrl == "")
+ m_baseUrl = PasteTypes.at(pasteType).defaultBase;
+
+ // HACK: Paste's docs say the standard API path is at /api/<version> but the official instance paste.gg doesn't follow that??
+ if (pasteType == PasteGG && m_baseUrl == PasteTypes.at(pasteType).defaultBase)
+ m_uploadUrl = "https://api.paste.gg/v1/pastes";
+ else
+ m_uploadUrl = m_baseUrl + PasteTypes.at(pasteType).endpointPath;
}
PasteUpload::~PasteUpload()
@@ -53,26 +67,73 @@ PasteUpload::~PasteUpload()
void PasteUpload::executeTask()
{
QNetworkRequest request{QUrl(m_uploadUrl)};
+ QNetworkReply *rep{};
+
request.setHeader(QNetworkRequest::UserAgentHeader, BuildConfig.USER_AGENT_UNCACHED);
- QHttpMultiPart *multiPart = new QHttpMultiPart{QHttpMultiPart::FormDataType};
+ switch (m_pasteType) {
+ case NullPointer: {
+ QHttpMultiPart *multiPart =
+ new QHttpMultiPart{QHttpMultiPart::FormDataType};
- QHttpPart filePart;
- filePart.setBody(m_text);
- filePart.setHeader(QNetworkRequest::ContentTypeHeader, "text/plain");
- filePart.setHeader(QNetworkRequest::ContentDispositionHeader, "form-data; name=\"file\"; filename=\"log.txt\"");
+ QHttpPart filePart;
+ filePart.setBody(m_text);
+ filePart.setHeader(QNetworkRequest::ContentTypeHeader, "text/plain");
+ filePart.setHeader(QNetworkRequest::ContentDispositionHeader,
+ "form-data; name=\"file\"; filename=\"log.txt\"");
+ multiPart->append(filePart);
- multiPart->append(filePart);
+ rep = APPLICATION->network()->post(request, multiPart);
+ multiPart->setParent(rep);
- QNetworkReply *rep = APPLICATION->network()->post(request, multiPart);
- multiPart->setParent(rep);
+ break;
+ }
+ case Hastebin: {
+ request.setHeader(QNetworkRequest::UserAgentHeader, BuildConfig.USER_AGENT_UNCACHED);
+ rep = APPLICATION->network()->post(request, m_text);
+ break;
+ }
+ case Mclogs: {
+ QUrlQuery postData;
+ postData.addQueryItem("content", m_text);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
+ rep = APPLICATION->network()->post(request, postData.toString().toUtf8());
+ break;
+ }
+ case PasteGG: {
+ QJsonObject obj;
+ QJsonDocument doc;
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
- m_reply = std::shared_ptr<QNetworkReply>(rep);
- setStatus(tr("Uploading to %1").arg(m_uploadUrl));
+ obj.insert("expires", QDateTime::currentDateTimeUtc().addDays(100).toString(Qt::DateFormat::ISODate));
+
+ QJsonArray files;
+ QJsonObject logFileInfo;
+ QJsonObject logFileContentInfo;
+ logFileContentInfo.insert("format", "text");
+ logFileContentInfo.insert("value", QString::fromUtf8(m_text));
+ logFileInfo.insert("name", "log.txt");
+ logFileInfo.insert("content", logFileContentInfo);
+ files.append(logFileInfo);
+
+ obj.insert("files", files);
+
+ doc.setObject(obj);
+ rep = APPLICATION->network()->post(request, doc.toJson());
+ break;
+ }
+ }
connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress);
- connect(rep, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(downloadError(QNetworkReply::NetworkError)));
- connect(rep, SIGNAL(finished()), this, SLOT(downloadFinished()));
+ connect(rep, &QNetworkReply::finished, this, &PasteUpload::downloadFinished);
+ // This function call would be a lot shorter if we were using the latest Qt
+ connect(rep,
+ static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),
+ this, &PasteUpload::downloadError);
+
+ m_reply = std::shared_ptr<QNetworkReply>(rep);
+
+ setStatus(tr("Uploading to %1").arg(m_uploadUrl));
}
void PasteUpload::downloadError(QNetworkReply::NetworkError error)
@@ -102,6 +163,82 @@ void PasteUpload::downloadFinished()
return;
}
- m_pasteLink = QString::fromUtf8(data).trimmed();
+ switch (m_pasteType)
+ {
+ case NullPointer:
+ m_pasteLink = QString::fromUtf8(data).trimmed();
+ break;
+ case Hastebin: {
+ QJsonDocument jsonDoc{QJsonDocument::fromJson(data)};
+ QJsonObject jsonObj{jsonDoc.object()};
+ if (jsonObj.contains("key") && jsonObj["key"].isString())
+ {
+ QString key = jsonDoc.object()["key"].toString();
+ m_pasteLink = m_baseUrl + "/" + key;
+ }
+ else
+ {
+ emitFailed(tr("Error: %1 returned a malformed response body").arg(m_uploadUrl));
+ qCritical() << m_uploadUrl << " returned malformed response body: " << data;
+ return;
+ }
+ break;
+ }
+ case Mclogs: {
+ QJsonDocument jsonDoc{QJsonDocument::fromJson(data)};
+ QJsonObject jsonObj{jsonDoc.object()};
+ if (jsonObj.contains("success") && jsonObj["success"].isBool())
+ {
+ bool success = jsonObj["success"].toBool();
+ if (success)
+ {
+ m_pasteLink = jsonObj["url"].toString();
+ }
+ else
+ {
+ QString error = jsonObj["error"].toString();
+ emitFailed(tr("Error: %1 returned an error: %2").arg(m_uploadUrl, error));
+ qCritical() << m_uploadUrl << " returned error: " << error;
+ qCritical() << "Response body: " << data;
+ return;
+ }
+ }
+ else
+ {
+ emitFailed(tr("Error: %1 returned a malformed response body").arg(m_uploadUrl));
+ qCritical() << m_uploadUrl << " returned malformed response body: " << data;
+ return;
+ }
+ break;
+ }
+ case PasteGG:
+ QJsonDocument jsonDoc{QJsonDocument::fromJson(data)};
+ QJsonObject jsonObj{jsonDoc.object()};
+ if (jsonObj.contains("status") && jsonObj["status"].isString())
+ {
+ QString status = jsonObj["status"].toString();
+ if (status == "success")
+ {
+ m_pasteLink = m_baseUrl + "/p/anonymous/" + jsonObj["result"].toObject()["id"].toString();
+ }
+ else
+ {
+ QString error = jsonObj["error"].toString();
+ QString message = (jsonObj.contains("message") && jsonObj["message"].isString()) ? jsonObj["message"].toString() : "none";
+ emitFailed(tr("Error: %1 returned an error code: %2\nError message: %3").arg(m_uploadUrl, error, message));
+ qCritical() << m_uploadUrl << " returned error: " << error;
+ qCritical() << "Error message: " << message;
+ qCritical() << "Response body: " << data;
+ return;
+ }
+ }
+ else
+ {
+ emitFailed(tr("Error: %1 returned a malformed response body").arg(m_uploadUrl));
+ qCritical() << m_uploadUrl << " returned malformed response body: " << data;
+ return;
+ }
+ break;
+ }
emitSucceeded();
}
diff --git a/launcher/net/PasteUpload.h b/launcher/net/PasteUpload.h
index ea3a06d3..e276234f 100644
--- a/launcher/net/PasteUpload.h
+++ b/launcher/net/PasteUpload.h
@@ -36,14 +36,38 @@
#include "tasks/Task.h"
#include <QNetworkReply>
+#include <QString>
#include <QBuffer>
#include <memory>
+#include <array>
class PasteUpload : public Task
{
Q_OBJECT
public:
- PasteUpload(QWidget *window, QString text, QString url);
+ enum PasteType : unsigned int {
+ // 0x0.st
+ NullPointer,
+ // hastebin.com
+ Hastebin,
+ // paste.gg
+ PasteGG,
+ // mclo.gs
+ Mclogs,
+ // Helpful to get the range of valid values on the enum for input sanitisation:
+ First = NullPointer,
+ Last = Mclogs
+ };
+
+ struct PasteTypeInfo {
+ const QString name;
+ const QString defaultBase;
+ const QString endpointPath;
+ };
+
+ static std::array<PasteTypeInfo, 4> PasteTypes;
+
+ PasteUpload(QWidget *window, QString text, QString url, PasteType pasteType);
virtual ~PasteUpload();
QString pasteLink()
@@ -56,7 +80,9 @@ protected:
private:
QWidget *m_window;
QString m_pasteLink;
+ QString m_baseUrl;
QString m_uploadUrl;
+ PasteType m_pasteType;
QByteArray m_text;
std::shared_ptr<QNetworkReply> m_reply;
public
diff --git a/launcher/ui/GuiUtil.cpp b/launcher/ui/GuiUtil.cpp
index 9eb658e2..5e9d1eda 100644
--- a/launcher/ui/GuiUtil.cpp
+++ b/launcher/ui/GuiUtil.cpp
@@ -16,8 +16,9 @@
QString GuiUtil::uploadPaste(const QString &text, QWidget *parentWidget)
{
ProgressDialog dialog(parentWidget);
- auto pasteUrlSetting = APPLICATION->settings()->get("PastebinURL").toString();
- std::unique_ptr<PasteUpload> paste(new PasteUpload(parentWidget, text, pasteUrlSetting));
+ auto pasteTypeSetting = static_cast<PasteUpload::PasteType>(APPLICATION->settings()->get("PastebinType").toUInt());
+ auto pasteCustomAPIBaseSetting = APPLICATION->settings()->get("PastebinCustomAPIBase").toString();
+ std::unique_ptr<PasteUpload> paste(new PasteUpload(parentWidget, text, pasteCustomAPIBaseSetting, pasteTypeSetting));
dialog.execWithTask(paste.get());
if (!paste->wasSuccessful())
diff --git a/launcher/ui/pages/global/APIPage.cpp b/launcher/ui/pages/global/APIPage.cpp
index 8b806bcf..b2827a19 100644
--- a/launcher/ui/pages/global/APIPage.cpp
+++ b/launcher/ui/pages/global/APIPage.cpp
@@ -3,6 +3,7 @@
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (c) 2022 Lenny McLennington <lenny@sneed.church>
*
* 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
@@ -46,15 +47,34 @@
#include "settings/SettingsObject.h"
#include "tools/BaseProfiler.h"
#include "Application.h"
+#include "net/PasteUpload.h"
APIPage::APIPage(QWidget *parent) :
QWidget(parent),
ui(new Ui::APIPage)
{
+ // this is here so you can reorder the entries in the combobox without messing stuff up
+ unsigned int comboBoxEntries[] = {
+ PasteUpload::PasteType::Mclogs,
+ PasteUpload::PasteType::NullPointer,
+ PasteUpload::PasteType::PasteGG,
+ PasteUpload::PasteType::Hastebin
+ };
+
static QRegularExpression validUrlRegExp("https?://.+");
+
ui->setupUi(this);
- ui->urlChoices->setValidator(new QRegularExpressionValidator(validUrlRegExp, ui->urlChoices));
- ui->tabWidget->tabBar()->hide();\
+
+ for (auto pasteType : comboBoxEntries) {
+ ui->pasteTypeComboBox->addItem(PasteUpload::PasteTypes.at(pasteType).name, pasteType);
+ }
+
+ connect(ui->pasteTypeComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &APIPage::updateBaseURLPlaceholder);
+ // This function needs to be called even when the ComboBox's index is still in its default state.
+ updateBaseURLPlaceholder(ui->pasteTypeComboBox->currentIndex());
+ ui->baseURLEntry->setValidator(new QRegularExpressionValidator(validUrlRegExp, ui->baseURLEntry));
+ ui->tabWidget->tabBar()->hide();
+
loadSettings();
}
@@ -63,11 +83,28 @@ APIPage::~APIPage()
delete ui;
}
+void APIPage::updateBaseURLPlaceholder(int index)
+{
+ ui->baseURLEntry->setPlaceholderText(PasteUpload::PasteTypes.at(ui->pasteTypeComboBox->itemData(index).toUInt()).defaultBase);
+}
+
void APIPage::loadSettings()
{
auto s = APPLICATION->settings();
- QString pastebinURL = s->get("PastebinURL").toString();
- ui->urlChoices->setCurrentText(pastebinURL);
+
+ unsigned int pasteType = s->get("PastebinType").toUInt();
+ QString pastebinURL = s->get("PastebinCustomAPIBase").toString();
+
+ ui->baseURLEntry->setText(pastebinURL);
+ int pasteTypeIndex = ui->pasteTypeComboBox->findData(pasteType);
+ if (pasteTypeIndex == -1)
+ {
+ pasteTypeIndex = ui->pasteTypeComboBox->findData(PasteUpload::PasteType::Mclogs);
+ ui->baseURLEntry->clear();
+ }
+
+ ui->pasteTypeComboBox->setCurrentIndex(pasteTypeIndex);
+
QString msaClientID = s->get("MSAClientIDOverride").toString();
ui->msaClientID->setText(msaClientID);
QString curseKey = s->get("CFKeyOverride").toString();
@@ -77,8 +114,10 @@ void APIPage::loadSettings()
void APIPage::applySettings()
{
auto s = APPLICATION->settings();
- QString pastebinURL = ui->urlChoices->currentText();
- s->set("PastebinURL", pastebinURL);
+
+ s->set("PastebinType", ui->pasteTypeComboBox->currentData().toUInt());
+ s->set("PastebinCustomAPIBase", ui->baseURLEntry->text());
+
QString msaClientID = ui->msaClientID->text();
s->set("MSAClientIDOverride", msaClientID);
QString curseKey = ui->curseKey->text();
diff --git a/launcher/ui/pages/global/APIPage.h b/launcher/ui/pages/global/APIPage.h
index 20356009..0bb84c89 100644
--- a/launcher/ui/pages/global/APIPage.h
+++ b/launcher/ui/pages/global/APIPage.h
@@ -73,6 +73,7 @@ public:
void retranslate() override;
private:
+ void updateBaseURLPlaceholder(int index);
void loadSettings();
void applySettings();
diff --git a/launcher/ui/pages/global/APIPage.ui b/launcher/ui/pages/global/APIPage.ui
index eaa44c88..d986c2e2 100644
--- a/launcher/ui/pages/global/APIPage.ui
+++ b/launcher/ui/pages/global/APIPage.ui
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
- <width>603</width>
- <height>530</height>
+ <width>512</width>
+ <height>538</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@@ -36,59 +36,30 @@
<item>
<widget class="QGroupBox" name="groupBox_paste">
<property name="title">
- <string>&amp;Pastebin URL</string>
+ <string>Pastebin Service</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
- <widget class="Line" name="line">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
+ <widget class="QLabel" name="pasteServiceTypeLabel">
+ <property name="text">
+ <string>Paste Service Type</string>
</property>
</widget>
</item>
<item>
- <widget class="QLabel" name="label_2">
- <property name="font">
- <font>
- <pointsize>10</pointsize>
- </font>
- </property>
- <property name="text">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Note: only input that starts with &lt;span style=&quot; font-weight:600;&quot;&gt;http://&lt;/span&gt; or &lt;span style=&quot; font-weight:600;&quot;&gt;https://&lt;/span&gt; will be accepted.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="scaledContents">
- <bool>false</bool>
- </property>
- </widget>
+ <widget class="QComboBox" name="pasteTypeComboBox"/>
</item>
<item>
- <widget class="QComboBox" name="urlChoices">
- <property name="editable">
- <bool>true</bool>
- </property>
- <property name="insertPolicy">
- <enum>QComboBox::NoInsert</enum>
+ <widget class="QLabel" name="baseURLLabel">
+ <property name="text">
+ <string>Base URL</string>
</property>
- <item>
- <property name="text">
- <string notr="true">https://0x0.st</string>
- </property>
- </item>
</widget>
</item>
<item>
- <widget class="QLabel" name="label">
- <property name="text">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Here you can choose from a predefined list of paste services, or input the URL of a different paste service of your choice, provided it supports the same protocol as 0x0.st, that is POST a file parameter to the URL and return a link in the response body.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="textFormat">
- <enum>Qt::RichText</enum>
- </property>
- <property name="wordWrap">
- <bool>true</bool>
- </property>
- <property name="openExternalLinks">
- <bool>true</bool>
+ <widget class="QLineEdit" name="baseURLEntry">
+ <property name="placeholderText">
+ <string/>
</property>
</widget>
</item>
@@ -102,13 +73,6 @@
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
- <widget class="Line" name="line_2">
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- </widget>
- </item>
- <item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Note: you probably don't need to set this if logging in via Microsoft Authentication already works.</string>