From 0d5d1ae4e69024fa97d6204fcfc30a0b12555dc4 Mon Sep 17 00:00:00 2001 From: Glavo Date: Wed, 13 Aug 2025 15:37:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=20authlib-injector=20=E5=B5=8C?= =?UTF-8?q?=E5=85=A5=E5=90=AF=E5=8A=A8=E5=99=A8=20(#4246)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- HMCL/build.gradle.kts | 9 +++ .../org/jackhuang/hmcl/setting/Accounts.java | 39 +++------- .../AuthlibInjectorExtractor.java | 78 +++++++++++++++++++ gradle/libs.versions.toml | 2 + 4 files changed, 99 insertions(+), 29 deletions(-) create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/auth/authlibinjector/AuthlibInjectorExtractor.java diff --git a/HMCL/build.gradle.kts b/HMCL/build.gradle.kts index 762abe702..3040165c8 100644 --- a/HMCL/build.gradle.kts +++ b/HMCL/build.gradle.kts @@ -37,6 +37,8 @@ val launcherExe = System.getenv("HMCL_LAUNCHER_EXE") version = "$versionRoot.$buildNumber" +val embedResources by configurations.registering + dependencies { implementation(project(":HMCLCore")) implementation(project(":HMCLBoot")) @@ -47,6 +49,8 @@ dependencies { if (launcherExe == null) { implementation(libs.hmclauncher) } + + embedResources(libs.authlib.injector) } fun digest(algorithm: String, bytes: ByteArray): ByteArray = MessageDigest.getInstance(algorithm).digest(bytes) @@ -132,6 +136,10 @@ tasks.shadowJar { exclude(project(":HMCLBoot")) } + into("assets/") { + from(embedResources) + } + manifest { attributes( "Created-By" to "Copyright(c) 2013-2025 huangyuhui.", @@ -141,6 +149,7 @@ tasks.shadowJar { "Microsoft-Auth-Id" to microsoftAuthId, "Microsoft-Auth-Secret" to microsoftAuthSecret, "CurseForge-Api-Key" to curseForgeApiKey, + "Authlib-Injector-Version" to libs.authlib.injector.get().version!!, "Build-Channel" to versionType, "Class-Path" to "pack200.jar", "Add-Opens" to listOf( diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Accounts.java b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Accounts.java index 02b6ba6bc..97379cf75 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/setting/Accounts.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/setting/Accounts.java @@ -36,6 +36,7 @@ import org.jackhuang.hmcl.auth.yggdrasil.RemoteAuthenticationException; import org.jackhuang.hmcl.game.OAuthServer; import org.jackhuang.hmcl.task.Schedulers; import org.jackhuang.hmcl.util.FileSaver; +import org.jackhuang.hmcl.util.io.JarUtils; import org.jackhuang.hmcl.util.skin.InvalidSkinException; import javax.net.ssl.SSLException; @@ -68,18 +69,6 @@ public final class Accounts { private static final AuthlibInjectorArtifactProvider AUTHLIB_INJECTOR_DOWNLOADER = createAuthlibInjectorArtifactProvider(); - private static void triggerAuthlibInjectorUpdateCheck() { - if (AUTHLIB_INJECTOR_DOWNLOADER instanceof AuthlibInjectorDownloader) { - Schedulers.io().execute(() -> { - try { - ((AuthlibInjectorDownloader) AUTHLIB_INJECTOR_DOWNLOADER).checkUpdate(); - } catch (IOException e) { - LOG.warning("Failed to check update for authlib-injector", e); - } - }); - } - } - public static final OAuthServer.Factory OAUTH_CALLBACK = new OAuthServer.Factory(); public static final OfflineAccountFactory FACTORY_OFFLINE = new OfflineAccountFactory(AUTHLIB_INJECTOR_DOWNLOADER); @@ -337,8 +326,6 @@ public final class Accounts { }); } - triggerAuthlibInjectorUpdateCheck(); - for (AuthlibInjectorServer server : config().getAuthlibInjectorServers()) { if (selected instanceof AuthlibInjectorAccount && ((AuthlibInjectorAccount) selected).getServer() == server) continue; @@ -371,24 +358,18 @@ public final class Accounts { // ==== authlib-injector ==== private static AuthlibInjectorArtifactProvider createAuthlibInjectorArtifactProvider() { String authlibinjectorLocation = System.getProperty("hmcl.authlibinjector.location"); - if (authlibinjectorLocation == null) { - return new AuthlibInjectorDownloader( - Metadata.DEPENDENCIES_DIRECTORY.resolve("universal").resolve("authlib-injector.jar"), - DownloadProviders::getDownloadProvider) { - @Override - public Optional getArtifactInfoImmediately() { - Optional local = super.getArtifactInfoImmediately(); - if (local.isPresent()) { - return local; - } - // search authlib-injector.jar in current directory, it's used as a fallback - return parseArtifact(Metadata.CURRENT_DIRECTORY.resolve("authlib-injector.jar")); - } - }; - } else { + if (authlibinjectorLocation != null) { LOG.info("Using specified authlib-injector: " + authlibinjectorLocation); return new SimpleAuthlibInjectorArtifactProvider(Paths.get(authlibinjectorLocation)); } + + String authlibInjectorVersion = JarUtils.getManifestAttribute("Authlib-Injector-Version", null); + if (authlibInjectorVersion == null) + throw new AssertionError("Missing Authlib-Injector-Version"); + + String authlibInjectorFileName = "authlib-injector-" + authlibInjectorVersion + ".jar"; + return new AuthlibInjectorExtractor(Accounts.class.getResource("/assets/" + authlibInjectorFileName), + Metadata.DEPENDENCIES_DIRECTORY.resolve("universal").resolve(authlibInjectorFileName)); } private static AuthlibInjectorServer getOrCreateAuthlibInjectorServer(String url) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/authlibinjector/AuthlibInjectorExtractor.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/authlibinjector/AuthlibInjectorExtractor.java new file mode 100644 index 000000000..06ab1479c --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/authlibinjector/AuthlibInjectorExtractor.java @@ -0,0 +1,78 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2025 huangyuhui and contributors + * + * 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, either version 3 of the License, or + * (at your option) any later version. + * + * 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 . + */ +package org.jackhuang.hmcl.auth.authlibinjector; + +import org.jackhuang.hmcl.util.io.FileUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Optional; + +import static org.jackhuang.hmcl.util.logging.Logger.LOG; + +/** + * @author Glavo + */ +public final class AuthlibInjectorExtractor implements AuthlibInjectorArtifactProvider { + private final URL source; + private final Path artifactLocation; + + public AuthlibInjectorExtractor(URL source, Path artifactLocation) { + if (source == null) + throw new IllegalArgumentException("Missing authlib injector"); + this.source = source; + this.artifactLocation = artifactLocation; + } + + @Override + public AuthlibInjectorArtifactInfo getArtifactInfo() throws IOException { + Optional cached = getArtifactInfoImmediately(); + if (cached.isPresent()) + return cached.get(); + + synchronized (this) { + cached = getArtifactInfoImmediately(); + if (cached.isPresent()) + return cached.get(); + + LOG.info("No local authlib-injector found, extracting"); + Files.createDirectories(artifactLocation.getParent()); + try (InputStream inputStream = source.openStream()) { + FileUtils.saveSafely(artifactLocation, inputStream::transferTo); + } + return getArtifactInfoImmediately().orElseThrow(() -> + new IOException("Failed to extract authlib-injector artifact")); + } + } + + @Override + public Optional getArtifactInfoImmediately() { + if (!Files.isRegularFile(artifactLocation)) + return Optional.empty(); + + try { + return Optional.of(AuthlibInjectorArtifactInfo.from(artifactLocation)); + } catch (IOException e) { + LOG.warning("Bad authlib-injector artifact", e); + return Optional.empty(); + } + } +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d66c5d3e5..17aa1942d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -16,6 +16,7 @@ twelvemonkeys = "3.12.0" jna = "5.17.0" pci-ids = "0.4.0" java-info = "1.0" +authlib-injector = "1.2.5" # testing junit = "5.13.4" @@ -43,6 +44,7 @@ jna = { module = "net.java.dev.jna:jna", version.ref = "jna" } jna-platform = { module = "net.java.dev.jna:jna-platform", version.ref = "jna" } pci-ids = { module = "org.glavo:pci-ids", version.ref = "pci-ids" } java-info = { module = "org.glavo:java-info", version.ref = "java-info" } +authlib-injector = { module = "org.glavo.hmcl:authlib-injector", version.ref = "authlib-injector" } # testing junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit" }