diff options
Diffstat (limited to 'loader/src/main')
19 files changed, 347 insertions, 263 deletions
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 e8d3e36b..e4696dd1 100755 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java @@ -20,9 +20,11 @@ package kr.syeyoung.dungeonsguide.launcher; import kr.syeyoung.dungeonsguide.launcher.auth.AuthManager; import kr.syeyoung.dungeonsguide.launcher.branch.UpdateRetrieverUtil; +import kr.syeyoung.dungeonsguide.launcher.exceptions.DungeonsGuideLoadingException; import kr.syeyoung.dungeonsguide.launcher.exceptions.NoSuitableLoaderFoundException; import kr.syeyoung.dungeonsguide.launcher.exceptions.NoVersionFoundException; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; +import kr.syeyoung.dungeonsguide.launcher.exceptions.auth.AuthenticationUnavailableException; import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiDisplayer; import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiLoadingError; import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiReferenceLeak; @@ -49,7 +51,7 @@ public class Main { public static final String MOD_ID = "dungeons_guide_wrapper"; public static final String VERSION = "1.0"; - public static final String DOMAIN = "http://testmachine:8080/api"; + public static final String DOMAIN = "http://testmachine2/api"; private static Main main; @@ -81,8 +83,15 @@ public class Main Configuration configuration = new Configuration(f); IDGLoader idgLoader = obtainLoader(configuration); load(idgLoader); - } catch (Throwable e) { - GuiDisplayer.INSTANCE.displayGui(obtainErrorGUI(e)); + } catch (NoSuitableLoaderFoundException e) { + e.printStackTrace(); + GuiDisplayer.INSTANCE.displayGui(new GuiLoadingError(e)); + } catch (NoVersionFoundException e) { + e.printStackTrace(); + GuiDisplayer.INSTANCE.displayGui(new GuiLoadingError(e)); + } catch (DungeonsGuideLoadingException e) { + e.printStackTrace(); + GuiDisplayer.INSTANCE.displayGui(new GuiLoadingError(e)); } } @@ -99,7 +108,7 @@ public class Main } currentLoader = null; } - private void load(IDGLoader newLoader) throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException { + private void load(IDGLoader newLoader) throws DungeonsGuideLoadingException { if (dgInterface != null) throw new IllegalStateException("DG is loaded"); dgInterface = newLoader.loadDungeonsGuide(); currentLoader = newLoader; @@ -114,28 +123,18 @@ public class Main try { unload(); load(newLoader); - } catch (Exception e) { + } catch (DungeonsGuideLoadingException | ReferenceLeakedException e) { dgInterface = null; currentLoader = null; e.printStackTrace(); - GuiDisplayer.INSTANCE.displayGui(obtainErrorGUI(e)); - } - } - - 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) { - return new GuiReferenceLeak(lastError); - } else if (lastError != null){ - return new GuiLoadingError(lastError); + if (e instanceof DungeonsGuideLoadingException) { + GuiDisplayer.INSTANCE.displayGui(new GuiLoadingError(e)); + } else { + GuiDisplayer.INSTANCE.displayGui(new GuiReferenceLeak(e)); + } } - // when gets called init and stuff remove thing - return null; } @@ -149,7 +148,7 @@ public class Main } - public IDGLoader obtainLoader(Configuration configuration) { + public IDGLoader obtainLoader(Configuration configuration) throws NoVersionFoundException, NoSuitableLoaderFoundException { String loader = getLoaderName(configuration); if ("local".equals(loader) || @@ -158,7 +157,7 @@ public class Main } else if ("jar".equals(loader) || (loader.equals("auto") && this.getClass().getResourceAsStream("/mod.jar") == null)) { return new JarLoader(); - } else if (loader.equals("auto") ){ + } else if (loader.equals("remote") || loader.equals("auto") ){ // remote load 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"); @@ -167,11 +166,9 @@ public class Main 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); + throw new NoVersionFoundException(branch, version, "IO err", e); } } else { throw new NoSuitableLoaderFoundException(System.getProperty("dg.loader"), configuration.get("loader", "modsource", "auto").getString()); @@ -182,31 +179,28 @@ public class Main public void preInit(FMLPreInitializationEvent preInitializationEvent) { // setup static variables main = this; + dgInterface = null; + currentLoader = null; configDir = preInitializationEvent.getModConfigurationDirectory(); // setup preinit progress bar for well, progress bar! ProgressManager.ProgressBar bar = ProgressManager.push("DungeonsGuide", 1); + // Try authenticate + bar.step("Authenticating..."); + try { - // Try authenticate - bar.step("Authenticating..."); AuthManager.getInstance().init(); + } catch (Exception e) { + e.printStackTrace(); + } + File f = new File(preInitializationEvent.getModConfigurationDirectory(), "loader.cfg"); + Configuration configuration = new Configuration(f); + // Save config because... well to generate it + configuration.save(); - // If authentication succeeds, obtain loader and partially load dungeons guide - - File f = new File(preInitializationEvent.getModConfigurationDirectory(), "loader.cfg"); - Configuration configuration = new Configuration(f); - // Save config because... well to generate it - configuration.save(); - } catch (Throwable t) { - dgInterface = null; - currentLoader = null; - - t.printStackTrace(); - } finally { - while(bar.getStep() < bar.getSteps()) bar.step(""); - ProgressManager.pop(bar); - } + while(bar.getStep() < bar.getSteps()) bar.step(""); + ProgressManager.pop(bar); ((IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager()).registerReloadListener(a -> { if (dgInterface != null) dgInterface.onResourceReload(a); 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 c3dd747a..c6834a47 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,27 +2,18 @@ package kr.syeyoung.dungeonsguide.launcher.auth; import com.google.common.base.Throwables; import com.google.common.util.concurrent.ThreadFactoryBuilder; -import com.mojang.authlib.exceptions.AuthenticationException; -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.exceptions.auth.AuthFailedExeption; +import kr.syeyoung.dungeonsguide.launcher.exceptions.auth.AuthenticationUnavailableException; +import kr.syeyoung.dungeonsguide.launcher.exceptions.auth.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 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.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.spec.InvalidKeySpecException; import java.util.concurrent.*; @@ -45,10 +36,14 @@ public class AuthManager { else return null; } + /** + * @throws AuthenticationUnavailableException variations of it. + * @return actual dg token + */ 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 NullToken) throw new AuthenticationUnavailableException("Null Token"); else if (currentToken instanceof PrivacyPolicyRequiredToken) throw new PrivacyPolicyRequiredException(); throw new IllegalStateException("weird token: "+currentToken); } @@ -104,8 +99,7 @@ public class AuthManager { GuiDisplayer.INSTANCE.displayGui(new GuiPrivacyPolicy()); throw new PrivacyPolicyRequiredException(); } - } catch (NoSuchAlgorithmException | AuthenticationException | IOException | NoSuchPaddingException | - InvalidKeyException | InvalidKeySpecException | IllegalBlockSizeException | BadPaddingException e) { + } catch (Exception 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); @@ -118,7 +112,7 @@ public class AuthManager { } - AuthToken acceptPrivacyPolicy() throws IOException { + AuthToken acceptPrivacyPolicy() { if (reauthLock) { while(reauthLock); return currentToken; @@ -129,11 +123,11 @@ public class AuthManager { try { currentToken = DgAuthUtil.acceptNewPrivacyPolicy(currentToken.getToken()); if (currentToken instanceof PrivacyPolicyRequiredToken) throw new PrivacyPolicyRequiredException(); - } catch (IOException e) { + } catch (Exception e) { currentToken = new FailedAuthToken(e); // TODO: loader notifications on bottom right? logger.error("Accepting Privacy Policy failed with message {}, trying again in a 2 seconds", String.valueOf(Throwables.getRootCause(e))); - throw e; + throw new AuthFailedExeption(e); } finally { reauthLock = false; } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthUtil.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthUtil.java index e5408f0b..3b1adaf2 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthUtil.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthUtil.java @@ -6,7 +6,6 @@ import com.google.gson.JsonParser; import javax.crypto.*; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; -import javax.net.ssl.HttpsURLConnection; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -19,9 +18,6 @@ public class AuthUtil { private AuthUtil() {} public static PublicKey getPublicKey(byte[] bytes) throws NoSuchAlgorithmException, InvalidKeySpecException { - PublicKey publicKey = - KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(bytes)); - publicKey.getEncoded(); - return publicKey; + return KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(bytes)); } } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DGResponse.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DGResponse.java index 5873fbda..d69fba44 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DGResponse.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DGResponse.java @@ -7,6 +7,7 @@ import org.json.JSONObject; @Data @AllArgsConstructor public class DGResponse<T> { + private final int responseCode; private final String status; private final T data; private final String errorMessage; diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DgAuthUtil.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DgAuthUtil.java index 78fc91c9..68a31ccd 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DgAuthUtil.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DgAuthUtil.java @@ -1,7 +1,5 @@ package kr.syeyoung.dungeonsguide.launcher.auth; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import com.mojang.authlib.GameProfile; import com.mojang.authlib.exceptions.AuthenticationException; import com.mojang.authlib.minecraft.MinecraftSessionService; @@ -9,9 +7,8 @@ import kr.syeyoung.dungeonsguide.launcher.Main; import kr.syeyoung.dungeonsguide.launcher.auth.token.AuthToken; import kr.syeyoung.dungeonsguide.launcher.auth.token.DGAuthToken; import kr.syeyoung.dungeonsguide.launcher.auth.token.PrivacyPolicyRequiredToken; -import kr.syeyoung.dungeonsguide.launcher.exceptions.AuthServerException; -import kr.syeyoung.dungeonsguide.launcher.exceptions.PrivacyPolicyRequiredException; -import kr.syeyoung.dungeonsguide.launcher.exceptions.ResponseParsingException; +import kr.syeyoung.dungeonsguide.launcher.exceptions.http.AuthServerException; +import kr.syeyoung.dungeonsguide.launcher.exceptions.http.ResponseParsingException; import net.minecraft.client.Minecraft; import net.minecraft.util.Session; import org.apache.commons.codec.binary.Base64; @@ -22,10 +19,10 @@ import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; -import javax.net.ssl.HttpsURLConnection; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; +import java.net.HttpURLConnection; import java.net.URL; import java.security.*; import java.security.spec.InvalidKeySpecException; @@ -35,8 +32,17 @@ public class DgAuthUtil { private static final SecureRandom random = new SecureRandom(); private DgAuthUtil(){} - - private static <T> DGResponse<T> getResponse(HttpsURLConnection connection, Class<T> data) throws IOException { + /** + * + * @param connection + * @param data + * @return + * @param <T> + * @throws IOException when stuff wrong + * @throws ResponseParsingException failed to parse generic response + * @throws AuthServerException auth server returned FAILURE + */ + private static <T> T getResponse(HttpURLConnection connection, Class<T> data) throws IOException { connection.getResponseCode(); InputStream toRead = connection.getErrorStream(); if (toRead == null) @@ -45,24 +51,30 @@ public class DgAuthUtil { try { JSONObject json = new JSONObject(payload); - return new DGResponse( + DGResponse<T> response = new DGResponse<>( + connection.getResponseCode(), json.getString("status"), - (T) json.get("data"), - json.getString("errorMessage"), - json.getString("qrCode") + json.isNull("data") ? null:(T) json.get("data"), + json.isNull("errorMessage") ?null: json.getString("errorMessage"), + json.isNull("qrCode") ? null: json.getString("qrCode") ); - } catch (Exception e) { - throw new ResponseParsingException(payload, e.getMessage()); + + if (!"SUCCESS".equals(response.getStatus())) { + throw new AuthServerException(response); + } + + return (T) response.getData(); + } catch (Exception e) { + throw new ResponseParsingException(payload, e); } finally { toRead.close(); } - } public static String requestAuth() throws IOException { GameProfile profile = Minecraft.getMinecraft().getSession().getProfile(); - HttpsURLConnection connection = (HttpsURLConnection) new URL(Main.DOMAIN + "/auth/requestAuth").openConnection(); + HttpURLConnection connection = (HttpURLConnection) new URL(Main.DOMAIN + "/auth/v2/requestAuth").openConnection(); connection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); connection.setRequestProperty("Content-Type", "application/json"); connection.setRequestMethod("POST"); @@ -71,24 +83,25 @@ public class DgAuthUtil { connection.getOutputStream().write(("{\"uuid\":\""+profile.getId().toString()+"\",\"nickname\":\""+profile.getName()+"\"}").getBytes()); - DGResponse<String> preToken = getResponse(connection, String.class); - if (!"SUCCESS".equals(preToken.getStatus())) { - throw new AuthServerException(preToken); - } - - return preToken.getData(); + return getResponse(connection, String.class); } public static byte[] checkSessionAuthenticityAndReturnEncryptedSecret(String tempToken) throws NoSuchAlgorithmException, AuthenticationException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException { - JSONObject d = getJwtPayload(tempToken); - byte[] sharedSecret = new byte[16]; - random.nextBytes(sharedSecret); - byte[] publicKey =Base64.decodeBase64(d.getString("publicKey")); - - Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.ENCRYPT_MODE, AuthUtil.getPublicKey(publicKey)); - byte[] result = cipher.doFinal(sharedSecret); + byte[] sharedSecret = new byte[16]; + byte[] result; + byte[] publicKey; + try { + JSONObject d = getJwtPayload(tempToken); + random.nextBytes(sharedSecret); + publicKey = Base64.decodeBase64(d.getString("publicKey")); + + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, AuthUtil.getPublicKey(publicKey)); + result = cipher.doFinal(sharedSecret); + } catch (Exception e) { + throw new RuntimeException("Failed to parse publicKey, generate shared secret, then encrypt it.", e); + } String hash = calculateServerHash(sharedSecret, publicKey); @@ -99,8 +112,17 @@ public class DgAuthUtil { return result; } + /** + * + * @param tempToken + * @param encSecret + * @return + * @throws IOException when io error happens + * @throws ResponseParsingException when fails to parse exception + * @throws AuthServerException when auth server throws error + */ public static AuthToken verifyAuth(String tempToken, byte[] encSecret) throws IOException { - HttpsURLConnection urlConnection = (HttpsURLConnection) new URL(Main.DOMAIN + "/auth/authenticate").openConnection(); + HttpURLConnection urlConnection = (HttpURLConnection) new URL(Main.DOMAIN + "/auth/v2/authenticate").openConnection(); urlConnection.setRequestMethod("POST"); urlConnection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); urlConnection.setRequestProperty("Content-Type", "application/json"); @@ -109,22 +131,22 @@ public class DgAuthUtil { urlConnection.getOutputStream().write(("{\"jwt\":\""+tempToken+"\",\"sharedSecret\":\""+Base64.encodeBase64URLSafeString(encSecret)+"\"}").getBytes()); - DGResponse<JSONObject> postToken = getResponse(urlConnection, JSONObject.class); - if (!"SUCCESS".equals(postToken.getStatus())) { - throw new AuthServerException(postToken); - } - JSONObject data = postToken.getData(); - if (data.getString("result").equals("TOS_PRIVACY_POLICY_ACCEPT_REQUIRED")) { - return new PrivacyPolicyRequiredToken(data.getString("jwt")); - } else if (data.getString("result").equals("SUCCESSFUL")) { - return new DGAuthToken(data.getString("jwt")); - } else { - throw new AuthServerException(postToken); + JSONObject data = getResponse(urlConnection, JSONObject.class); + try { + if (data.getString("result").equals("TOS_PRIVACY_POLICY_ACCEPT_REQUIRED")) { + return new PrivacyPolicyRequiredToken(data.getString("jwt")); + } else if (data.getString("result").equals("SUCCESSFUL")) { + return new DGAuthToken(data.getString("jwt")); + } else { + throw new UnsupportedOperationException("Unknown auth result"); + } + } catch (Exception e) { + throw new ResponseParsingException(data.toString(), e); } } public static AuthToken acceptNewPrivacyPolicy(String tempToken) throws IOException { - HttpsURLConnection urlConnection = (HttpsURLConnection) new URL(Main.DOMAIN + "/auth/acceptPrivacyPolicy").openConnection(); + HttpURLConnection urlConnection = (HttpURLConnection) new URL(Main.DOMAIN + "/auth/v2/acceptPrivacyPolicy").openConnection(); urlConnection.setRequestMethod("POST"); urlConnection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); urlConnection.setRequestProperty("Content-Type", "application/json"); @@ -133,17 +155,17 @@ public class DgAuthUtil { urlConnection.getOutputStream().write(tempToken.getBytes()); - DGResponse<JSONObject> postToken = getResponse(urlConnection, JSONObject.class); - if (!"SUCCESS".equals(postToken.getStatus())) { - throw new AuthServerException(postToken); - } - JSONObject data = postToken.getData(); - if (data.getString("result").equals("TOS_PRIVACY_POLICY_ACCEPT_REQUIRED")) { - return new PrivacyPolicyRequiredToken(data.getString("jwt")); - } else if (data.getString("result").equals("SUCCESSFUL")) { - return new DGAuthToken(data.getString("jwt")); - } else { - throw new AuthServerException(postToken); + JSONObject data = getResponse(urlConnection, JSONObject.class); + try { + if (data.getString("result").equals("TOS_PRIVACY_POLICY_ACCEPT_REQUIRED")) { + return new PrivacyPolicyRequiredToken(data.getString("jwt")); + } else if (data.getString("result").equals("SUCCESSFUL")) { + return new DGAuthToken(data.getString("jwt")); + } else { + throw new UnsupportedOperationException("Unknown auth result"); + } + } catch (Exception e) { + throw new ResponseParsingException(data.toString(), e); } } public static JSONObject getJwtPayload(String jwt) { diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/UpdateRetrieverUtil.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/UpdateRetrieverUtil.java index fe7e54dd..abc0cff4 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/UpdateRetrieverUtil.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/UpdateRetrieverUtil.java @@ -1,21 +1,19 @@ package kr.syeyoung.dungeonsguide.launcher.branch; import kr.syeyoung.dungeonsguide.launcher.Main; -import kr.syeyoung.dungeonsguide.launcher.auth.DGResponse; +import kr.syeyoung.dungeonsguide.launcher.auth.AuthManager; import kr.syeyoung.dungeonsguide.launcher.exceptions.AssetNotFoundException; import kr.syeyoung.dungeonsguide.launcher.exceptions.NoVersionFoundException; -import kr.syeyoung.dungeonsguide.launcher.exceptions.ResponseParsingException; +import kr.syeyoung.dungeonsguide.launcher.exceptions.http.ResponseParsingException; import lombok.Builder; import lombok.Data; import org.apache.commons.io.IOUtils; import org.json.JSONArray; import org.json.JSONObject; -import javax.net.ssl.HttpsURLConnection; import java.io.IOException; import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.ProtocolException; +import java.net.HttpURLConnection; import java.net.URL; import java.time.Instant; import java.util.List; @@ -24,94 +22,110 @@ import java.util.UUID; import java.util.stream.Collectors; public class UpdateRetrieverUtil { - private static String getResponse(HttpsURLConnection connection) throws IOException { + private static String getResponse(HttpURLConnection connection) throws IOException { connection.getResponseCode(); InputStream toRead = connection.getErrorStream(); if (toRead == null) toRead = connection.getInputStream(); - String payload = IOUtils.readLines(toRead).stream().collect(Collectors.joining("\n")); - return payload; + return IOUtils.readLines(toRead).stream().collect(Collectors.joining("\n")); } public static List<UpdateBranch> getUpdateBranches() throws IOException { - HttpsURLConnection connection = (HttpsURLConnection) new URL(Main.DOMAIN + "/updates/").openConnection(); + HttpURLConnection connection = (HttpURLConnection) new URL(Main.DOMAIN + "/updates/").openConnection(); connection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); - connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("Authorization", "Bearer "+ AuthManager.getInstance().getWorkingTokenOrThrow()); connection.setRequestMethod("GET"); connection.setDoInput(true); connection.setDoOutput(true); - JSONArray jsonArray = new JSONArray(getResponse(connection)); - return jsonArray.toList() - .stream() - .map(a -> (JSONObject)a) - .map(a -> { - UpdateBranch updateBranch = new UpdateBranch(); - updateBranch.setId(a.getLong("id")); - updateBranch.setName(a.getString("name")); - updateBranch.setMetadata(a.getJSONObject("metadata")); - return updateBranch; - }).collect(Collectors.toList()); + String payload = getResponse(connection); + try { + JSONArray jsonArray = new JSONArray(payload); + return jsonArray.toList() + .stream() + .map(a -> (JSONObject) a) + .map(a -> { + UpdateBranch updateBranch = new UpdateBranch(); + updateBranch.setId(a.getLong("id")); + updateBranch.setName(a.getString("name")); + updateBranch.setMetadata(a.getJSONObject("metadata")); + return updateBranch; + }).collect(Collectors.toList()); + } catch (Exception e) { + throw new ResponseParsingException(payload, e); + } } public static List<Update> getLatestUpdates(long branchId, int page) throws IOException { - HttpsURLConnection connection = (HttpsURLConnection) new URL(Main.DOMAIN + "/updates/"+branchId+"/?page="+page).openConnection(); + HttpURLConnection connection = (HttpURLConnection) new URL(Main.DOMAIN + "/updates/"+branchId+"/?page="+page).openConnection(); connection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); connection.setRequestMethod("GET"); + connection.setRequestProperty("Authorization", "Bearer "+ AuthManager.getInstance().getWorkingTokenOrThrow()); connection.setDoInput(true); connection.setDoOutput(true); - JSONArray jsonArray = new JSONArray(getResponse(connection)); - return jsonArray.toList() - .stream() - .map(a -> (JSONObject)a) - .map(a -> { - Update update = new Update(); - update.setId(a.getLong("id")); - update.setBranchId(a.getLong("branchId")); - update.setName(a.getString("name")); - update.setUpdateLog(a.getString("updateLog")); - update.setMetadata(a.getJSONObject("metadata")); - update.setAssets(a.getJSONObject("assets").getJSONArray("assets").toList().stream().map(b -> (JSONObject)b) - .map(b -> { - Update.Asset asset = new Update.Asset(); - asset.setName(b.getString("name")); - asset.setAssetId(UUID.fromString(b.getString("assetId"))); - asset.setSize(b.getLong("size")); - asset.setObjectId(b.getString("objectId")); - return asset; - }).collect(Collectors.toList())); - update.setReleaseDate(Instant.parse(a.getString("releaseDate"))); - return update; - }).collect(Collectors.toList()); + String payload = getResponse(connection); + try { + JSONArray jsonArray = new JSONArray(payload); + return jsonArray.toList() + .stream() + .map(a -> (JSONObject) a) + .map(a -> { + Update update = new Update(); + update.setId(a.getLong("id")); + update.setBranchId(a.getLong("branchId")); + update.setName(a.getString("name")); + update.setUpdateLog(a.getString("updateLog")); + update.setMetadata(a.getJSONObject("metadata")); + update.setAssets(a.getJSONObject("assets").getJSONArray("assets").toList().stream().map(b -> (JSONObject) b) + .map(b -> { + Update.Asset asset = new Update.Asset(); + asset.setName(b.getString("name")); + asset.setAssetId(UUID.fromString(b.getString("assetId"))); + asset.setSize(b.getLong("size")); + asset.setObjectId(b.getString("objectId")); + return asset; + }).collect(Collectors.toList())); + update.setReleaseDate(Instant.parse(a.getString("releaseDate"))); + return update; + }).collect(Collectors.toList()); + } catch (Exception e) { + throw new ResponseParsingException(payload, e); + } } public static Update getUpdate(long branchId, long updateId) throws IOException { - HttpsURLConnection connection = (HttpsURLConnection) new URL(Main.DOMAIN + "/updates/"+branchId+"/"+updateId).openConnection(); + HttpURLConnection connection = (HttpURLConnection) new URL(Main.DOMAIN + "/updates/"+branchId+"/"+updateId).openConnection(); connection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); + connection.setRequestProperty("Authorization", "Bearer "+ AuthManager.getInstance().getWorkingTokenOrThrow()); connection.setRequestMethod("GET"); connection.setDoInput(true); connection.setDoOutput(true); - JSONObject a = new JSONObject(getResponse(connection)); - - Update update = new Update(); - update.setId(a.getLong("id")); - update.setBranchId(a.getLong("branchId")); - update.setName(a.getString("name")); - update.setUpdateLog(a.getString("updateLog")); - update.setMetadata(a.getJSONObject("metadata")); - update.setAssets(a.getJSONObject("assets").getJSONArray("assets").toList().stream().map(b -> (JSONObject)b) - .map(b -> { - Update.Asset asset = new Update.Asset(); - asset.setName(b.getString("name")); - asset.setAssetId(UUID.fromString(b.getString("assetId"))); - asset.setSize(b.getLong("size")); - asset.setObjectId(b.getString("objectId")); - return asset; - }).collect(Collectors.toList())); - update.setReleaseDate(Instant.parse(a.getString("releaseDate"))); - return update; + String payload = getResponse(connection); + try { + JSONObject a = new JSONObject(); + + Update update = new Update(); + update.setId(a.getLong("id")); + update.setBranchId(a.getLong("branchId")); + update.setName(a.getString("name")); + update.setUpdateLog(a.getString("updateLog")); + update.setMetadata(a.getJSONObject("metadata")); + update.setAssets(a.getJSONObject("assets").getJSONArray("assets").toList().stream().map(b -> (JSONObject) b) + .map(b -> { + Update.Asset asset = new Update.Asset(); + asset.setName(b.getString("name")); + asset.setAssetId(UUID.fromString(b.getString("assetId"))); + asset.setSize(b.getLong("size")); + asset.setObjectId(b.getString("objectId")); + return asset; + }).collect(Collectors.toList())); + update.setReleaseDate(Instant.parse(a.getString("releaseDate"))); + return update; + } catch (Exception e) { + throw new ResponseParsingException(payload, e); + } } public static InputStream downloadFile(Update update, String assetName) throws IOException { @@ -119,17 +133,22 @@ public class UpdateRetrieverUtil { .findFirst().orElseThrow(() -> new AssetNotFoundException(update.getBranchId()+"", update.getId()+"("+update.getName()+")", assetName)); - HttpsURLConnection connection = (HttpsURLConnection) new URL(Main.DOMAIN + "/updates/"+update.getBranchId()+"/"+update.getId()+"/"+asset.getAssetId()).openConnection(); + HttpURLConnection connection = (HttpURLConnection) new URL(Main.DOMAIN + "/updates/"+update.getBranchId()+"/"+update.getId()+"/"+asset.getAssetId()).openConnection(); connection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); connection.setRequestMethod("GET"); connection.setDoInput(true); connection.setDoOutput(true); - JSONObject result = new JSONObject(getResponse(connection)); - String url = result.getString("url"); - String method = result.getString("method"); - - connection = (HttpsURLConnection) new URL(url).openConnection(); + String payload = getResponse(connection); + String url, method; + try { + JSONObject result = new JSONObject(payload); + url = result.getString("url"); + method = result.getString("method"); + } catch (Exception e) { + throw new ResponseParsingException(payload, e); + } + connection = (HttpURLConnection) new URL(url).openConnection(); connection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); connection.setRequestMethod(method); return connection.getInputStream(); @@ -142,41 +161,55 @@ public class UpdateRetrieverUtil { String friendlyVersionName = ""; long updateId; } - public static VersionInfo getIds(String branch, String version) throws IOException { - long branchId = -1, updateId = -1; - UpdateBranch branch1 = null; - for (UpdateBranch updateBranch : UpdateRetrieverUtil.getUpdateBranches()) { + public static VersionInfo getIds(String branch, String version) throws IOException, NoVersionFoundException { + try { + long branchId = -1, updateId = -1; + UpdateBranch branch1 = null; + List<UpdateBranch> branches = UpdateRetrieverUtil.getUpdateBranches(); + for (UpdateBranch updateBranch : branches) { if (updateBranch.getName().equals(branch) || (branch.equals("$default") && Optional.ofNullable(updateBranch.getMetadata()) - .map(a -> a.getJSONObject("additionalMeta")) - .map(a -> a.getBoolean("defaultMod")).orElse(false))) { + .map(a -> a.isNull("additionalMeta") ? null : a.getJSONObject("additionalMeta")) + .map(a -> a.isNull("defaultMod") ? null : a.getBoolean("defaultMod")).orElse(false))) { branchId = updateBranch.getId(); branch1 = updateBranch; break; } } - if (branchId == -1) return null; - - Update target = null; - int page = 0; - while (updateId == -1) { - List<Update> updateList = UpdateRetrieverUtil.getLatestUpdates(branchId, page++); - if (updateList == null || updateList.isEmpty()) return null; - for (Update update : updateList) { - if (update.getName().equals(version) || version.equals("latest")) { // if latest, get the first one. - updateId = update.getId(); - target = update; - break; + if (branchId == -1) { + throw new NoVersionFoundException(branch, version, + branches.stream() + .map(a -> a.getName() + + Optional.ofNullable(a.getMetadata()).map(b -> b.getJSONObject("additionalMeta")).map(b -> b.toString()).orElse("")) + .collect(Collectors.joining(", ")) + ); + } + + Update target = null; + int page = 0; + while (updateId == -1) { + List<Update> updateList = UpdateRetrieverUtil.getLatestUpdates(branchId, page++); + if (updateList == null || updateList.isEmpty()) { + throw new NoVersionFoundException(branch, version, "Unable to find version / branchId: " + branchId); + } + for (Update update : updateList) { + if (update.getName().equals(version) || version.equals("latest")) { // if latest, get the first one. + updateId = update.getId(); + target = update; + break; + } } } - } - return VersionInfo.builder() - .branchId(branchId) - .updateId(updateId) - .friendlyBranchName(branch1.getName()) - .friendlyVersionName(target.getName()) - .build(); + return VersionInfo.builder() + .branchId(branchId) + .updateId(updateId) + .friendlyBranchName(branch1.getName()) + .friendlyVersionName(target.getName()) + .build(); + } catch (Exception e) { + throw new NoVersionFoundException(branch, version, "Exception occured", e); + } } } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/DungeonsGuideLoadingException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/DungeonsGuideLoadingException.java new file mode 100644 index 00000000..07f72d40 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/DungeonsGuideLoadingException.java @@ -0,0 +1,7 @@ +package kr.syeyoung.dungeonsguide.launcher.exceptions; + +public class DungeonsGuideLoadingException extends Exception { + public DungeonsGuideLoadingException(String message) {super(message);} + public DungeonsGuideLoadingException(Throwable cause) {super(cause);} + public DungeonsGuideLoadingException(String message, Throwable cause) {super(message, cause);} +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/NoSuitableLoaderFoundException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/NoSuitableLoaderFoundException.java index c2f9a907..2f6665d5 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/NoSuitableLoaderFoundException.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/NoSuitableLoaderFoundException.java @@ -20,7 +20,7 @@ package kr.syeyoung.dungeonsguide.launcher.exceptions; import lombok.AllArgsConstructor; -public class NoSuitableLoaderFoundException extends RuntimeException { +public class NoSuitableLoaderFoundException extends Exception { private String jvmFlag; private String configuration; diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/NoVersionFoundException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/NoVersionFoundException.java index b99d12c1..b5b39f32 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/NoVersionFoundException.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/NoVersionFoundException.java @@ -21,17 +21,17 @@ package kr.syeyoung.dungeonsguide.launcher.exceptions; import lombok.Getter; @Getter -public class NoVersionFoundException extends RuntimeException { +public class NoVersionFoundException extends Exception { private String branch; private String version; - public NoVersionFoundException(String branch, String version) { - super("No version found: "+branch+" - "+version); + public NoVersionFoundException(String branch, String version, String payload) { + super("No version found: "+branch+" - "+version+"\n Additional Data: "+payload); this.branch = branch; this.version = version; } - public NoVersionFoundException(String branch, String version, Throwable e) { - super("No version found: "+branch+" - "+version, e); + public NoVersionFoundException(String branch, String version, String payload, Throwable e) { + super("No version found: "+branch+" - "+version+"\n Additional Data: "+payload+"\n "+e.toString(), e); this.branch = branch; this.version = version; } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthFailedExeption.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/auth/AuthFailedExeption.java index d860afb6..25a97353 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthFailedExeption.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/auth/AuthFailedExeption.java @@ -1,4 +1,4 @@ -package kr.syeyoung.dungeonsguide.launcher.exceptions; +package kr.syeyoung.dungeonsguide.launcher.exceptions.auth; public class AuthFailedExeption extends AuthenticationUnavailableException { public AuthFailedExeption(Throwable cause) { diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthenticationUnavailableException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/auth/AuthenticationUnavailableException.java index a42ddd93..674b26d6 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthenticationUnavailableException.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/auth/AuthenticationUnavailableException.java @@ -1,4 +1,4 @@ -package kr.syeyoung.dungeonsguide.launcher.exceptions; +package kr.syeyoung.dungeonsguide.launcher.exceptions.auth; public class AuthenticationUnavailableException extends RuntimeException { public AuthenticationUnavailableException(Throwable cause){ diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/PrivacyPolicyRequiredException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/auth/PrivacyPolicyRequiredException.java index a48632dc..3eee30a5 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/PrivacyPolicyRequiredException.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/auth/PrivacyPolicyRequiredException.java @@ -16,7 +16,7 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -package kr.syeyoung.dungeonsguide.launcher.exceptions; +package kr.syeyoung.dungeonsguide.launcher.exceptions.auth; public class PrivacyPolicyRequiredException extends AuthenticationUnavailableException { } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/TokenExpiredException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/auth/TokenExpiredException.java index 4826b1ba..0f71507c 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/TokenExpiredException.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/auth/TokenExpiredException.java @@ -16,7 +16,7 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -package kr.syeyoung.dungeonsguide.launcher.exceptions; +package kr.syeyoung.dungeonsguide.launcher.exceptions.auth; public class TokenExpiredException extends AuthenticationUnavailableException { diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthServerException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/http/AuthServerException.java index 67647b9b..7784e3ee 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthServerException.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/http/AuthServerException.java @@ -16,23 +16,26 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -package kr.syeyoung.dungeonsguide.launcher.exceptions; +package kr.syeyoung.dungeonsguide.launcher.exceptions.http; import kr.syeyoung.dungeonsguide.launcher.auth.DGResponse; -import kr.syeyoung.dungeonsguide.launcher.util.QRCodeGenerator; -import org.json.JSONObject; - -import java.util.Objects; +import kr.syeyoung.dungeonsguide.launcher.exceptions.auth.AuthenticationUnavailableException; public class AuthServerException extends AuthenticationUnavailableException { private DGResponse response; public AuthServerException(DGResponse response) { - super(response.getErrorMessage() == null ? "Invalid Server Response" : response.getErrorMessage()); + super(response.getErrorMessage()); this.response = response; } public String getQRCode() { return response.getQrCode() == null ? null : response.getQrCode(); } + + + @Override + public String toString() { + return super.toString()+"\n Server ResponseCode: "+response.getResponseCode(); + } } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/ResponseParsingException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/http/ResponseParsingException.java index 3933b78e..59454e17 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/ResponseParsingException.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/http/ResponseParsingException.java @@ -16,18 +16,32 @@ * along with this program. If not, see <https://www.gnu.org/licenses/>. */ -package kr.syeyoung.dungeonsguide.launcher.exceptions; +package kr.syeyoung.dungeonsguide.launcher.exceptions.http; import lombok.Getter; import org.json.JSONObject; public class ResponseParsingException extends RuntimeException { @Getter - private String payload; + private final String payload; + + public ResponseParsingException(String payload, Exception e) { + super(e); + this.payload = payload; + } + + public ResponseParsingException(String payload, String message, Exception e) { + super(message, e); + this.payload = payload; + } public ResponseParsingException(String payload, String message) { super(message); this.payload = payload; } + @Override + public String toString() { + return super.toString()+"\n Problematic Message: "+payload; + } } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/IDGLoader.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/IDGLoader.java index a79fdb7e..1edc0b7c 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/IDGLoader.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/IDGLoader.java @@ -19,12 +19,13 @@ package kr.syeyoung.dungeonsguide.launcher.loader; import kr.syeyoung.dungeonsguide.launcher.DGInterface; +import kr.syeyoung.dungeonsguide.launcher.exceptions.DungeonsGuideLoadingException; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; import java.io.IOException; public interface IDGLoader { - DGInterface loadDungeonsGuide() throws InstantiationException, IllegalAccessException, ClassNotFoundException, IOException; + DGInterface loadDungeonsGuide() throws DungeonsGuideLoadingException; DGInterface getInstance(); void unloadDungeonsGuide() throws ReferenceLeakedException; diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/JarLoader.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/JarLoader.java index fa86054d..2a448e97 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/JarLoader.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/JarLoader.java @@ -20,6 +20,7 @@ package kr.syeyoung.dungeonsguide.launcher.loader; import kr.syeyoung.dungeonsguide.launcher.DGInterface; import kr.syeyoung.dungeonsguide.launcher.Main; +import kr.syeyoung.dungeonsguide.launcher.exceptions.DungeonsGuideLoadingException; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; import org.apache.commons.io.IOUtils; import sun.misc.Resource; @@ -73,14 +74,18 @@ public class JarLoader implements IDGLoader { private JarClassLoader classLoader; @Override - public DGInterface loadDungeonsGuide() throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException { + public DGInterface loadDungeonsGuide() throws DungeonsGuideLoadingException { if (dgInterface != null) throw new IllegalStateException("Already loaded"); - classLoader = new JarClassLoader(this.getClass().getClassLoader(), new ZipInputStream(JarLoader.class.getResourceAsStream("/mod.jar"))); + try { + classLoader = new JarClassLoader(this.getClass().getClassLoader(), new ZipInputStream(JarLoader.class.getResourceAsStream("/mod.jar"))); - dgInterface = (DGInterface) classLoader.loadClass("kr.syeyoung.dungeonsguide.DungeonsGuide", true).newInstance(); - phantomReference = new PhantomReference<>(classLoader, refQueue); - return dgInterface; + dgInterface = (DGInterface) classLoader.loadClass("kr.syeyoung.dungeonsguide.DungeonsGuide", true).newInstance(); + phantomReference = new PhantomReference<>(classLoader, refQueue); + return dgInterface; + } catch (Exception e) { + throw new DungeonsGuideLoadingException(e); + } } @Override diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/LocalLoader.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/LocalLoader.java index 683f77d0..267f66d8 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/LocalLoader.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/LocalLoader.java @@ -19,6 +19,7 @@ package kr.syeyoung.dungeonsguide.launcher.loader; import kr.syeyoung.dungeonsguide.launcher.DGInterface; +import kr.syeyoung.dungeonsguide.launcher.exceptions.DungeonsGuideLoadingException; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; import org.apache.commons.io.IOUtils; @@ -60,14 +61,18 @@ public class LocalLoader implements IDGLoader { private LocalClassLoader classLoader; @Override - public DGInterface loadDungeonsGuide() throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException { + public DGInterface loadDungeonsGuide() throws DungeonsGuideLoadingException { if (dgInterface != null) throw new IllegalStateException("Already loaded"); - classLoader = new LocalClassLoader(this.getClass().getClassLoader()); + try { + classLoader = new LocalClassLoader(this.getClass().getClassLoader()); - dgInterface = (DGInterface) classLoader.loadClass("kr.syeyoung.dungeonsguide.DungeonsGuide", true).newInstance(); - phantomReference = new PhantomReference<>(classLoader, refQueue); - return dgInterface; + dgInterface = (DGInterface) classLoader.loadClass("kr.syeyoung.dungeonsguide.DungeonsGuide", true).newInstance(); + phantomReference = new PhantomReference<>(classLoader, refQueue); + return dgInterface; + } catch (Exception e) { + throw new DungeonsGuideLoadingException(e); + } } @Override diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/RemoteLoader.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/RemoteLoader.java index 719f5cce..860c5a9c 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/RemoteLoader.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/RemoteLoader.java @@ -22,6 +22,7 @@ import kr.syeyoung.dungeonsguide.launcher.DGInterface; import kr.syeyoung.dungeonsguide.launcher.branch.Update; import kr.syeyoung.dungeonsguide.launcher.branch.UpdateBranch; import kr.syeyoung.dungeonsguide.launcher.branch.UpdateRetrieverUtil; +import kr.syeyoung.dungeonsguide.launcher.exceptions.DungeonsGuideLoadingException; import kr.syeyoung.dungeonsguide.launcher.exceptions.InvalidSignatureException; import kr.syeyoung.dungeonsguide.launcher.exceptions.NoVersionFoundException; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; @@ -82,30 +83,38 @@ public class RemoteLoader implements IDGLoader { @Override - public DGInterface loadDungeonsGuide() throws ClassNotFoundException, InstantiationException, IllegalAccessException, IOException { + public DGInterface loadDungeonsGuide() throws DungeonsGuideLoadingException { if (dgInterface != null) throw new IllegalStateException("Already loaded"); + try { + Update target; + try { + target = UpdateRetrieverUtil.getUpdate(branchId, updateId); + friendlyVersionName = target.getName(); + } catch (Exception e) { + throw new NoVersionFoundException(friendlyBranchName, friendlyVersionName, branchId+"@"+updateId, e); + } - Update target = UpdateRetrieverUtil.getUpdate(branchId, updateId); - friendlyVersionName = target.getName(); + InputStream in; + byte[] mod = IOUtils.toByteArray(in = UpdateRetrieverUtil.downloadFile(target, "mod.jar")); + in.close(); + byte[] signature = IOUtils.toByteArray(in = UpdateRetrieverUtil.downloadFile(target, "signature.asc")); + in.close(); + int version = target.getMetadata().getInt("signatureVersion"); + + if (version == 0) { + SignatureValidator.validateVersion1Signature(target, mod, signature); + } else { + throw new InvalidSignatureException(target, "Invalid Signature Version: " + version); + } - InputStream in; - byte[] mod = IOUtils.toByteArray(in = UpdateRetrieverUtil.downloadFile(target, "mod.jar")); - in.close(); - byte[] signature =IOUtils.toByteArray(in = UpdateRetrieverUtil.downloadFile(target, "signature.asc")); - in.close(); - int version = target.getMetadata().getInt("signatureVersion"); + classLoader = new JarClassLoader(this.getClass().getClassLoader(), new ZipInputStream(new ByteArrayInputStream(mod))); - if (version == 0) { - SignatureValidator.validateVersion1Signature(target, mod, signature); - } else { - throw new InvalidSignatureException(target, "Invalid Signature Version: "+version); + dgInterface = (DGInterface) classLoader.loadClass("kr.syeyoung.dungeonsguide.DungeonsGuide", true).newInstance(); + phantomReference = new PhantomReference<>(classLoader, refQueue); + return dgInterface; + } catch (Exception e) { + throw new DungeonsGuideLoadingException(e); } - - classLoader = new JarClassLoader(this.getClass().getClassLoader(), new ZipInputStream(new ByteArrayInputStream(mod))); - - dgInterface = (DGInterface) classLoader.loadClass("kr.syeyoung.dungeonsguide.DungeonsGuide", true).newInstance(); - phantomReference = new PhantomReference<>(classLoader, refQueue); - return dgInterface; } @Override |