Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -218,10 +218,7 @@ set(Launcher_BUILD_ARTIFACT "" CACHE STRING "Artifact name to help the updater i
set(Launcher_META_URL "https://meta.prismlauncher.org/v1/" CACHE STRING "URL to fetch Launcher's meta files from.")

# Ely.by metadata URL
set(Launcher_EPL_META_URL "https://freesmlauncher.org/metadata/epl_metadata.json" CACHE STRING "URL to fetch Ely authlibs metadata")

# Ely.by metadata fallback URL
set(Launcher_EPL_META_FALLBACK_URL "https://raw.githubusercontent.com/FreesmTeam/FreesmLauncher/refs/heads/develop/epl_metadata.json" CACHE STRING "Fallback URL to fetch Ely authlibs metadata")
set(Launcher_EPL_META_URL "https://freesmlauncher.org/metadata/" CACHE STRING "URL to fetch Ely authlibs metadata")

# Imgur API Client ID
set(Launcher_IMGUR_CLIENT_ID "5b97b0713fba4a3" CACHE STRING "Client ID you can get from Imgur when you register an application")
Expand Down
1 change: 0 additions & 1 deletion buildconfig/BuildConfig.cpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,6 @@ Config::Config()
FLAME_API_KEY = "@Launcher_CURSEFORGE_API_KEY@";
META_URL = "@Launcher_META_URL@";
EPL_META_URL = "@Launcher_EPL_META_URL@";
EPL_META_FALLBACK_URL = "@Launcher_EPL_META_FALLBACK_URL@";
FMLLIBS_BASE_URL = "@Launcher_FMLLIBS_BASE_URL@";

GLFW_LIBRARY_NAME = "@Launcher_GLFW_LIBRARY_NAME@";
Expand Down
1 change: 0 additions & 1 deletion buildconfig/BuildConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,6 @@ class Config {
QString META_URL;

QString EPL_META_URL;
QString EPL_META_FALLBACK_URL;

QString GLFW_LIBRARY_NAME;
QString OPENAL_LIBRARY_NAME;
Expand Down
9 changes: 7 additions & 2 deletions epl_metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,11 @@
}
},
"extras": {
"authlib-injector": "https://github.com/yushijinhun/authlib-injector/releases/download/v1.2.5/authlib-injector-1.2.5.jar"
"authlib-injector": {
"name": "authlib-injector",
"url": "https://github.com/yushijinhun/authlib-injector/releases/download/v1.2.5/authlib-injector-1.2.5.jar",
"sha256": "3bc9ebdc583b36abd2a65b626c4b9f35f21177fbf42a851606eaaea3fd42ee0f",
"size": 341970
}
}
}
}
19 changes: 19 additions & 0 deletions launcher/Application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
#include "settings/INISettingsObject.h"
#include "settings/Setting.h"

#include "meta/EplMeta.h"
#include "meta/Index.h"
#include "translations/TranslationsModel.h"

Expand Down Expand Up @@ -776,6 +777,16 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
if (!metaUrl.isValid() || (metaUrl.scheme() != "http" && metaUrl.scheme() != "https"))
m_settings->reset("MetaURLOverride");
}
{
// EPL Meta URL
m_settings->registerSetting("EPLMetaURLOverride", "");

QUrl eplMetaUrl(m_settings->get("EPLMetaURLOverride").toString());

// get rid of invalid meta urls
if (!eplMetaUrl.isValid() || eplMetaUrl.scheme() != "https")
m_settings->reset("MetaURLOverride");
}

m_settings->registerSetting("CloseAfterLaunch", false);
m_settings->registerSetting("QuitAfterGameStop", false);
Expand Down Expand Up @@ -1730,6 +1741,14 @@ shared_qobject_ptr<Meta::Index> Application::metadataIndex()
return m_metadataIndex;
}

std::shared_ptr<Meta::EplMeta> Application::eplMetadata()
{
if (!m_eplMetadata) {
m_eplMetadata.reset(new Meta::EplMeta());
}
return m_eplMetadata;
}

void Application::updateCapabilities()
{
m_capabilities = None;
Expand Down
6 changes: 5 additions & 1 deletion launcher/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ class DiscordIntegration;

namespace Meta {
class Index;
}
class EplMeta;
} // namespace Meta

#if defined(APPLICATION)
#undef APPLICATION
Expand Down Expand Up @@ -151,6 +152,8 @@ class Application : public QApplication {

shared_qobject_ptr<Meta::Index> metadataIndex();

std::shared_ptr<Meta::EplMeta> eplMetadata();

void updateCapabilities();

void detectLibraries();
Expand Down Expand Up @@ -252,6 +255,7 @@ class Application : public QApplication {

shared_qobject_ptr<HttpMetaCache> m_metacache;
shared_qobject_ptr<Meta::Index> m_metadataIndex;
std::shared_ptr<Meta::EplMeta> m_eplMetadata;

std::shared_ptr<SettingsObject> m_settings;
std::shared_ptr<InstanceList> m_instances;
Expand Down
2 changes: 2 additions & 0 deletions launcher/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,8 @@ set(META_SOURCES
meta/Version.h
meta/Index.cpp
meta/Index.h
meta/EplMeta.cpp
meta/EplMeta.h
)

set(API_SOURCES
Expand Down
65 changes: 65 additions & 0 deletions launcher/meta/EplMeta.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Freesm Launcher - Minecraft Launcher
* Copyright (C) 2025 so5iso4ka <[email protected]>
*
* 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 <https://www.gnu.org/licenses/>.
*/

#include "Application.h"
#include "BuildConfig.h"
#include "JsonFormat.h"

#include "EplMeta.h"

QUrl Meta::EplMeta::url() const
{
auto s = APPLICATION->settings();
QString metaOverride = s->get("EPLMetaURLOverride").toString();
if (metaOverride.isEmpty()) {
return QUrl(BuildConfig.EPL_META_URL).resolved(localFilename());
}
return QUrl(metaOverride).resolved(localFilename());
}

void Meta::EplMeta::parse(const QJsonObject& obj)
{
const auto overrides = obj["overrides"].toObject();
const auto authlibs = overrides["com.mojang:authlib"].toObject();
const auto extras = obj["extras"].toObject();
if (authlibs.isEmpty() || extras.isEmpty()) {
throw ParseException(QObject::tr("Invalid EPL metadata"));
}

for (auto it = authlibs.constBegin(); it != authlibs.constEnd(); ++it) {
m_authlibs[it.key()] = it.value().toObject();
}
m_authlibInjector = extras["authlib-injector"].toObject();

if (m_authlibs.empty() || m_authlibInjector.isEmpty()) {
throw ParseException(QObject::tr("Invalid EPL metadata"));
}
}

QJsonObject Meta::EplMeta::overrideFromVersion(const QString& version)
{
if (const auto it = m_authlibs.find(version); it != m_authlibs.end()) {
return it->second;
}
return {};
}

QJsonObject Meta::EplMeta::authlibInjector()
{
return m_authlibInjector;
}
41 changes: 41 additions & 0 deletions launcher/meta/EplMeta.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Freesm Launcher - Minecraft Launcher
* Copyright (C) 2025 so5iso4ka <[email protected]>
*
* 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 <https://www.gnu.org/licenses/>.
*/

#pragma once

#include <unordered_map>

#include "BaseEntity.h"

namespace Meta {

class EplMeta : public BaseEntity {
public:
QString localFilename() const override { return "epl_metadata.json"; }
QUrl url() const override;

void parse(const QJsonObject& obj) override;

QJsonObject overrideFromVersion(const QString& version);
QJsonObject authlibInjector();

private:
std::unordered_map<QString, QJsonObject> m_authlibs;
QJsonObject m_authlibInjector;
};
} // namespace Meta
2 changes: 1 addition & 1 deletion launcher/minecraft/MinecraftInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1202,7 +1202,7 @@ shared_qobject_ptr<LaunchTask> MinecraftInstance::createLaunchTask(AuthSessionPt
if (!session->demo) {
process->appendStep(makeShared<ClaimAccount>(pptr, session));
}
process->appendStep(makeShared<ApplyLibraryOverrides>(pptr, session));
process->appendStep(makeShared<ApplyLibraryOverrides>(pptr));
if (session->wants_authlib_injector) {
process->appendStep(makeShared<ApplyAuthlibInjector>(pptr, session));
}
Expand Down
68 changes: 57 additions & 11 deletions launcher/minecraft/launch/ApplyAuthlibInjector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,28 +20,74 @@

#include "Application.h"
#include "launch/LaunchTask.h"
#include "meta/EplMeta.h"

ApplyAuthlibInjector::ApplyAuthlibInjector(LaunchTask* parent, AuthSessionPtr session)
: LaunchStep(parent), m_session(session), m_instance(m_parent->instance())
{}
ApplyAuthlibInjector::ApplyAuthlibInjector(LaunchTask* parent, const AuthSessionPtr& session) : LaunchStep(parent), m_session(session) {}

void ApplyAuthlibInjector::executeTask()
{
const QString downloadUrl = "https://github.com/yushijinhun/authlib-injector/releases/download/v1.2.5/authlib-injector-1.2.5.jar";
m_request = Net::Download::makeFile(downloadUrl, "authlib-injector.jar");
auto meta = APPLICATION->eplMetadata();
if (meta->isLoaded())
return onRequestDone();

m_task.reset(new NetJob("Download authlib-injector", APPLICATION->network()));
m_task->addNetAction(m_request);
m_metaTask = meta->loadTask();
connect(m_metaTask.get(), &Task::succeeded, this, &ApplyAuthlibInjector::onRequestDone);
connect(m_metaTask.get(), &Task::failed, this, [this] {
emit logLine(tr("Couldn't fetch EPL metadata from %1").arg(APPLICATION->eplMetadata()->url().toString()), MessageLevel::Error);
emitFailed(tr("Couldn't fetch EPL metadata"));
});
connect(m_metaTask.get(), &Task::aborted, this, [this] { emitFailed(tr("Aborted")); });

connect(m_task.get(), &NetJob::succeeded, this, &ApplyAuthlibInjector::onRequestDone);
connect(m_task.get(), &NetJob::failed, this, &ApplyAuthlibInjector::emitFailed);
connect(m_task.get(), &NetJob::aborted, this, [this] { emitFailed(tr("Aborted")); });
if (!m_metaTask->isRunning()) {
m_metaTask->start();
}
}

void ApplyAuthlibInjector::downloadFile()
{
const QString downloadUrl = APPLICATION->eplMetadata()->authlibInjector()["url"].toString();
auto request = Net::Download::makeFile(downloadUrl, "authlib-injector.jar");

m_netTask.reset(new NetJob("Download authlib-injector", APPLICATION->network()));
m_netTask->addNetAction(request);

m_task->start();
connect(m_netTask.get(), &NetJob::succeeded, this, &ApplyAuthlibInjector::onRequestDone);
connect(m_netTask.get(), &NetJob::failed, this, [this](QString reason) {
emit logLine(tr("Couldn't load authlib-injector: %1").arg(std::move(reason)), MessageLevel::Error);
emitFailed(tr("Download failed"));
});
connect(m_netTask.get(), &NetJob::aborted, this, [this] { emitFailed(tr("Aborted")); });

m_netTask->start();
}

void ApplyAuthlibInjector::onRequestDone()
{
if (!checkFile()) {
if (m_netTask != nullptr) {
emit logLine(tr("The checksum of the downloaded file does not match."), MessageLevel::Error);
emitFailed(tr("Checksum mismatch"));
return;
}

return downloadFile();
}

m_session->authlib_injector_ready = true;

emitSucceeded();
}

bool ApplyAuthlibInjector::checkFile()
{
const auto authlibInjector = APPLICATION->eplMetadata()->authlibInjector();

QFile file("authlib-injector.jar");
file.open(QIODevice::ReadOnly);
if (!file.exists() || !file.isOpen() ||
QCryptographicHash::hash(file.readAll(), QCryptographicHash::Sha256).toHex() != authlibInjector["sha256"].toString()) {
return false;
}

return true;
}
22 changes: 11 additions & 11 deletions launcher/minecraft/launch/ApplyAuthlibInjector.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,28 @@

#pragma once

#include <launch/LaunchStep.h>
#include <minecraft/auth/BaseAccount.h>
#include "minecraft/MinecraftInstance.h"
#include "net/Download.h"
#include "launch/LaunchStep.h"
#include "meta/BaseEntity.h"
#include "minecraft/auth/AuthSession.h"
#include "net/NetJob.h"

class ApplyAuthlibInjector : public LaunchStep {
Q_OBJECT
public:
explicit ApplyAuthlibInjector(LaunchTask* parent, AuthSessionPtr session);
virtual ~ApplyAuthlibInjector() = default;
explicit ApplyAuthlibInjector(LaunchTask* parent, const AuthSessionPtr& session);
~ApplyAuthlibInjector() override = default;

void executeTask() override;
bool canAbort() const override { return false; }

public slots:
private slots:
void onRequestDone();

private:
void downloadFile();
static bool checkFile();

AuthSessionPtr m_session;
MinecraftInstancePtr m_instance;
std::shared_ptr<QByteArray> m_response = std::make_shared<QByteArray>();
Net::Download::Ptr m_request;
NetJob::Ptr m_task;
Meta::BaseEntityLoadTask::Ptr m_metaTask;
NetJob::Ptr m_netTask;
};
Loading
Loading