diff options
Diffstat (limited to 'loader/src/main/java/kr/syeyoung')
44 files changed, 1450 insertions, 1087 deletions
diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/DungeonsGuideReloadListener.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/DungeonsGuideReloadListener.java index 7252a9db..a96805c1 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/DungeonsGuideReloadListener.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/DungeonsGuideReloadListener.java @@ -19,6 +19,9 @@ package kr.syeyoung.dungeonsguide.launcher; public interface DungeonsGuideReloadListener { + /** + * @implNote This is very important that you GET RID OF referene to DGInterface when this is called, or else dg is gonna crash with ReferenceLeakedException. + */ public void unloadReference(); public void onLoad(DGInterface dgInterface); } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java index 7cc0f806..e8d3e36b 100755 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java @@ -18,25 +18,21 @@ package kr.syeyoung.dungeonsguide.launcher; -import com.mojang.authlib.exceptions.AuthenticationUnavailableException; -import com.mojang.authlib.exceptions.InvalidCredentialsException; -import kr.syeyoung.dungeonsguide.launcher.exceptions.AuthServerException; -import kr.syeyoung.dungeonsguide.launcher.authentication.Authenticator; -import kr.syeyoung.dungeonsguide.launcher.branch.ModDownloader; +import kr.syeyoung.dungeonsguide.launcher.auth.AuthManager; +import kr.syeyoung.dungeonsguide.launcher.branch.UpdateRetrieverUtil; import kr.syeyoung.dungeonsguide.launcher.exceptions.NoSuitableLoaderFoundException; -import kr.syeyoung.dungeonsguide.launcher.exceptions.PrivacyPolicyRequiredException; +import kr.syeyoung.dungeonsguide.launcher.exceptions.NoVersionFoundException; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; -import kr.syeyoung.dungeonsguide.launcher.exceptions.TokenExpiredException; -import kr.syeyoung.dungeonsguide.launcher.gui.GuiLoadingError; -import kr.syeyoung.dungeonsguide.launcher.gui.GuiPrivacyPolicy; +import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiDisplayer; +import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiLoadingError; +import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiReferenceLeak; +import kr.syeyoung.dungeonsguide.launcher.gui.screen.SpecialGuiScreen; import kr.syeyoung.dungeonsguide.launcher.loader.IDGLoader; import kr.syeyoung.dungeonsguide.launcher.loader.JarLoader; import kr.syeyoung.dungeonsguide.launcher.loader.LocalLoader; +import kr.syeyoung.dungeonsguide.launcher.loader.RemoteLoader; 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; @@ -44,13 +40,9 @@ 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.FMLPreInitializationEvent; -import net.minecraftforge.fml.common.eventhandler.EventPriority; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import java.io.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; +import java.util.*; @Mod(modid = Main.MOD_ID, version = Main.VERSION) public class Main @@ -61,13 +53,15 @@ public class Main private static Main main; - private File configDir; + private static File configDir; private DGInterface dgInterface; - private Authenticator authenticator = new Authenticator(); - private ModDownloader modDownloader = new ModDownloader(authenticator); - private List<DungeonsGuideReloadListener> listeners = new ArrayList<>(); + private final List<DungeonsGuideReloadListener> listeners = new ArrayList<>(); + + public static File getConfigDir() { + return configDir; + } public void addDGReloadListener(DungeonsGuideReloadListener dungeonsGuideReloadListener) { listeners.add(Objects.requireNonNull(dungeonsGuideReloadListener)); @@ -77,28 +71,18 @@ public class Main } private IDGLoader currentLoader; - - private Throwable lastError; - private boolean isMcLoaded; - - - - @EventHandler - public void initEvent(FMLInitializationEvent initializationEvent) - { + public void initEvent(FMLInitializationEvent initializationEvent) throws ClassNotFoundException, InstantiationException, IllegalAccessException { MinecraftForge.EVENT_BUS.register(this); - if (dgInterface != null) { - try { - dgInterface.init(configDir); - - for (DungeonsGuideReloadListener listener : listeners) { - listener.onLoad(dgInterface); - } - } catch (Exception e) { - e.printStackTrace(); - setLastFatalError(e); - } + MinecraftForge.EVENT_BUS.register(GuiDisplayer.INSTANCE); + + try { + File f = new File(configDir, "loader.cfg"); + Configuration configuration = new Configuration(f); + IDGLoader idgLoader = obtainLoader(configuration); + load(idgLoader); + } catch (Throwable e) { + GuiDisplayer.INSTANCE.displayGui(obtainErrorGUI(e)); } } @@ -111,12 +95,14 @@ public class Main listener.unloadReference(); } if (currentLoader != null) { - currentLoader.unloadJar(); + currentLoader.unloadDungeonsGuide(); } currentLoader = null; } - private void load(IDGLoader newLoader) throws ClassNotFoundException, InstantiationException, IllegalAccessException { - partialLoad(newLoader); + private void load(IDGLoader newLoader) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException { + if (dgInterface != null) throw new IllegalStateException("DG is loaded"); + dgInterface = newLoader.loadDungeonsGuide(); + currentLoader = newLoader; dgInterface.init(configDir); @@ -124,13 +110,6 @@ public class Main listener.onLoad(dgInterface); } } - private void partialLoad(IDGLoader newLoader) throws ClassNotFoundException, InstantiationException, IllegalAccessException { - if (dgInterface != null) throw new IllegalStateException("DG is loaded"); - newLoader.loadJar(authenticator); - dgInterface = newLoader.getInstance(); - currentLoader = newLoader; - } - public void reload(IDGLoader newLoader) { try { unload(); @@ -140,49 +119,25 @@ public class Main currentLoader = null; e.printStackTrace(); - setLastFatalError(e); - } - } - public void tryOpenError() { - if (isMcLoaded) Minecraft.getMinecraft().displayGuiScreen(obtainErrorGUI()); + GuiDisplayer.INSTANCE.displayGui(obtainErrorGUI(e)); + } } - public GuiScreen obtainErrorGUI() { - if (lastError instanceof PrivacyPolicyRequiredException) { - return new GuiPrivacyPolicy(); - } else if (lastError instanceof TokenExpiredException) { - + public SpecialGuiScreen obtainErrorGUI(Throwable lastError) { + if (lastError instanceof kr.syeyoung.dungeonsguide.launcher.exceptions.AuthenticationUnavailableException) { + return null; } else if (lastError instanceof NoSuitableLoaderFoundException) { - + return new GuiLoadingError(lastError); } else if (lastError instanceof ReferenceLeakedException) { - - } else if (lastError instanceof AuthServerException) { - - } else if (lastError instanceof InvalidCredentialsException) { - - } else if (lastError instanceof AuthenticationUnavailableException) { - + return new GuiReferenceLeak(lastError); } else if (lastError != null){ - return new GuiLoadingError(lastError, () -> {lastError = null;}); + return new GuiLoadingError(lastError); } - if (lastError != null) - lastError.printStackTrace(); // when gets called init and stuff remove thing return null; } - @SubscribeEvent(priority = EventPriority.LOWEST) - public void onGuiOpen(GuiOpenEvent guiOpenEvent) { - if (guiOpenEvent.gui instanceof GuiMainMenu) { - isMcLoaded = true; - } - if (lastError != null && guiOpenEvent.gui instanceof GuiMainMenu) { - GuiScreen gui = obtainErrorGUI(); - if (gui != null) - guiOpenEvent.gui = gui; - } - } public String getLoaderName(Configuration configuration) { String loader = System.getProperty("dg.loader"); @@ -205,7 +160,19 @@ public class Main return new JarLoader(); } else if (loader.equals("auto") ){ // remote load - throw new UnsupportedOperationException(""); // yet + String branch = System.getProperty("branch") == null ? configuration.get("loader", "remoteBranch", "$default").getString() : System.getProperty("branch"); + String version = System.getProperty("version") == null ? configuration.get("loader", "remoteVersion", "latest").getString() : System.getProperty("version"); + try { + UpdateRetrieverUtil.VersionInfo versionInfo = UpdateRetrieverUtil.getIds( + branch, + version + ); + if (versionInfo == null) throw new NoVersionFoundException(branch, version); + + return new RemoteLoader(versionInfo.getFriendlyBranchName(), versionInfo.getBranchId(), versionInfo.getUpdateId()); + } catch (IOException e) { + throw new NoVersionFoundException(branch, version, e); + } } else { throw new NoSuitableLoaderFoundException(System.getProperty("dg.loader"), configuration.get("loader", "modsource", "auto").getString()); } @@ -218,20 +185,17 @@ public class Main configDir = preInitializationEvent.getModConfigurationDirectory(); // setup preinit progress bar for well, progress bar! - ProgressManager.ProgressBar bar = ProgressManager.push("DungeonsGuide", 2); + ProgressManager.ProgressBar bar = ProgressManager.push("DungeonsGuide", 1); try { // Try authenticate bar.step("Authenticating..."); - authenticator.repeatAuthenticate(5); + AuthManager.getInstance().init(); // If authentication succeeds, obtain loader and partially load dungeons guide + File f = new File(preInitializationEvent.getModConfigurationDirectory(), "loader.cfg"); Configuration configuration = new Configuration(f); - - bar.step("Instantiating..."); - partialLoad(obtainLoader(configuration)); - // Save config because... well to generate it configuration.save(); } catch (Throwable t) { @@ -239,7 +203,6 @@ public class Main currentLoader = null; t.printStackTrace(); - setLastFatalError(t); } finally { while(bar.getStep() < bar.getSteps()) bar.step(""); ProgressManager.pop(bar); @@ -250,11 +213,6 @@ public class Main }); } - public void setLastFatalError(Throwable t) { - lastError = t; - tryOpenError(); - } - public static Main getMain() { return main; } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthManager.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthManager.java index f0c346c6..c3dd747a 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthManager.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthManager.java @@ -2,149 +2,142 @@ package kr.syeyoung.dungeonsguide.launcher.auth; import com.google.common.base.Throwables; import com.google.common.util.concurrent.ThreadFactoryBuilder; -import com.google.gson.JsonObject; import com.mojang.authlib.exceptions.AuthenticationException; -import kr.syeyoung.dungeonsguide.launcher.auth.authprovider.AuthProvider; -import kr.syeyoung.dungeonsguide.launcher.auth.authprovider.DgAuth.DgAuth; -import kr.syeyoung.dungeonsguide.launcher.auth.authprovider.DgAuth.DgAuthUtil; -import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter; -import kr.syeyoung.dungeonsguide.mod.events.impl.AuthChangedEvent; -import kr.syeyoung.dungeonsguide.mod.stomp.StompManager; +import kr.syeyoung.dungeonsguide.launcher.Main; +import kr.syeyoung.dungeonsguide.launcher.auth.token.*; +import kr.syeyoung.dungeonsguide.launcher.events.AuthChangedEvent; +import kr.syeyoung.dungeonsguide.launcher.exceptions.AuthFailedExeption; +import kr.syeyoung.dungeonsguide.launcher.exceptions.PrivacyPolicyRequiredException; +import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiDisplayer; +import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiPrivacyPolicy; import lombok.Setter; import net.minecraft.client.Minecraft; import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; -import net.minecraftforge.fml.common.gameevent.TickEvent; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; import java.io.IOException; -import java.security.KeyPair; +import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; -import java.util.Objects; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; +import java.security.spec.InvalidKeySpecException; +import java.util.concurrent.*; public class AuthManager { Logger logger = LogManager.getLogger("AuthManger"); - private static AuthManager instance; + private static AuthManager INSTANCE; public static AuthManager getInstance() { - if(instance == null) instance = new AuthManager(); - return instance; + if(INSTANCE == null) INSTANCE = new AuthManager(); + return INSTANCE; } + private AuthToken currentToken = new NullToken(); - - @Setter - private String baseserverurl = "https://dungeons.guide"; - - private AuthProvider currentProvider; - - public String getToken() { - if (currentProvider != null && currentProvider.getToken() != null) { - return currentProvider.getToken(); - } - return null; + public AuthToken getToken() { + return currentToken; + } + public String getWorkingTokenOrNull() { + if (currentToken instanceof DGAuthToken) return currentToken.getToken(); + else return null; } - public KeyPair getKeyPair(){ - if (currentProvider != null && currentProvider.getToken() != null) { - return currentProvider.getRsaKey(); - } - return null; + public String getWorkingTokenOrThrow() { + if (currentToken instanceof DGAuthToken) return currentToken.getToken(); + else if (currentToken instanceof FailedAuthToken) throw new AuthFailedExeption(((FailedAuthToken) currentToken).getException()); + else if (currentToken instanceof NullToken) throw new IllegalStateException("No Token"); + else if (currentToken instanceof PrivacyPolicyRequiredToken) throw new PrivacyPolicyRequiredException(); + throw new IllegalStateException("weird token: "+currentToken); } - boolean initlock = false; + private volatile boolean initlock = false; public void init() { if (initlock) { logger.info("Cannot init AuthManger twice"); - return; + throw new IllegalStateException("Can not init AuthManager twice"); } - reauth(); - initlock = true; - - MinecraftForge.EVENT_BUS.register(this); - ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("DgAuth Pool").build(); final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, namedThreadFactory); scheduler.scheduleAtFixedRate(() -> { - if (getToken() != null) { - JsonObject obj = DgAuthUtil.getJwtPayload(getToken()); - if (!obj.get("uuid").getAsString().replace("-", "").equals(Minecraft.getMinecraft().getSession().getPlayerID())) { - shouldReAuth = true; - } + boolean shouldReAuth = false; + if (!getToken().getUID().replace("-", "").equals(Minecraft.getMinecraft().getSession().getPlayerID())) { + shouldReAuth = true; + } + if (!getToken().isAuthenticated()) { + shouldReAuth = true; } + if (shouldReAuth) + reAuth(); }, 10,2000, TimeUnit.MILLISECONDS); - } - - boolean shouldReAuth = true; - int tickCounter; - @SubscribeEvent - public void onTickClientTick(TickEvent.ClientTickEvent event) { - if (event.phase != TickEvent.Phase.START) return; - if (tickCounter % 200 == 0) { - tickCounter = 0; - reauth(); - } - tickCounter++; - - } - - public boolean isPlebUser(){ - return Objects.equals(getInstance().getPlanType(), "OPENSOURCE"); + reAuth(); } - public String getPlanType(){ - if(getToken() == null) return null; + private volatile boolean reauthLock = false; - JsonObject jwt = DgAuthUtil.getJwtPayload(getToken()); - if(!jwt.has("plan")) return null; + AuthToken reAuth() { + if (reauthLock) { + while (reauthLock) ; + return currentToken; + } - return jwt.get("plan").getAsString(); + reauthLock = true; + try { + String token = DgAuthUtil.requestAuth(); + byte[] encSecret = DgAuthUtil.checkSessionAuthenticityAndReturnEncryptedSecret(token); + currentToken = DgAuthUtil.verifyAuth(token, encSecret); + MinecraftForge.EVENT_BUS.post(new AuthChangedEvent(currentToken)); + + if (currentToken instanceof PrivacyPolicyRequiredToken) { + GuiDisplayer.INSTANCE.displayGui(new GuiPrivacyPolicy()); + throw new PrivacyPolicyRequiredException(); + } + } catch (NoSuchAlgorithmException | AuthenticationException | IOException | NoSuchPaddingException | + InvalidKeyException | InvalidKeySpecException | IllegalBlockSizeException | BadPaddingException e) { + currentToken = new FailedAuthToken(e); + // TODO: loader notifications on bottom right? +// ChatTransmitter.addToQueue("§eDungeons Guide §7:: §r§cDG auth failed, trying again in ten seconds", true); + logger.error("Re-auth failed with message {}, trying again in a 2 seconds", String.valueOf(Throwables.getRootCause(e))); + throw new AuthFailedExeption(e); + } finally { + reauthLock = false; + } + return currentToken; } - void reauth() { - if (!shouldReAuth) return; - shouldReAuth = false; + AuthToken acceptPrivacyPolicy() throws IOException { + if (reauthLock) { + while(reauthLock); + return currentToken; + } - currentProvider = null; - try { - currentProvider = new DgAuth(baseserverurl).createAuthProvider(); - if (currentProvider.getToken() == null) { - shoul |
