diff --git a/src/main/java/com/osiris/autoplug/client/configs/UpdaterConfig.java b/src/main/java/com/osiris/autoplug/client/configs/UpdaterConfig.java index 45437a41..5c8cd00c 100644 --- a/src/main/java/com/osiris/autoplug/client/configs/UpdaterConfig.java +++ b/src/main/java/com/osiris/autoplug/client/configs/UpdaterConfig.java @@ -28,6 +28,7 @@ public class UpdaterConfig extends MyYaml { public YamlSection self_updater; public YamlSection self_updater_profile; public YamlSection self_updater_build; + public YamlSection self_updater_safe_mode; public YamlSection java_updater; public YamlSection java_updater_profile; @@ -35,6 +36,7 @@ public class UpdaterConfig extends MyYaml { public YamlSection java_updater_version; public YamlSection java_updater_build_id; public YamlSection java_updater_large_heap; + public YamlSection java_updater_force_enable; public YamlSection server_updater; public YamlSection server_updater_profile; @@ -125,6 +127,10 @@ public UpdaterConfig() throws IOException, DuplicateKeyException, YamlReaderExce self_updater_build = put(name, "self-updater", "build").setDefValues("stable").setComments( "Choose between 'stable' and 'beta' builds.", "Stable builds are recommended."); + self_updater_safe_mode = put(name, "self-updater", "safe-mode").setDefValues("true").setComments( + "If AutoPlug is disabled, it will update itself without advanced compatibility. Self-updating on Ptero will work in the same way as it does when not on Ptero.", + "Its strongly recommended to have this feature enabled on non AutoPlug specific eggs," + ); put(name, "java-updater").setCountTopLineBreaks(1); java_updater = put(name, "java-updater", "enable").setDefValues("true"); @@ -141,6 +147,9 @@ public UpdaterConfig() throws IOException, DuplicateKeyException, YamlReaderExce "Otherwise don't touch this. It gets replaced after every successful update automatically."); java_updater_large_heap = put(name, "java-updater", "large-heap").setDefValues("false").setComments( "Only enable if you plan to give your server more than 57gb of ram, otherwise not recommended."); + java_updater_force_enable = put(name, "java-updater", "force-enable").setDefValues("false").setComments( + "If you are running AutoPlug via Pterodactyl Panel, the java-updater is disabled to avoid redundancy. Set to true to force the self-updater to run anyways." + ); put(name, "server-updater").setCountTopLineBreaks(1); diff --git a/src/main/java/com/osiris/autoplug/client/tasks/updater/TaskDownload.java b/src/main/java/com/osiris/autoplug/client/tasks/updater/TaskDownload.java index 8a88b186..8f79aefa 100644 --- a/src/main/java/com/osiris/autoplug/client/tasks/updater/TaskDownload.java +++ b/src/main/java/com/osiris/autoplug/client/tasks/updater/TaskDownload.java @@ -22,6 +22,7 @@ import java.io.File; import java.io.FileOutputStream; import java.util.Arrays; +import java.util.Locale; import java.util.Random; public class TaskDownload extends BThread { @@ -76,18 +77,8 @@ public void runAtStart() throws Exception { body = response.body(); if (body == null) throw new Exception("Download of '" + dest.getName() + "' failed because of null response body!"); - else if (!ignoreContentType && body.contentType() == null) - throw new Exception("Download of '" + dest.getName() + "' failed due to null content type!"); - else if (!ignoreContentType && !body.contentType().type().equals("application")) - throw new Exception("Download of '" + dest.getName() + "' failed because of invalid content type: " + body.contentType().type()); - else if (!ignoreContentType && !body.contentType().subtype().equals("java-archive") - && !body.contentType().subtype().equals("jar") - && !body.contentType().subtype().equals("octet-stream")) { - if (allowedSubContentTypes == null) - throw new Exception("Download of '" + dest.getName() + "' failed because of invalid sub-content type: " + body.contentType().subtype()); - if (!Arrays.asList(allowedSubContentTypes).contains(body.contentType().subtype())) - throw new Exception("Download of '" + dest.getName() + "' failed because of invalid sub-content type: " + body.contentType().subtype()); - } + if (!isAllowedContentType(fileName, body.contentType(), ignoreContentType, allowedSubContentTypes)) + throw new Exception("Download of '" + dest.getName() + "' failed because of invalid content type: " + body.contentType()); long completeFileSize = body.contentLength(); setMax(completeFileSize); @@ -151,4 +142,20 @@ public boolean compareWithSHA256(String expectedHash) { return result; } + static boolean isAllowedContentType(String fileName, okhttp3.MediaType contentType, boolean ignoreContentType, String... allowedSubContentTypes) { + if (ignoreContentType) return true; + if (contentType == null) return false; + String type = contentType.type(); + String subtype = contentType.subtype(); + if ("application".equals(type)) { + if ("java-archive".equals(subtype) || "jar".equals(subtype) || "octet-stream".equals(subtype)) return true; + if (allowedSubContentTypes == null) return false; + return Arrays.asList(allowedSubContentTypes).contains(subtype); + } + return fileName != null + && fileName.toLowerCase(Locale.ROOT).endsWith(".jar") + && "text".equals(type) + && "plain".equals(subtype); + } + } diff --git a/src/main/java/com/osiris/autoplug/client/tasks/updater/java/TaskJavaUpdater.java b/src/main/java/com/osiris/autoplug/client/tasks/updater/java/TaskJavaUpdater.java index 9ce92741..73084a2d 100644 --- a/src/main/java/com/osiris/autoplug/client/tasks/updater/java/TaskJavaUpdater.java +++ b/src/main/java/com/osiris/autoplug/client/tasks/updater/java/TaskJavaUpdater.java @@ -14,6 +14,7 @@ import com.osiris.autoplug.client.Server; import com.osiris.autoplug.client.configs.UpdaterConfig; import com.osiris.autoplug.client.utils.GD; +import com.osiris.autoplug.client.utils.UtilsEnvironment; import com.osiris.betterthread.BThread; import com.osiris.betterthread.BThreadManager; import com.osiris.jlib.logger.AL; @@ -45,12 +46,12 @@ public void runAtStart() throws Exception { skip(); return; } - if (Server.isRunning()) throw new Exception("Cannot perform update while server is running!"); - - if (!updaterConfig.java_updater.asBoolean()) { + if (new UtilsEnvironment().isPterodactylEnvironment() && !updaterConfig.java_updater_force_enable.asBoolean()) { + setStatus("Java updater disabled on Pterodactyl-managed servers."); skip(); return; } + if (Server.isRunning()) throw new Exception("Cannot perform update while server is running!"); setStatus("Searching for updates..."); diff --git a/src/main/java/com/osiris/autoplug/client/tasks/updater/self/TaskSelfUpdater.java b/src/main/java/com/osiris/autoplug/client/tasks/updater/self/TaskSelfUpdater.java index 379546a9..66cd2ecd 100644 --- a/src/main/java/com/osiris/autoplug/client/tasks/updater/self/TaskSelfUpdater.java +++ b/src/main/java/com/osiris/autoplug/client/tasks/updater/self/TaskSelfUpdater.java @@ -15,6 +15,7 @@ import com.osiris.autoplug.client.managers.FileManager; import com.osiris.autoplug.client.tasks.updater.TaskDownload; import com.osiris.autoplug.client.utils.GD; +import com.osiris.autoplug.client.utils.UtilsEnvironment; import com.osiris.autoplug.client.utils.UtilsJar; import com.osiris.betterthread.BThread; import com.osiris.betterthread.BThreadManager; @@ -160,6 +161,18 @@ private void doUpdating(String url) throws Exception { finish("Downloaded AutoPlug update is broken. Nothing changed!", false); return; } + boolean isPterodactyl = new UtilsEnvironment().isPterodactylEnvironment(); + if (isPterodactyl && updaterConfig.self_updater_safe_mode.asBoolean()) { + File currentJarFile = currentInstallationPath != null + ? FileManager.convertRelativeToAbsolutePath(currentInstallationPath) + : new UtilsJar().getThisJar(); + setStatus("Installing AutoPlug update in place (" + currentVersion + " -> " + version + ")..."); + Files.copy(cache_dest.toPath(), currentJarFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + setStatus("AutoPlug update was installed successfully (" + currentVersion + " -> " + version + ")!"); + finish(true); + System.exit(0); + return; + } setStatus("Installing AutoPlug update (" + currentVersion + " -> " + version + ")..."); // Create the actual update copy file, by simply copying the newly downloaded file. Files.copy(cache_dest.toPath(), @@ -180,5 +193,3 @@ private void doUpdating(String url) throws Exception { } } - - diff --git a/src/main/java/com/osiris/autoplug/client/utils/UtilsEnvironment.java b/src/main/java/com/osiris/autoplug/client/utils/UtilsEnvironment.java new file mode 100644 index 00000000..10fa5642 --- /dev/null +++ b/src/main/java/com/osiris/autoplug/client/utils/UtilsEnvironment.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2026 Osiris-Team. + * All rights reserved. + * + * This software is copyrighted work, licensed under the terms + * of the MIT-License. Consult the "LICENSE" file for details. + */ + +package com.osiris.autoplug.client.utils; + +import java.util.Locale; +import java.util.Map; + +public class UtilsEnvironment { + public boolean isPterodactylEnvironment() { + return isPterodactylEnvironment(System.getenv()); + } + + public boolean isPterodactylEnvironment(Map env) { + for (String key : env.keySet()) { + if (key == null) continue; + String upperKey = key.toUpperCase(Locale.ROOT); + if (upperKey.startsWith("PTERODACTYL_")) return true; + if (upperKey.startsWith("P_SERVER_")) return true; + } + return false; + } +} diff --git a/src/test/java/com/osiris/autoplug/client/utils/UtilsEnvironmentTest.java b/src/test/java/com/osiris/autoplug/client/utils/UtilsEnvironmentTest.java new file mode 100644 index 00000000..6c9e34ce --- /dev/null +++ b/src/test/java/com/osiris/autoplug/client/utils/UtilsEnvironmentTest.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2026 Osiris-Team. + * All rights reserved. + * + * This software is copyrighted work, licensed under the terms + * of the MIT-License. Consult the "LICENSE" file for details. + */ + +package com.osiris.autoplug.client.utils; + +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class UtilsEnvironmentTest { + @Test + void detectsPterodactylEnvVars() { + UtilsEnvironment utilsEnvironment = new UtilsEnvironment(); + + Map env = new HashMap<>(); + env.put("P_SERVER_UUID", "abc"); + assertTrue(utilsEnvironment.isPterodactylEnvironment(env)); + + env.clear(); + env.put("PTERODACTYL_SERVER_UUID", "abc"); + assertTrue(utilsEnvironment.isPterodactylEnvironment(env)); + } + + @Test + void ignoresNonPterodactylEnvVars() { + UtilsEnvironment utilsEnvironment = new UtilsEnvironment(); + + Map env = new HashMap<>(); + env.put("SERVER_UUID", "abc"); + env.put("PANEL_NAME", "AutoPlug"); + assertFalse(utilsEnvironment.isPterodactylEnvironment(env)); + } +}