aboutsummaryrefslogtreecommitdiff
path: root/wrapper
diff options
context:
space:
mode:
Diffstat (limited to 'wrapper')
-rw-r--r--wrapper/build.gradle89
-rwxr-xr-xwrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/DGInterface.java31
-rw-r--r--wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/GuiLoadingError.java84
-rwxr-xr-xwrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java239
-rw-r--r--wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/AuthServerException.java27
-rwxr-xr-xwrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/Authenticator.java253
-rw-r--r--wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/TokenStatus.java27
-rw-r--r--wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/ModDownloader.java302
-rw-r--r--wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/Update.java46
-rw-r--r--wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/UpdateBranch.java29
-rw-r--r--wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/NoSuitableLoaderFoundException.java27
-rw-r--r--wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/PrivacyPolicyRequiredException.java22
-rw-r--r--wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/ReferenceLeakedException.java22
-rw-r--r--wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/TokenExpiredException.java22
-rw-r--r--wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/IDGLoader.java36
-rwxr-xr-xwrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGConnection.java47
-rwxr-xr-xwrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandler.java36
-rwxr-xr-xwrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandlerFactory.java37
-rwxr-xr-xwrapper/src/main/resources/mcmod.info16
19 files changed, 1392 insertions, 0 deletions
diff --git a/wrapper/build.gradle b/wrapper/build.gradle
new file mode 100644
index 00000000..13ea4088
--- /dev/null
+++ b/wrapper/build.gradle
@@ -0,0 +1,89 @@
+
+
+buildscript {
+ repositories {
+ gradlePluginPortal()
+ mavenCentral()
+ maven {
+ name = "forge"
+ url = "https://maven.minecraftforge.net/"
+ }
+ maven { url "https://jitpack.io" }
+ }
+ dependencies {
+ classpath "com.github.Skytils:ForgeGradle:6f5327"
+ classpath "com.github.jengelman.gradle.plugins:shadow:6.1.0"
+ }
+}
+apply plugin: "net.minecraftforge.gradle.forge"
+apply plugin: "com.github.johnrengelman.shadow"
+apply plugin: "java"
+
+
+version = "3.0"
+group = "kr.syeyoung.dungeonsguide"
+archivesBaseName = "dungeonsguide"
+
+sourceCompatibility = targetCompatibility = JavaVersion.VERSION_1_8
+
+tasks.withType(JavaCompile) {
+ options.encoding = "UTF-8"
+}
+
+minecraft {
+ version = "1.8.9-11.15.1.2318-1.8.9"
+ runDir = "run"
+
+ mappings = "stable_22"
+ makeObfSourceJar = false
+}
+
+repositories {
+ mavenCentral()
+ maven { url "https://jitpack.io" }
+}
+dependencies {
+ implementation "org.jetbrains:annotations-java5:19.0.0"
+ implementation "org.json:json:20171018"
+
+
+ compileOnly "org.projectlombok:lombok:1.18.20"
+ annotationProcessor "org.projectlombok:lombok:1.18.16"
+
+ testCompileOnly "org.projectlombok:lombok:1.18.20"
+ testAnnotationProcessor "org.projectlombok:lombok:1.18.20"
+}
+
+shadowJar {
+
+ archiveFileName = jar.archiveFileName
+
+ dependencies {
+ include(dependency("org.json:json:20171018"))
+ }
+}
+
+reobf {
+ shadowJar {
+ mappingType = "SEARGE"
+ }
+}
+
+processResources {
+ // this will ensure that this task is redone when the versions change.
+ inputs.property "version", project.version
+ inputs.property "mcversion", project.minecraft.version
+
+ // replace stuff in mcmod.info, nothing else
+ from(sourceSets.main.resources.srcDirs) {
+ include "mcmod.info"
+
+ // replace version and mcversion
+ expand "version": project.version, "mcversion": project.minecraft.version
+ }
+
+ // copy everything else, thats not the mcmod.info
+ from(sourceSets.main.resources.srcDirs) {
+ exclude "mcmod.info"
+ }
+} \ No newline at end of file
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/DGInterface.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/DGInterface.java
new file mode 100755
index 00000000..c88a3cbf
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/DGInterface.java
@@ -0,0 +1,31 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher;
+
+import net.minecraft.client.resources.IResourceManager;
+import net.minecraftforge.fml.common.event.FMLInitializationEvent;
+import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
+
+import java.io.File;
+
+public interface DGInterface {
+ void init(File resourceDir);
+ void unload();
+ void onResourceReload(IResourceManager a);
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/GuiLoadingError.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/GuiLoadingError.java
new file mode 100644
index 00000000..965f9163
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/GuiLoadingError.java
@@ -0,0 +1,84 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher;
+
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.*;
+import net.minecraftforge.fml.common.FMLCommonHandler;
+import org.lwjgl.opengl.GL11;
+
+import java.io.IOException;
+
+public class GuiLoadingError extends GuiScreen {
+ private String stacktrace;
+ private Throwable throwable;
+ private GuiScreen originalGUI;
+ public GuiLoadingError(Throwable t, String stacktrace, GuiScreen originalGUI) {
+ this.throwable = t;
+ this.stacktrace = stacktrace;
+ this.originalGUI = originalGUI;
+ }
+
+ @Override
+ public void initGui() {
+ ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft());
+ this.buttonList.add(new GuiButton(0, sr.getScaledWidth()/2-100,sr.getScaledHeight()-70 ,"Close Minecraft"));
+ this.buttonList.add(new GuiButton(1, sr.getScaledWidth()/2-100,sr.getScaledHeight()-40 ,"Play Without DG"));
+ }
+
+ @Override
+ protected void actionPerformed(GuiButton button) throws IOException {
+ super.actionPerformed(button);
+ if (button.id == 0) {
+ FMLCommonHandler.instance().exitJava(-1,true);
+ } else if (button.id == 1) {
+ Minecraft.getMinecraft().displayGuiScreen(originalGUI);
+ }
+ }
+
+ @Override
+ public void drawScreen(int mouseX, int mouseY, float partialTicks) {
+ super.drawBackground(1);
+
+ ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft());
+ FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj;
+ fontRenderer.drawString("DungeonsGuide has ran into error while loading itself", (sr.getScaledWidth()-fontRenderer.getStringWidth("DungeonsGuide has ran into error while loading itself"))/2,40,0xFFFF0000);
+ fontRenderer.drawString("Please contact DungeonsGuide support with this screen", (sr.getScaledWidth()-fontRenderer.getStringWidth("Please contact developer with this screen"))/2, (int) (40+fontRenderer.FONT_HEIGHT*1.5),0xFFFF0000);
+
+ int tenth = sr.getScaledWidth() / 10;
+
+ Gui.drawRect(tenth, 70,sr.getScaledWidth()-tenth, sr.getScaledHeight()-80, 0xFF5B5B5B);
+ String[] split = stacktrace.split("\n");
+ clip(sr, tenth, 70,sr.getScaledWidth()-2*tenth, sr.getScaledHeight()-150);
+ GL11.glEnable(GL11.GL_SCISSOR_TEST);
+ for (int i = 0; i < split.length; i++) {
+ fontRenderer.drawString(split[i].replace("\t", " "), tenth+2,i*fontRenderer.FONT_HEIGHT + 72, 0xFFFFFFFF);
+ }
+ GL11.glDisable(GL11.GL_SCISSOR_TEST);
+
+ super.drawScreen(mouseX, mouseY, partialTicks);
+ }
+
+ public static void clip(ScaledResolution resolution, int x, int y, int width, int height) {
+ if (width < 0 || height < 0) return;
+
+ int scale = resolution.getScaleFactor();
+ GL11.glScissor((x ) * scale, Minecraft.getMinecraft().displayHeight - (y + height) * scale, (width) * scale, height * scale);
+ }
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java
new file mode 100755
index 00000000..f7db1b44
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java
@@ -0,0 +1,239 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher;
+
+import com.mojang.authlib.exceptions.AuthenticationException;
+import kr.syeyoung.dungeonsguide.launcher.authentication.Authenticator;
+import kr.syeyoung.dungeonsguide.launcher.branch.ModDownloader;
+import kr.syeyoung.dungeonsguide.launcher.exceptions.NoSuitableLoaderFoundException;
+import kr.syeyoung.dungeonsguide.launcher.exceptions.PrivacyPolicyRequiredException;
+import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException;
+import kr.syeyoung.dungeonsguide.launcher.exceptions.TokenExpiredException;
+import kr.syeyoung.dungeonsguide.launcher.loader.IDGLoader;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.GuiMainMenu;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.client.resources.IReloadableResourceManager;
+import net.minecraftforge.client.event.GuiOpenEvent;
+import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.common.config.Configuration;
+import net.minecraftforge.fml.common.Mod;
+import net.minecraftforge.fml.common.Mod.EventHandler;
+import net.minecraftforge.fml.common.ProgressManager;
+import net.minecraftforge.fml.common.event.FMLInitializationEvent;
+import net.minecraftforge.fml.common.event.FMLLoadCompleteEvent;
+import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
+import net.minecraftforge.fml.common.eventhandler.EventPriority;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
+
+import java.io.*;
+import java.security.*;
+
+@Mod(modid = Main.MOD_ID, version = Main.VERSION)
+public class Main
+{
+ public static final String MOD_ID = "skyblock_dungeons_guide";
+ public static final String VERSION = "1.0";
+ public static final String DOMAIN = "http://testmachine:8080";
+
+ private static Main main;
+
+ private File configDir;
+
+ private DGInterface dgInterface;
+ private Authenticator authenticator = new Authenticator();
+ private ModDownloader modDownloader = new ModDownloader(authenticator);
+
+
+ private IDGLoader currentLoader;
+
+ private Throwable lastError;
+ private boolean isMcLoaded;
+
+
+
+
+ @EventHandler
+ public void initEvent(FMLInitializationEvent initializationEvent)
+ {
+ MinecraftForge.EVENT_BUS.register(this);
+ if (dgInterface != null) {
+ try {
+ dgInterface.init(configDir);
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ public void unload() throws ReferenceLeakedException {
+ if (currentLoader != null && !currentLoader.isUnloadable()) {
+ throw new UnsupportedOperationException("Current version is not unloadable");
+ }
+ dgInterface = null;
+ if (currentLoader != null) {
+ currentLoader.unloadJar();
+ }
+ currentLoader = null;
+ }
+ public void load(IDGLoader newLoader) {
+ if (dgInterface != null) throw new IllegalStateException("DG is loaded");
+ newLoader.loadJar(authenticator);
+ dgInterface = newLoader.getInstance();
+ currentLoader = newLoader;
+
+ dgInterface.init(configDir);
+ }
+
+ public void reload(IDGLoader newLoader) {
+ try {
+ unload();
+ load(newLoader);
+ } catch (Exception e) {
+ lastError = e;
+ dgInterface = null;
+ currentLoader = null;
+ tryOpenError();
+ }
+ }
+
+ public void tryOpenError() {
+ }
+
+ public GuiScreen obtainErrorGUI() {
+ // when gets called init and stuff remove thing
+ }
+
+ @SubscribeEvent(priority = EventPriority.LOWEST)
+ public void onGuiOpen(GuiOpenEvent guiOpenEvent) {
+ if (guiOpenEvent.gui instanceof GuiMainMenu) {
+ isMcLoaded = true;
+ }
+ if (lastError != null && guiOpenEvent.gui instanceof GuiMainMenu) {
+ guiOpenEvent.gui = obtainErrorGUI();
+ }
+ }
+
+ public String getLoaderName(Configuration configuration) {
+ String loader = System.getProperty("dg.loader");
+ if (loader == null) {
+ loader = configuration.get("loader", "modsource", "auto").getString();
+ }
+ if (loader == null) loader = "auto";
+ return loader;
+ }
+
+
+ public IDGLoader obtainLoader(Configuration configuration) {
+ String loader = getLoaderName(configuration);
+
+ if ("local".equals(loader) ||
+ (loader.equals("auto") && this.getClass().getResourceAsStream("/kr/syeyoung/dungeonsguide/DungeonsGuide.class") == null)) {
+
+ } else if ("jar".equals("loader") ||
+ (loader.equals("auto") && this.getClass().getResourceAsStream("/mod.jar") == null)) {
+
+ } else if (loader.equals("auto") ){
+ // remote load
+ } else {
+ throw new NoSuitableLoaderFoundException(System.getProperty("dg.loader"), configuration.get("loader", "modsource", "auto").getString());
+ }
+ }
+
+ @EventHandler
+ public void preInit(FMLPreInitializationEvent preInitializationEvent) {
+ main = this;
+ configDir = preInitializationEvent.getModConfigurationDirectory();
+ ProgressManager.ProgressBar bar = null;
+ try {
+ bar = ProgressManager.push("DungeonsGuide",2);
+ bar.step("Authenticating...");
+ authenticator.repeatAuthenticate(5);
+
+ File f = new File(preInitializationEvent.getModConfigurationDirectory(), "loader.cfg");
+ Configuration configuration = new Configuration(f);
+ bar.step("Instantiating...");
+
+ load(obtainLoader(configuration));
+
+ configuration.save();
+ } catch (Throwable t) {
+ lastError = t;
+ dgInterface = null;
+ currentLoader = null;
+ tryOpenError();
+ } finally {
+ if (bar != null) ProgressManager.pop(bar);
+ }
+
+ ((IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager()).registerReloadListener(a -> {
+ if (dgInterface != null) dgInterface.onResourceReload(a);
+ });
+// try {
+// token = authenticator.authenticateAndDownload(this.getClass().getResourceAsStream("/kr/syeyoung/dungeonsguide/DungeonsGuide.class") == null ? System.getProperty("dg.version") == null ? "nlatest" : System.getProperty("dg.version") : null);
+// if (token != null) {
+// main = this;
+// URL.setURLStreamHandlerFactory(new DGStreamHandlerFactory(authenticator));
+// LaunchClassLoader classLoader = (LaunchClassLoader) Main.class.getClassLoader();
+// classLoader.addURL(new URL("z:///"));
+//
+// try {
+// progressBar.step("Initializing");
+// this.dgInterface = new DungeonsGuide(authenticator);
+// this.dgInterface.pre(preInitializationEvent);
+// while (progressBar.getStep() < progressBar.getSteps())
+// progressBar.step("random-"+progressBar.getStep());
+// ProgressManager.pop(progressBar);
+// isLoaded = true;
+// } catch (Throwable e) {
+// cause = e;
+// ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+// PrintStream printStream = new PrintStream(byteArrayOutputStream);
+// e.printStackTrace(printStream);
+// stacktrace = new String(byteArrayOutputStream.toByteArray());
+//
+// while (progressBar.getStep() < progressBar.getSteps())
+// progressBar.step("random-"+progressBar.getStep());
+// ProgressManager.pop(progressBar);
+//
+// e.printStackTrace();
+// }
+// }
+// } catch (IOException | AuthenticationException | NoSuchAlgorithmException | CertificateException | KeyStoreException | KeyManagementException | InvalidKeySpecException | SignatureException e) {
+// cause = e;
+// ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+// PrintStream printStream = new PrintStream(byteArrayOutputStream);
+// e.printStackTrace(printStream);
+// stacktrace = new String(byteArrayOutputStream.toByteArray());
+//
+// while (progressBar.getStep() < progressBar.getSteps())
+// progressBar.step("random-"+progressBar.getStep());
+// ProgressManager.pop(progressBar);
+//
+// e.printStackTrace();
+// }
+ }
+
+ public void setLastError(Throwable t) {
+ lastError = t;
+ }
+
+ public static Main getMain() {
+ return main;
+ }
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/AuthServerException.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/AuthServerException.java
new file mode 100644
index 00000000..3ffc491b
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/AuthServerException.java
@@ -0,0 +1,27 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher.authentication;
+
+import lombok.AllArgsConstructor;
+import org.json.JSONObject;
+
+@AllArgsConstructor
+public class AuthServerException extends RuntimeException {
+ private JSONObject payload;
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/Authenticator.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/Authenticator.java
new file mode 100755
index 00000000..8adcc7e6
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/Authenticator.java
@@ -0,0 +1,253 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher.authentication;
+
+import com.mojang.authlib.exceptions.AuthenticationException;
+import com.mojang.authlib.minecraft.MinecraftSessionService;
+import kr.syeyoung.dungeonsguide.launcher.Main;
+import kr.syeyoung.dungeonsguide.launcher.exceptions.PrivacyPolicyRequiredException;
+import kr.syeyoung.dungeonsguide.launcher.exceptions.TokenExpiredException;
+import lombok.Getter;
+import net.minecraft.client.Minecraft;
+import net.minecraft.util.Session;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.IOUtils;
+import org.json.JSONObject;
+import sun.reflect.Reflection;
+
+import javax.crypto.*;
+import javax.net.ssl.*;
+import java.io.*;
+import java.math.BigInteger;
+import java.net.*;
+import java.security.*;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.time.Instant;
+import java.util.UUID;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+public class Authenticator {
+ private String token;
+ private Instant validThru;
+ @Getter
+ private TokenStatus tokenStatus = TokenStatus.UNAUTHENTICATED;
+
+ private final SecureRandom secureRandom = new SecureRandom();
+
+ private Lock authenticationLock = new ReentrantLock();
+
+ static {
+ Reflection.registerFieldsToFilter(Authenticator.class, "token"); // Please do not touch this field. I know there is a way to block it completely, but I won't do it here.
+ }
+
+ public String getRawToken() {
+ return token;
+ }
+ public String getUnexpiredToken() {
+ if (tokenStatus != TokenStatus.AUTHENTICATED) throw new IllegalStateException("Token is not available");
+ long expiry = getJwtPayload(token).getLong("exp");
+ if (System.currentTimeMillis() >= expiry-2000 || tokenStatus == TokenStatus.EXPIRED) {
+ tokenStatus = TokenStatus.EXPIRED;
+ try {
+ repeatAuthenticate(5);
+ } catch (Throwable t) {
+ Main.getMain().setLastError(t);
+ throw new TokenExpiredException();
+ }
+ }
+ return token;
+ }
+
+
+ private byte[] generateSharedSecret() {
+ byte[] bts = new byte[32];
+ secureRandom.nextBytes(bts);
+ return bts;
+ }
+
+ public String repeatAuthenticate(int tries) {
+ int cnt = 0;
+ while(true) {
+ try {
+ reauthenticate();
+ break;
+ } catch (IOException | AuthenticationException | NoSuchAlgorithmException e) {
+ if (cnt == tries) throw new RuntimeException(e);
+ try {
+ Thread.sleep((long) Math.max(Math.pow(2, tries)* 100, 1000 * 10));
+ } catch (InterruptedException ex) {}
+ }
+ cnt++;
+ }
+ return token;
+ }
+ public String reauthenticate() throws IOException, AuthenticationException, NoSuchAlgorithmException {
+ try {
+ authenticationLock.lock();
+
+ MinecraftSessionService yggdrasilMinecraftSessionService = Minecraft.getMinecraft().getSessionService();
+ Session session = Minecraft.getMinecraft().getSession();
+
+ tokenStatus = TokenStatus.UNAUTHENTICATED;
+ token = null;
+ token = requestAuth(session.getProfile().getId(), session.getProfile().getName());
+ JSONObject d = getJwtPayload(token);
+
+ byte[] sharedSecret = generateSharedSecret();
+
+
+ String hash = calculateServerHash(sharedSecret,
+ Base64.decodeBase64(d.getString("publicKey")));
+
+ byte[] encodedSharedSecret;
+ try {
+ Cipher cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.ENCRYPT_MODE, KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.decodeBase64(d.getString("publicKey")))));
+ encodedSharedSecret = cipher.doFinal(sharedSecret);
+ } catch (NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException |
+ InvalidKeySpecException |
+ InvalidKeyException e) {
+ throw new RuntimeException(e);
+ }
+
+ yggdrasilMinecraftSessionService.joinServer(session.getProfile(), session.getToken(), hash); // Sent to "MOJANG" Server.
+ JSONObject furtherStuff = verifyAuth(token, encodedSharedSecret);
+ token = furtherStuff.getString("jwt");
+ if ("TOS_PRIVACY_POLICY_ACCEPT_REQUIRED".equals(furtherStuff.getString("result"))) {
+ tokenStatus = TokenStatus.PP_REQUIRED;
+ throw new PrivacyPolicyRequiredException();
+ }
+ tokenStatus = TokenStatus.AUTHENTICATED;
+ return this.token;
+ } finally {
+ authenticationLock.unlock();
+ }
+ }
+
+ public String acceptLatestTOS() throws IOException {
+ try {
+ authenticationLock.lock();
+ if (tokenStatus != TokenStatus.PP_REQUIRED) throw new IllegalStateException("Already accepted TOS");
+ JSONObject furtherStuff = acceptPrivacyPolicy(token);
+ token = furtherStuff.getString("jwt");
+ if ("TOS_PRIVACY_POLICY_ACCEPT_REQUIRED".equals(furtherStuff.getString("result"))) {
+ tokenStatus = TokenStatus.PP_REQUIRED;
+ throw new PrivacyPolicyRequiredException();
+ }
+ tokenStatus = TokenStatus.AUTHENTICATED;
+ return this.token;
+ } finally {
+ authenticationLock.unlock();
+ }
+ }
+
+ public JSONObject getJwtPayload(String jwt) {
+ String midPart = jwt.split("\\.")[1].replace("+", "-").replace("/", "_");
+ String base64Decode = new String(Base64.decodeBase64(midPart)); // padding
+ return new JSONObject(base64Decode);
+ }
+
+ private String requestAuth(UUID uuid, String nickname) throws IOException {
+ HttpsURLConnection urlConnection = (HttpsURLConnection) request("POST", "/auth/v2/requestAuth");
+ urlConnection.setRequestProperty("Content-Type", "application/json");
+
+ urlConnection.getOutputStream().write(("{\"uuid\":\""+uuid.toString()+"\",\"nickname\":\""+nickname+"\"}").getBytes());
+ try (InputStream is = obtainInputStream(urlConnection)) {
+ String payload = String.join("\n", IOUtils.readLines(is));
+ if (urlConnection.getResponseCode() != 200)
+ System.out.println("/auth/requestAuth :: Received " + urlConnection.getResponseCode() + " along with\n" + payload);
+
+ JSONObject json = new JSONObject(payload);
+
+ if ("Success".equals(json.getString("status"))) {
+ return json.getString("data");
+ } else {
+ throw new AuthServerException(json);
+ }
+ }
+ }
+ private JSONObject verifyAuth(String tempToken, byte[] secret) throws IOException {
+ HttpsURLConnection urlConnection = (HttpsURLConnection) request("POST", "/auth/v2/authenticate");
+
+ urlConnection.getOutputStream().write(("{\"jwt\":\""+tempToken+"\",\"sharedSecret\":\""+Base64.encodeBase64URLSafeString(secret)+"}").getBytes());
+ try (InputStream is = obtainInputStream(urlConnection)) {
+ String payload = String.join("\n", IOUtils.readLines(is));
+ if (urlConnection.getResponseCode() != 200)
+ System.out.println("/auth/authenticate :: Received " + urlConnection.getResponseCode() + " along with\n" + payload);
+
+ JSONObject jsonObject = new JSONObject(payload);
+ if (!"Success".equals(jsonObject.getString("status"))) {
+ throw new AuthServerException(jsonObject);
+ }
+ return jsonObject.getJSONObject("data");
+ }
+ }
+ private JSONObject acceptPrivacyPolicy(String tempToken) throws IOException {
+ HttpsURLConnection urlConnection = (HttpsURLConnection) request("POST", "/auth/v2/acceptPrivacyPolicy");
+
+ urlConnection.getOutputStream().write(tempToken.getBytes());
+ try (InputStream is = obtainInputStream(urlConnection)) {
+ String payload = String.join("\n", IOUtils.readLines(is));
+ if (urlConnection.getResponseCode() != 200)
+ System.out.println("/auth/authenticate :: Received " + urlConnection.getResponseCode() + " along with\n" + payload);
+
+ JSONObject jsonObject = new JSONObject(payload);
+ if (!"Success".equals(jsonObject.getString("status"))) {
+ throw new AuthServerException(jsonObject);
+ }
+ return jsonObject.getJSONObject("data");
+ }
+ }
+
+
+ private String calculateServerHash(byte[] a, byte[] b) throws NoSuchAlgorithmException {
+ MessageDigest c = MessageDigest.getInstance("SHA-1");
+ c.update("".getBytes());
+ c.update(a);
+ c.update(b);
+ byte[] d = c.digest();
+ return new BigInteger(d).toString(16);
+ }
+
+ public InputStream obtainInputStream(HttpURLConnection huc) {
+ InputStream inputStream = null;
+ try {
+ inputStream = huc.getInputStream();
+ } catch (Exception e) {
+ inputStream = huc.getErrorStream();
+ }
+ return inputStream;
+ }
+ public HttpURLConnection request(String method, String url) throws IOException {
+ HttpsURLConnection urlConnection = (HttpsURLConnection) new URL(Main.DOMAIN+url).openConnection();
+ urlConnection.setRequestMethod(method);
+ urlConnection.setRequestProperty("User-Agent", "DungeonsGuide/1.0");
+ urlConnection.setDoInput(true);
+ urlConnection.setDoOutput(true);
+ urlConnection.setAllowUserInteraction(true);
+ String token = getUnexpiredToken();
+ if (tokenStatus == TokenStatus.AUTHENTICATED)
+ urlConnection.setRequestProperty("Authorization", "Bearer "+token);
+ return urlConnection;
+ }
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/TokenStatus.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/TokenStatus.java
new file mode 100644
index 00000000..a83818b8
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/TokenStatus.java
@@ -0,0 +1,27 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher.authentication;
+
+public enum TokenStatus {
+ UNAUTHENTICATED,
+ BANNED,
+ PP_REQUIRED,
+ AUTHENTICATED,
+ EXPIRED
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/ModDownloader.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/ModDownloader.java
new file mode 100644
index 00000000..45eacee5
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/ModDownloader.java
@@ -0,0 +1,302 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher.branch;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import kr.syeyoung.dungeonsguide.launcher.authentication.Authenticator;
+import lombok.Getter;
+import net.minecraftforge.fml.common.ProgressManager;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.io.IOUtils;
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import javax.crypto.*;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.HttpsURLConnection;
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.security.*;
+import java.security.cert.CertificateException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.UUID;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+public class ModDownloader {
+ private Authenticator authenticator;
+
+ @Getter
+ private List<UpdateBranch> accessibleBranches = null;
+
+ public ModDownloader(Authenticator authenticator) {
+ this.authenticator = authenticator;
+ }
+
+ public List<UpdateBranch> fetchAccessibleBranches() throws IOException {
+ HttpURLConnection urlConnection = authenticator.request("GET", "/updates/");
+ try (InputStream is = authenticator.obtainInputStream(urlConnection)) {
+ String payload = String.join("\n", IOUtils.readLines(is));
+
+ JSONArray jsonArray = new JSONArray(payload);
+ List<UpdateBranch> branches = new ArrayList<>();
+ for (Object o : jsonArray) {
+ if (o instanceof JSONObject) {
+ JSONObject branch = (JSONObject) o;
+ UpdateBranch updateBranch = new UpdateBranch();
+ updateBranch.setId(branch.getLong("id"));
+ updateBranch.setName(branch.getString("name"));
+ updateBranch.setMetadata(branch.getJSONObject("metadata").getJSONObject("metadataSchema"));
+ branches.add(updateBranch);
+ }
+ }
+ return this.accessibleBranches = branches;
+ }
+ }
+
+ public List<Update> fetchUpdates(Long branch, int page) throws IOException {
+ HttpURLConnection urlConnection = authenticator.request("GET", "/updates/"+branch+"/");
+ try (InputStream is = authenticator.obtainInputStream(urlConnection)) {
+ String payload = String.join("\n", IOUtils.readLines(is));
+
+ JSONArray jsonArray = new JSONArray(payload);
+ List<Update> updates = new ArrayList<>();
+ for (Object o : jsonArray) {
+ if (o instanceof JSONObject) {
+ JSONObject json = (JSONObject) o;
+ Update update = new Update();
+ update.setId(json.getLong("id"));
+ update.setBranchId(json.getLong("branchId"));
+ update.setName(json.getString("versionName"));
+ update.setUpdateLog(json.getString("updateLog"));
+ update.setMetadata(json.getJSONObject("metadata"));
+ for (Object assets : json.getJSONObject("assets").getJSONArray("assets")) {
+ if (assets instanceof JSONObject) {
+ JSONObject a_json = (JSONObject) assets;
+ Update.Asset asset = new Update.Asset();
+ asset.setName(a_json.getString("name"));
+ asset.setSize(a_json.getLong("size"));
+ asset.setObjectId(a_json.getString("objectId"));
+ asset.setAssetId(UUID.fromString(a_json.getString("assetID")));
+ update.getAssets().add(asset);
+ }
+ }
+ updates.add(update);
+ }
+ }
+ return updates;
+ }
+ }
+
+ /*
+ pls Close after done
+ */
+ public InputStream fetchAsset(Update update, UUID assetId) throws IOException {
+ HttpURLConnection urlConnection = authenticator.request("GET", "/updates/"+update.getBranchId()+"/"+update.getId()+"/"+assetId.toString());
+ try (InputStream is = authenticator.obtainInputStream(urlConnection)) {
+ String payload = String.join("\n", IOUtils.readLines(is));
+ JSONObject object = new JSONObject(payload);
+
+ HttpURLConnection connection = (HttpURLConnection) new URL(object.getString("url")).openConnection();
+ connection.setRequestMethod(object.getString("method"));
+ urlConnection.setRequestProperty("User-Agent", "DungeonsGuide/1.0");
+ urlConnection.setDoInput(true);
+ urlConnection.setDoOutput(true);
+ urlConnection.setAllowUserInteraction(true);
+ return authenticator.obtainInputStream(connection);
+ }
+ }
+
+
+
+
+
+
+ private ProgressManager.ProgressBar progressBar;
+
+ private PublicKey dgPublicKey;
+ private PublicKey getDGPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
+ if (dgPublicKey != null) return dgPublicKey;
+ X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decodeBase64("MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxO89qtwG67jNucQ9Y44c" +
+ "IUs/B+5BeJPs7G+RG2gfs4/2+tzF/c1FLDc33M7yKw8aKk99vsBUY9Oo8gxxiEPB" +
+ "JitP/qfon2THp94oM77ZTpHlmFoqbZMcKGZVI8yfvEL4laTM8Hw+qh5poQwtpEbK" +
+ "Xo47AkxygxJasUnykER2+aSTZ6kWU2D4xiNtFA6lzqN+/oA+NaYfPS0amAvyVlHR" +
+ "n/8IuGkxb5RrlqVssQstFnxsJuv88qdGSEqlcKq2tLeg9hb8eCnl2OFzvXmgbVER" +
+ "0JaV+4Z02fVG1IlR3Xo1mSit7yIU6++3usRCjx2yfXpnGGJUW5pe6YETjNew3ax+" +
+ "FAZ4GePWCdmS7FvBnbbABKo5pE06ZTfDUTCjQlAJQiUgoF6ntMJvQAXPu48Vr8q/" +
+ "mTcuZWVnI6CDgyE7nNq3WNoq3397sBzxRohMxuqzl3T19zkfPKF05iV2Ju1HQMW5" +
+ "I119bYrmVD240aGESZc20Sx/9g1BFpNzQbM5PGUlWJ0dhLjl2ge4ip2hHciY3OEY" +
+ "p2Qy2k+xEdenpKdL+WMRimCQoO9gWe2Tp4NmP5dppDXZgPjXqjZpnGs0Uxs+fXqW" +
+ "cwlg3MbX3rFl9so/fhVf4p9oXZK3ve7z5D6XSSDRYECvsKIa08WAxJ/U6n204E/4" +
+ "xUF+3ZgFPdzZGn2PU7SsnOsCAwEAAQ=="));
+ return dgPublicKey = KeyFactory.getInstance("RSA").generatePublic(spec);
+ }
+
+
+
+
+ private KeyPair rsaKey;
+ private KeyPair getKeyPair() {
+ KeyPairGenerator a = null;
+ try {
+ a = KeyPairGenerator.getInstance("RSA");
+ } catch (NoSuchAlgorithmException b) { }
+ a.initialize(1024);
+ this.rsaKey = a.generateKeyPair();
+ return this.rsaKey;
+ }
+
+
+ private final HashMap<String, byte[]> loadedResources = new HashMap<String, byte[]>();
+
+ public HashMap<String, byte[]> getResources() {
+ return loadedResources;
+ }
+
+ private void downloadSafe(String dgToken, String url, boolean isValidateSignature) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, CertificateException, KeyStoreException, KeyManagementException, SignatureException, InvalidKeySpecException {
+ HttpsURLConnection dgConnection = (HttpsURLConnection) new URL(url).openConnection();
+ dgConnection.setRequestProperty("User-Agent", "DungeonsGuide/1.0");
+ dgConnection.setRequestProperty("Content-Type", "application/json");
+ dgConnection.setRequestMethod("GET");
+ dgConnection.setRequestProperty("Authorization", dgToken);
+ dgConnection.setDoInput(true);
+ dgConnection.setDoOutput(true);
+
+ InputStream inputStream = dgConnection.getInputStream();
+ byte[] lengthBytes = new byte[4];
+ inputStream.read(lengthBytes);
+ int length = ((lengthBytes[0] & 0xFF) << 24) |
+ ((lengthBytes[1] & 0xFF) << 16) |
+ ((lengthBytes[2] & 0xFF) << 8) |
+ ((lengthBytes[3] & 0xFF));
+ while (inputStream.available() < length) ;
+ byte[] keyPayload = new byte[length];
+ inputStream.read(keyPayload);
+
+ Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+ cipher.init(Cipher.DECRYPT_MODE, this.rsaKey.getPrivate());
+ byte[] h = cipher.doFinal(keyPayload);
+
+ cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ SecretKeySpec keySpec = new SecretKeySpec(h, "AES");
+ IvParameterSpec ivSpec = new IvParameterSpec(h);
+ cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
+ CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher);
+
+ cipherInputStream.read(lengthBytes);
+ length = ((lengthBytes[0] & 0xFF) << 24) |
+ ((lengthBytes[1] & 0xFF) << 16) |
+ ((lengthBytes[2] & 0xFF) << 8) |
+ ((lengthBytes[3] & 0xFF));
+
+ int totalLen = length;
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ byte[] buff = new byte[256];
+ while (totalLen > 0) {
+ int len = cipherInputStream.read(buff, 0, Math.min(buff.length, totalLen));
+ totalLen -= len;
+ bos.write(buff, 0, len);
+ }
+ byte[] body = bos.toByteArray();
+
+ byte[] signed = null;
+ if (isValidateSignature) {
+ progressBar.step("Validating Signature");
+ cipherInputStream.read(lengthBytes,0 , 4);
+ length = ((lengthBytes[0] & 0xFF) << 24) |
+ ((lengthBytes[1] & 0xFF) << 16) |
+ ((lengthBytes[2] & 0xFF) << 8) |
+ ((lengthBytes[3] & 0xFF));
+
+ totalLen = length;
+ bos = new ByteArrayOutputStream();
+ while (totalLen > 0) {
+ int len = cipherInputStream.read(buff, 0, Math.min(buff.length, totalLen));
+ totalLen -= len;
+ bos.write(buff, 0, len);
+ }
+ signed = bos.toByteArray();
+
+ Signature sign = Signature.getInstance("SHA512withRSA");
+ sign.initVerify(getDGPublicKey());
+ sign.update(body);
+ boolean truth = sign.verify(signed);
+ if (!truth) throw new SignatureException("DG SIGNATURE FORGED");
+ }
+
+ ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream(body));
+ ZipEntry zipEntry;
+ while ((zipEntry=zipInputStream.getNextEntry()) != null) {
+ byte[] buffer = new byte[256];
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ int p = 0;
+ while((p = zipInputStream.read(buffer)) > 0) {
+ byteArrayOutputStream.write(buffer, 0, p);
+ }
+ this.loadedResources.put(zipEntry.getName(), byteArrayOutputStream.toByteArray());
+ }
+ dgConnection.disconnect();
+ }
+
+ public JsonElement getJsonSecured(String u) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, CertificateException, KeyStoreException, KeyManagementException {
+ HttpsURLConnection httpsURLConnection = (HttpsURLConnection) new URL(u).openConnection();
+ httpsURLConnection.setRequestProperty("User-Agent", "DungeonsGuide/1.0");
+ httpsURLConnection.setRequestProperty("Content-Type", "application/json");
+ httpsURLConnection.setRequestMethod("GET");
+ httpsURLConnection.setRequestProperty("Authorization", authenticator.getUnexpiredToken());
+ httpsURLConnection.setDoInput(true);
+ httpsURLConnection.setDoOutput(true);
+
+ InputStream inputStream = httpsURLConnection.getInputStream();
+ byte[] lengthPayload = new byte[4];
+ inputStream.read(lengthPayload);
+ int length = ((lengthPayload[0] & 0xFF) << 24) |
+ ((lengthPayload[1] & 0xFF) << 16) |
+ ((lengthPayload[2] & 0xFF) << 8) |
+ ((lengthPayload[3] & 0xFF));
+ while (inputStream.available() < length) ;
+ byte[] keyPayload = new byte[length];
+ inputStream.read(keyPayload);
+
+ Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
+ cipher.init(Cipher.DECRYPT_MODE, this.rsaKey.getPrivate());
+ byte[] AESKey = cipher.doFinal(keyPayload);
+
+ cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ SecretKeySpec secretKeySpec = new SecretKeySpec(AESKey, "AES");
+ IvParameterSpec ivParameterSpec = new IvParameterSpec(AESKey);
+ cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
+ CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher);
+ cipherInputStream.read(lengthPayload);
+ length = ((lengthPayload[0] & 0xFF) << 24) |
+ ((lengthPayload[1] & 0xFF) << 16) |
+ ((lengthPayload[2] & 0xFF) << 8) |
+ ((lengthPayload[3] & 0xFF));
+ JsonElement l = new JsonParser().parse(new InputStreamReader(cipherInputStream));
+ httpsURLConnection.disconnect();
+ return l;
+ }
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/Update.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/Update.java
new file mode 100644
index 00000000..565ac5aa
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/Update.java
@@ -0,0 +1,46 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher.branch;
+
+import lombok.Data;
+import org.json.JSONObject;
+
+import java.time.Instant;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+@Data
+public class Update {
+ private long id;
+ private long branchId;
+ private String name;
+ private String updateLog;
+ private JSONObject metadata;
+ private Instant releaseDate;
+ private List<Asset> assets = new ArrayList<>();
+
+ @Data
+ public static class Asset {
+ private String name;
+ private long size;
+ private String objectId;
+ private UUID assetId;
+ }
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/UpdateBranch.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/UpdateBranch.java
new file mode 100644
index 00000000..f0b05ee4
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/UpdateBranch.java
@@ -0,0 +1,29 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher.branch;
+
+import lombok.Data;
+import org.json.JSONObject;
+
+@Data
+public class UpdateBranch {
+ private Long id;
+ private String name;
+ private JSONObject metadata;
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/NoSuitableLoaderFoundException.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/NoSuitableLoaderFoundException.java
new file mode 100644
index 00000000..e5f50754
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/NoSuitableLoaderFoundException.java
@@ -0,0 +1,27 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher.exceptions;
+
+import lombok.AllArgsConstructor;
+
+@AllArgsConstructor
+public class NoSuitableLoaderFoundException extends RuntimeException {
+ private String jvmFlag;
+ private String configuration;
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/PrivacyPolicyRequiredException.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/PrivacyPolicyRequiredException.java
new file mode 100644
index 00000000..006e03ca
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/PrivacyPolicyRequiredException.java
@@ -0,0 +1,22 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher.exceptions;
+
+public class PrivacyPolicyRequiredException extends RuntimeException{
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/ReferenceLeakedException.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/ReferenceLeakedException.java
new file mode 100644
index 00000000..3a88b862
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/ReferenceLeakedException.java
@@ -0,0 +1,22 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher.exceptions;
+
+public class ReferenceLeakedException extends Exception {
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/TokenExpiredException.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/TokenExpiredException.java
new file mode 100644
index 00000000..d44d72fd
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/TokenExpiredException.java
@@ -0,0 +1,22 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher.exceptions;
+
+public class TokenExpiredException extends RuntimeException{
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/IDGLoader.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/IDGLoader.java
new file mode 100644
index 00000000..607fc668
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/IDGLoader.java
@@ -0,0 +1,36 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher.loader;
+
+import kr.syeyoung.dungeonsguide.launcher.DGInterface;
+import kr.syeyoung.dungeonsguide.launcher.authentication.Authenticator;
+import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException;
+import net.minecraftforge.common.config.Configuration;
+
+public interface IDGLoader {
+ void loadJar(Authenticator authenticator);
+ DGInterface getInstance();
+ void unloadJar() throws ReferenceLeakedException;
+
+ boolean isUnloadable();
+
+ boolean isLoaded();
+
+ String strategyName();
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGConnection.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGConnection.java
new file mode 100755
index 00000000..e8e40ebe
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGConnection.java
@@ -0,0 +1,47 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher.url;
+
+import kr.syeyoung.dungeonsguide.launcher.authentication.Authenticator;
+
+import java.io.*;
+import java.net.URL;
+import java.net.URLConnection;
+
+public class DGConnection extends URLConnection {
+ private final Authenticator authenticator;
+ protected DGConnection(URL url, Authenticator a) {
+ super(url);
+ connected = false;
+ this.authenticator = a;
+ }
+
+ @Override
+ public void connect() throws IOException {
+ }
+ @Override
+ public InputStream getInputStream() throws IOException {
+ if (authenticator != null) {
+ String path = url.getPath().substring(1);
+ if (!authenticator.getResources().containsKey(path)) throw new FileNotFoundException();
+ return new ByteArrayInputStream(authenticator.getResources().get(path));
+ }
+ throw new FileNotFoundException();
+ }
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandler.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandler.java
new file mode 100755
index 00000000..82ddff18
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandler.java
@@ -0,0 +1,36 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher.url;
+
+import kr.syeyoung.dungeonsguide.launcher.authentication.Authenticator;
+import lombok.AllArgsConstructor;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+
+@AllArgsConstructor
+public class DGStreamHandler extends URLStreamHandler {
+ private final Authenticator auth;
+ @Override
+ protected URLConnection openConnection(URL url) throws IOException {
+ return new DGConnection(url, this.auth);
+ }
+}
diff --git a/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandlerFactory.java b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandlerFactory.java
new file mode 100755
index 00000000..a7b50046
--- /dev/null
+++ b/wrapper/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandlerFactory.java
@@ -0,0 +1,37 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021 cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.launcher.url;
+
+import kr.syeyoung.dungeonsguide.launcher.authentication.Authenticator;
+import lombok.AllArgsConstructor;
+
+import java.net.URLStreamHandler;
+import java.net.URLStreamHandlerFactory;
+
+@AllArgsConstructor
+public class DGStreamHandlerFactory implements URLStreamHandlerFactory {
+ private final Authenticator auth;
+ @Override
+ public URLStreamHandler createURLStreamHandler(String protocol) {
+ if ("z".equals(protocol)) {
+ return new DGStreamHandler(this.auth);
+ }
+ return null;
+ }
+}
diff --git a/wrapper/src/main/resources/mcmod.info b/wrapper/src/main/resources/mcmod.info
new file mode 100755
index 00000000..70df65aa
--- /dev/null
+++ b/wrapper/src/main/resources/mcmod.info
@@ -0,0 +1,16 @@
+[
+{
+ "modid": "skyblock_dungeons_guide",
+ "name": "Skyblock Dungeons Guide",
+ "description": "A mod to help dungeon players to find and solve secrets and puzzles most efficiently.",
+ "version": "${version}",
+ "mcversion": "${mcversion}",
+ "url": "",
+ "updateUrl": "",
+ "authorList": ["syeyoung"],
+ "credits": "The guild Jerry's Crew, for nothing.",
+ "logoFile": "",
+ "screenshots": [],
+ "dependencies": []
+}
+]