diff options
author | syeyoung <cyoung06@naver.com> | 2022-11-15 23:26:59 +0900 |
---|---|---|
committer | syeyoung <cyoung06@naver.com> | 2022-11-15 23:52:55 +0900 |
commit | 2893b632b4239dfb116dce853d07369a9fea222d (patch) | |
tree | 2cd5a10264927d861d7d4573b76fb9181078beaa | |
parent | 0b4ce8c26a3126530599786d4a31c4bae44f7ec6 (diff) | |
download | Skyblock-Dungeons-Guide-2893b632b4239dfb116dce853d07369a9fea222d.tar.gz Skyblock-Dungeons-Guide-2893b632b4239dfb116dce853d07369a9fea222d.tar.bz2 Skyblock-Dungeons-Guide-2893b632b4239dfb116dce853d07369a9fea222d.zip |
- Authentication Overhaul to work with new dg 4.0 backend
Signed-off-by: syeyoung <cyoung06@naver.com>
31 files changed, 569 insertions, 577 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 921adca9..efba137d 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,8 @@ package kr.syeyoung.dungeonsguide.launcher; import com.mojang.authlib.exceptions.AuthenticationUnavailableException; import com.mojang.authlib.exceptions.InvalidCredentialsException; +import kr.syeyoung.dungeonsguide.launcher.auth.AuthManager; 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.exceptions.NoSuitableLoaderFoundException; import kr.syeyoung.dungeonsguide.launcher.exceptions.PrivacyPolicyRequiredException; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; @@ -64,10 +63,8 @@ public class Main 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; @@ -221,20 +218,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) { 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 23d9cf06..5aa6962b 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 @@ -4,23 +4,24 @@ 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.auth.token.*; +import kr.syeyoung.dungeonsguide.launcher.events.AuthChangedEvent; +import kr.syeyoung.dungeonsguide.launcher.exceptions.AuthFailedExeption; +import kr.syeyoung.dungeonsguide.launcher.exceptions.PrivacyPolicyRequiredException; 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.InvalidKeyException; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; +import java.security.spec.InvalidKeySpecException; import java.util.Objects; import java.util.concurrent.*; @@ -40,13 +41,12 @@ public class AuthManager { private AuthToken currentToken = new NullToken(); - public String getToken() { - return currentToken.getToken(); + public AuthToken getToken() { + return currentToken; } - - - public KeyPair getKeyPair(){ - return currentToken.getRSAKeyForAuth(); + public String getWorkingTokenOrNull() { + if (currentToken instanceof DGAuthToken) return currentToken.getToken(); + else return null; } @@ -58,83 +58,80 @@ public class AuthManager { return; } - 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(baseserverurl); + byte[] encSecret = DgAuthUtil.checkSessionAuthenticityAndReturnEncryptedSecret(token); + currentToken = DgAuthUtil.verifyAuth(token, encSecret, baseserverurl); + MinecraftForge.EVENT_BUS.post(new AuthChangedEvent(currentToken)); + + if (currentToken instanceof PrivacyPolicyRequiredToken) 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; - currentToken = new NullToken(); - try { - currentProvider = new DgAuth(baseserverurl).createAuthProvider(); - if (currentProvider.getToken() == null) { - shouldReAuth = true; - currentProvider = null; - ChatTransmitter.addToQueue("§eDungeons Guide §7:: §r§cDG auth failed, trying again in ten seconds", true); - logger.info("DG auth failed, trying again in a second"); - } else { - // RE-AUTHed SUCCESSFULLY HOORAY - // for some reason the forge events don't work in pre init, so I call the callback directly - StompManager.getInstance().init(); - MinecraftForge.EVENT_BUS.post(new AuthChangedEvent()); - } - } catch (NoSuchAlgorithmException | AuthenticationException | IOException e) { - shouldReAuth = true; - currentProvider = null; - 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 ten seconds", String.valueOf(Throwables.getRootCause(e))); + AuthToken acceptPrivacyPolicy() throws IOException { + if (reauthLock) { + while(reauthLock); + return currentToken; } + if (currentToken instanceof PrivacyPolicyRequiredToken) { + reauthLock = true; + try { + currentToken = DgAuthUtil.acceptNewPrivacyPolicy(currentToken.getToken(), baseserverurl); + if (currentToken instanceof PrivacyPolicyRequiredToken) throw new PrivacyPolicyRequiredException(); + } catch (IOException 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; + } finally { + reauthLock = false; + } + } + return currentToken; } - - } 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 9ce02643..e5408f0b 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 @@ -12,59 +12,16 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; public class AuthUtil { private AuthUtil() {} - public static KeyPair getKeyPair() throws NoSuchAlgorithmException { - KeyPairGenerator a = null; - a = KeyPairGenerator.getInstance("RSA"); - a.initialize(1024); - return a.generateKeyPair(); - } - - - public static JsonElement getJsonSecured(String u) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException{ - - int length = 0; - CipherInputStream cipherInputStream = null; - - 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", AuthManager.getInstance().getToken()); - httpsURLConnection.setDoInput(true); - httpsURLConnection.setDoOutput(true); - - InputStream inputStream = httpsURLConnection.getInputStream(); - byte[] lengthPayload = new byte[4]; - inputStream.read(lengthPayload); - 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, AuthManager.getInstance().getKeyPair().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 = new CipherInputStream(inputStream, cipher); - cipherInputStream.read(lengthPayload); - length = ((lengthPayload[0] & 0xFF) << 24) | - ((lengthPayload[1] & 0xFF) << 16) | - ((lengthPayload[2] & 0xFF) << 8) | - ((lengthPayload[3] & 0xFF)); - - httpsURLConnection.disconnect(); - - return new JsonParser().parse(new InputStreamReader(cipherInputStream)); + public static PublicKey getPublicKey(byte[] bytes) throws NoSuchAlgorithmException, InvalidKeySpecException { + PublicKey publicKey = + KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(bytes)); + publicKey.getEncoded(); + return publicKey; } } 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 new file mode 100644 index 00000000..5873fbda --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DGResponse.java @@ -0,0 +1,15 @@ +package kr.syeyoung.dungeonsguide.launcher.auth; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.json.JSONObject; + +@Data +@AllArgsConstructor +public class DGResponse<T> { + private final String status; + private final T data; + private final String errorMessage; + private final String qrCode; +} + 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 new file mode 100644 index 00000000..f585ac20 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DgAuthUtil.java @@ -0,0 +1,160 @@ +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; +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 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 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.URL; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.util.stream.Collectors; + +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 { + connection.getResponseCode(); + InputStream toRead = connection.getErrorStream(); + if (toRead == null) + toRead = connection.getInputStream(); + String payload = IOUtils.readLines(toRead).stream().collect(Collectors.joining("\n")); + + try { + JSONObject json = new JSONObject(payload); + return new DGResponse( + json.getString("status"), + (T) json.get("data"), + json.getString("errorMessage"), + json.getString("qrCode") + ); + } catch (Exception e) { + throw new ResponseParsingException(payload, e.getMessage()); + } + + } + + public static String requestAuth(String baseurl) throws IOException { + GameProfile profile = Minecraft.getMinecraft().getSession().getProfile(); + + HttpsURLConnection connection = (HttpsURLConnection) new URL(baseurl + "/auth/requestAuth").openConnection(); + connection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestMethod("POST"); + connection.setDoInput(true); + connection.setDoOutput(true); + + 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(); + } + + 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); + + + String hash = calculateServerHash(sharedSecret, publicKey); + + Session session = Minecraft.getMinecraft().getSession(); + MinecraftSessionService yggdrasilMinecraftSessionService = Minecraft.getMinecraft().getSessionService(); + yggdrasilMinecraftSessionService.joinServer(session.getProfile(), session.getToken(), hash); + + return result; + } + + public static AuthToken verifyAuth(String tempToken, byte[] encSecret, String baseurl) throws IOException { + HttpsURLConnection urlConnection = (HttpsURLConnection) new URL(baseurl + "/auth/authenticate").openConnection(); + urlConnection.setRequestMethod("POST"); + urlConnection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); + urlConnection.setRequestProperty("Content-Type", "application/json"); + urlConnection.setDoInput(true); + urlConnection.setDoOutput(true); + + 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); + } + } + + public static AuthToken acceptNewPrivacyPolicy(String tempToken, String baseurl) throws IOException { + HttpsURLConnection urlConnection = (HttpsURLConnection) new URL(baseurl + "/auth/acceptPrivacyPolicy").openConnection(); + urlConnection.setRequestMethod("POST"); + urlConnection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); + urlConnection.setRequestProperty("Content-Type", "application/json"); + urlConnection.setDoInput(true); + urlConnection.setDoOutput(true); + + 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); + } + } + public static JSONObject getJwtPayload(String jwt) { + String midPart = jwt.split("\\.")[1].replace("+", "-").replace("/", "_"); + String base64Decode = new String(Base64.decodeBase64(midPart)); // padding + return new JSONObject(base64Decode); + } + + public static 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); + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/InvalidDungeonsGuideCredentialsException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/InvalidDungeonsGuideCredentialsException.java deleted file mode 100644 index ebe78196..00000000 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/InvalidDungeonsGuideCredentialsException.java +++ /dev/null @@ -1,8 +0,0 @@ -package kr.syeyoung.dungeonsguide.launcher.auth; - -public class InvalidDungeonsGuideCredentialsException extends Throwable { - - public InvalidDungeonsGuideCredentialsException(String message) { - super(message); - } -} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/ResourceManager.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/ResourceManager.java deleted file mode 100644 index 721b629f..00000000 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/ResourceManager.java +++ /dev/null @@ -1,164 +0,0 @@ -package kr.syeyoung.dungeonsguide.launcher.auth; - -import lombok.Setter; -import net.minecraftforge.common.MinecraftForge; -import org.apache.commons.codec.binary.Base64; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import javax.crypto.*; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import javax.net.ssl.HttpsURLConnection; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.security.*; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; -import java.util.HashMap; -import java.util.Map; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -public class ResourceManager { - - Logger logger = LogManager.getLogger("ResourceManager"); - - @Setter - private String baseUrl; - @Setter - private String BASE64_X509ENCODEDKEYSPEC; - private final HashMap<String, byte[]> loadedResources = new HashMap<>(); - - - private static ResourceManager instance; - public static ResourceManager getInstance() { - if(instance == null) { - instance = new ResourceManager(); - MinecraftForge.EVENT_BUS.register(instance); - } - return instance; - } - - private ResourceManager() { - } - - public Map<String, byte[]> getResources() { - return loadedResources; - } - - - public void downloadAssets(String version) throws InvalidDungeonsGuideCredentialsException { - if(AuthManager.getInstance().getToken() == null) throw new InvalidDungeonsGuideCredentialsException("Not Authenticated while downloading assets"); - try { - // version not being null indicates that the user is "premium" - // so we download the special version - if (version != null) - downloadSafe( baseUrl + "/resource/version?v=" + version, true); - - if(!AuthManager.getInstance().isPlebUser()){ - downloadSafe(baseUrl + "/resource/roomdata", false); - } else { - logger.error("The current User is a pleb not downloading user data"); - } - - } catch (Exception t) { - t.printStackTrace(); - } - - } - - private void downloadSafe(String url, boolean isValidateSignature) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, 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", AuthManager.getInstance().getToken()); - 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, AuthManager.getInstance().getKeyPair().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; - if (isValidateSignature) { - 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(getPublicKey(BASE64_X509ENCODEDKEYSPEC)); - 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; - while((p = zipInputStream.read(buffer)) > 0) { - byteArrayOutputStream.write(buffer, 0, p); - } - this.loadedResources.put(zipEntry.getName(), byteArrayOutputStream.toByteArray()); - } - } - - - public static PublicKey getPublicKey(String base64X509EncodedKeySpec) throws NoSuchAlgorithmException, InvalidKeySpecException { - X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decodeBase64(base64X509EncodedKeySpec)); - - return KeyFactory.getInstance("RSA").generatePublic(spec); - } - -} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/AuthProvider.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/AuthProvider.java deleted file mode 100644 index d469c729..00000000 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/AuthProvider.java +++ /dev/null @@ -1,16 +0,0 @@ -package kr.syeyoung.dungeonsguide.launcher.auth.authprovider; - -import com.mojang.authlib.exceptions.AuthenticationException; - -import java.io.IOException; -import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; - -public interface AuthProvider { - String getToken(); - - KeyPair getRsaKey(); - - - AuthProvider createAuthProvider() throws NoSuchAlgorithmException, AuthenticationException, IOException; -} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/DgAuth/DgAuth.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/DgAuth/DgAuth.java deleted file mode 100644 index dca9ce33..00000000 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/DgAuth/DgAuth.java +++ /dev/null @@ -1,46 +0,0 @@ -package kr.syeyoung.dungeonsguide.launcher.auth.authprovider.DgAuth; - -import com.mojang.authlib.exceptions.AuthenticationException; -import kr.syeyoung.dungeonsguide.launcher.auth.AuthUtil; -import kr.syeyoung.dungeonsguide.launcher.auth.authprovider.AuthProvider; - -import java.io.IOException; -import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; - -public class DgAuth implements AuthProvider { - - private final String authServerUrl; - - public DgAuth(String authServerUrl){ - this.authServerUrl = authServerUrl; - } - - private String token; - private KeyPair rsaKey; - - @Override - public String getToken() { - return token; - } - - @Override - public KeyPair getRsaKey() { - return rsaKey; - } - - - @Override - public AuthProvider createAuthProvider() throws NoSuchAlgorithmException, AuthenticationException, IOException { - this.rsaKey = AuthUtil.getKeyPair(); - - String tempToken = DgAuthUtil.requestAuth(this.authServerUrl); - - DgAuthUtil.checkSessionAuthenticity(tempToken); - - this.token = DgAuthUtil.verifyAuth(tempToken, rsaKey.getPublic(), authServerUrl); - - return this; - } - -} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/DgAuth/DgAuthUtil.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/DgAuth/DgAuthUtil.java deleted file mode 100644 index 53b57e1a..00000000 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/DgAuth/DgAuthUtil.java +++ /dev/null @@ -1,88 +0,0 @@ -package kr.syeyoung.dungeonsguide.launcher.auth.authprovider.DgAuth; - -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; -import net.minecraft.client.Minecraft; -import net.minecraft.util.Session; -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.io.IOUtils; - -import javax.net.ssl.HttpsURLConnection; -import java.io.IOException; -import java.math.BigInteger; -import java.net.URL; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; - -public class DgAuthUtil { - private DgAuthUtil(){} - - public static String requestAuth(String baseurl) throws IOException { - GameProfile profile = Minecraft.getMinecraft().getSession().getProfile(); - - HttpsURLConnection connection = (HttpsURLConnection) new URL(baseurl + "/auth/requestAuth").openConnection(); - connection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); - connection.setRequestProperty("Content-Type", "application/json"); - connection.setRequestMethod("POST"); - connection.setDoInput(true); - connection.setDoOutput(true); - - connection.getOutputStream().write(("{\"uuid\":\""+profile.getId().toString()+"\",\"nickname\":\""+profile.getName()+"\"}").getBytes()); - String payload = String.join("\n", IOUtils.readLines(connection.getErrorStream() == null ? connection.getInputStream() : connection.getErrorStream())); - - JsonObject json = (JsonObject) new JsonParser().parse(payload); - - if (!"ok".equals(json.get("status").getAsString())) { - return null; - } - return json.get("data").getAsString(); - } - - public static void checkSessionAuthenticity(String tempToken) throws NoSuchAlgorithmException, AuthenticationException { - JsonObject d = getJwtPayload(tempToken); - byte[] sharedSecret = Base64.decodeBase64(d.get("sharedSecret").getAsString()); - byte[] publicKey =Base64.decodeBase64(d.get("publicKey").getAsString()); - String hash = calculateServerHash(sharedSecret, publicKey); - - Session session = Minecraft.getMinecraft().getSession(); - MinecraftSessionService yggdrasilMinecraftSessionService = Minecraft.getMinecraft().getSessionService(); - yggdrasilMinecraftSessionService.joinServer(session.getProfile(), session.getToken(), hash); - } - - public static String verifyAuth(String tempToken, PublicKey clientKey, String baseurl) throws IOException { - HttpsURLConnection urlConnection = (HttpsURLConnection) new URL(baseurl + "/auth/authenticate").openConnection(); - urlConnection.setRequestMethod("POST"); - urlConnection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); - urlConnection.setRequestProperty("Content-Type", "application/json"); - urlConnection.setDoInput(true); - urlConnection.setDoOutput(true); - - urlConnection.getOutputStream().write(("{\"jwt\":\""+tempToken+"\",\"publicKey\":\""+Base64.encodeBase64URLSafeString(clientKey.getEncoded())+"\"}").getBytes()); - String payload = String.join("\n", IOUtils.readLines(urlConnection.getErrorStream() == null ? urlConnection.getInputStream() : urlConnection.getErrorStream())); - - JsonObject jsonObject = (JsonObject) new JsonParser().parse(payload); - if (!"ok".equals(jsonObject.get("status").getAsString())) { - return null; - } - return jsonObject.get("data").getAsString(); - } - - public static JsonObject getJwtPayload(String jwt) { - String midPart = jwt.split("\\.")[1].replace("+", "-").replace("/", "_"); - String base64Decode = new String(Base64.decodeBase64(midPart)); // padding - return (JsonObject) new JsonParser().parse(base64Decode); - } - - public static 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); - } -} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/NullAuth.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/NullAuth.java deleted file mode 100644 index 303cfb0a..00000000 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/NullAuth.java +++ /dev/null @@ -1,62 +0,0 @@ -package kr.syeyoung.dungeonsguide.launcher.auth.authprovider; - -import com.mojang.authlib.exceptions.AuthenticationException; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.io.IOException; -import java.security.KeyPair; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; - -public class NullAuth implements AuthProvider { - - Logger logger = LogManager.getLogger("NullAuth"); - - @Override - public String getToken() { - return "TOKEN"; - } - - @Override - public KeyPair getRsaKey() { - return new KeyPair(new PublicKey() { - @Override - public String getAlgorithm() { - return null; - } - - @Override - public String getFormat() { - return null; - } - - @Override - public byte[] getEncoded() { - return new byte[0]; - } - }, new PrivateKey() { - @Override - public String getAlgorithm() { - return null; - } - - @Override - public String getFormat() { - return null; - } - - @Override - public byte[] getEncoded() { - return new byte[0]; - } - }); - } - - @Override - public AuthProvider createAuthProvider() throws NoSuchAlgorithmException, AuthenticationException, IOException { - return new NullAuth(); - } - -} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthToken.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/AuthToken.java index cb7c03da..6bbfec7b 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthToken.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/AuthToken.java @@ -1,4 +1,4 @@ -package kr.syeyoung.dungeonsguide.launcher.auth; +package kr.syeyoung.dungeonsguide.launcher.auth.token; import java.security.KeyPair; import java.security.interfaces.RSAKey; @@ -11,7 +11,9 @@ public interface AuthToken { Instant getExpiryInstant(); - KeyPair getRSAKeyForAuth(); + default String getUID() {return null;} + default String getUUID() {return null;} + default String getUsername() {return null;} String getToken(); } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/DGAuthToken.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/DGAuthToken.java new file mode 100644 index 00000000..702c23a1 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/DGAuthToken.java @@ -0,0 +1,57 @@ +package kr.syeyoung.dungeonsguide.launcher.auth.token; + +import kr.syeyoung.dungeonsguide.launcher.auth.AuthUtil; +import kr.syeyoung.dungeonsguide.launcher.auth.DgAuthUtil; +import org.json.JSONObject; + +import java.time.Instant; + +public class DGAuthToken implements AuthToken { + private String token; + private JSONObject parsed; + + public DGAuthToken(String token) { + this.token = token; + this.parsed = DgAuthUtil.getJwtPayload(token); + } + + @Override + public boolean isUserVerified() { + return true; + } + + @Override + public boolean hasFullCapability() { + return true; + } + + @Override + public boolean isAuthenticated() { + return true; + } + + @Override + public Instant getExpiryInstant() { + return Instant.ofEpochSecond(Long.parseLong(parsed.getString("exp"))); + } + + @Override + public String getUID() { + return parsed.getString("userid"); + } + + @Override + public String getUUID() { + return parsed.getString("uuid"); + } + + @Override + public String getUsername() { + return parsed.getString("nickname"); + } + + @Override + public String getToken() { + return token; + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/FailedAuthToken.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/FailedAuthToken.java new file mode 100644 index 00000000..de5fe2f7 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/FailedAuthToken.java @@ -0,0 +1,41 @@ +package kr.syeyoung.dungeonsguide.launcher.auth.token; + +import java.security.KeyPair; +import java.time.Instant; + +public class FailedAuthToken implements AuthToken { + private final Throwable exeption; + + public FailedAuthToken(Throwable exception) { + this.exeption = exception; + } + + @Override + public boolean isUserVerified() { + return false; + } + + @Override + public boolean hasFullCapability() { + return false; + } + + @Override + public boolean isAuthenticated() { + return false; + } + + @Override + public Instant getExpiryInstant() { + return Instant.MIN; + } + + @Override + public String getToken() { + return null; + } + + public Throwable getException() { + return exeption; + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/NullToken.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/NullToken.java index ddbfe58f..d2799a02 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/NullToken.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/NullToken.java @@ -1,4 +1,4 @@ -package kr.syeyoung.dungeonsguide.launcher.auth; +package kr.syeyoung.dungeonsguide.launcher.auth.token; import java.security.KeyPair; import java.time.Instant; @@ -25,11 +25,6 @@ public class NullToken implements AuthToken { } @Override - public KeyPair getRSAKeyForAuth() { - return null; - } - - @Override public String getToken() { return null; } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/PrivacyPolicyRequiredToken.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/PrivacyPolicyRequiredToken.java new file mode 100644 index 00000000..62fad840 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/PrivacyPolicyRequiredToken.java @@ -0,0 +1,56 @@ +package kr.syeyoung.dungeonsguide.launcher.auth.token; + +import kr.syeyoung.dungeonsguide.launcher.auth.DgAuthUtil; +import org.json.JSONObject; + +import java.time.Instant; + +public class PrivacyPolicyRequiredToken implements AuthToken { + private String token; + private JSONObject parsed; + + public PrivacyPolicyRequiredToken(String token) { + this.token = token; + this.parsed = DgAuthUtil.getJwtPayload(token); + } + + @Override + public boolean isUserVerified() { + return true; + } + + @Override + public boolean hasFullCapability() { + return false; + } + + @Override + public boolean isAuthenticated() { + return true; + } + + @Override + public Instant getExpiryInstant() { + return Instant.ofEpochSecond(Long.parseLong(parsed.getString("exp"))); + } + + @Override + public String getUID() { + return parsed.getString("userid"); + } + + @Override + public String getUUID() { + return parsed.getString("uuid"); + } + + @Override + public String getUsername() { + return parsed.getString("nickname"); + } + + @Override + public String getToken() { + return token; + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/events/AuthChangedEvent.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/events/AuthChangedEvent.java new file mode 100644 index 00000000..249c287f --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/events/AuthChangedEvent.java @@ -0,0 +1,12 @@ +package kr.syeyoung.dungeonsguide.launcher.events; + + +import kr.syeyoung.dungeonsguide.launcher.auth.token.AuthToken; +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.minecraftforge.fml.common.eventhandler.Event; + +@AllArgsConstructor @Getter +public class AuthChangedEvent extends Event { + private AuthToken authToken; +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthFailedExeption.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthFailedExeption.java new file mode 100644 index 00000000..881f7a1e --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthFailedExeption.java @@ -0,0 +1,7 @@ +package kr.syeyoung.dungeonsguide.launcher.exceptions; + +public class AuthFailedExeption extends RuntimeException { + public AuthFailedExeption(Throwable cause) { + super(cause); + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthServerException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthServerException.java index be610c3f..1c7a44af 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthServerException.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthServerException.java @@ -18,17 +18,21 @@ package kr.syeyoung.dungeonsguide.launcher.exceptions; +import kr.syeyoung.dungeonsguide.launcher.auth.DGResponse; +import kr.syeyoung.dungeonsguide.launcher.util.QRCodeGenerator; import org.json.JSONObject; +import java.util.Objects; + public class AuthServerException extends RuntimeException { - private JSONObject payload; + private DGResponse response; - public AuthServerException(JSONObject payload) { - super(payload.getString("errorMessage")); - this.payload = payload; + public AuthServerException(DGResponse response) { + super(response.getErrorMessage() == null ? "Invalid Server Response" : response.getErrorMessage()); + this.response = response; } public String getQRCode() { - return payload.getString("data"); + return response.getQrCode() == null ? null : response.getQrCode(); } } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/ResponseParsingException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/ResponseParsingException.java new file mode 100644 index 00000000..3933b78e --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/ResponseParsingException.java @@ -0,0 +1,33 @@ +/* + * 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.Getter; +import org.json.JSONObject; + +public class ResponseParsingException extends RuntimeException { + @Getter + private String payload; + + public ResponseParsingException(String payload, String message) { + super(message); + this.payload = 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 820ce0c8..f5149f82 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 @@ -30,6 +30,6 @@ public interface IDGLoader { boolean isLoaded(); - String branchName(); + String loaderName(); String version(); } 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 fff63a07..6baee0f3 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 @@ -123,7 +123,7 @@ public class JarLoader implements IDGLoader { } @Override - public String branchName() { + public String loaderName() { return "jar"; } 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 01159b34..ef9b3e7a 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 @@ -52,7 +52,7 @@ public class LocalLoader implements IDGLoader { } @Override - public String branchName() { + public String loaderName() { return "local"; } 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 new file mode 100644 index 00000000..f3baaa9d --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/RemoteLoader.java @@ -0,0 +1,44 @@ +package kr.syeyoung.dungeonsguide.launcher.loader; + +import kr.syeyoung.dungeonsguide.launcher.DGInterface; +import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; + +public class RemoteLoader implements IDGLoader { + private String branch; + private String version; + + @Override + public DGInterface loadDungeonsGuide() throws InstantiationException, IllegalAccessException, ClassNotFoundException { + return null; + } + + @Override + public DGInterface getInstance() { + return null; + } + + @Override + public void unloadDungeonsGuide() throws ReferenceLeakedException { + + } + + @Override + public boolean isUnloadable() { + return false; + } + + @Override + public boolean isLoaded() { + return false; + } + + @Override + public String loaderName() { + return branch; + } + + @Override + public String version() { + return version; + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGConnection.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGConnection.java index 5a310738..89b5fa8f 100755 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGConnection.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGConnection.java @@ -18,8 +18,6 @@ package kr.syeyoung.dungeonsguide.launcher.url; -import kr.syeyoung.dungeonsguide.launcher.auth.ResourceManager; - import java.io.ByteArrayInputStream; import java.io.FileNotFoundException; import java.io.IOException; diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/DungeonsGuide.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/DungeonsGuide.java index 4f50ac84..408ae9d7 100755 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/DungeonsGuide.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/DungeonsGuide.java @@ -19,7 +19,8 @@ package kr.syeyoung.dungeonsguide.mod; import com.google.common.collect.Sets; -import kr.syeyoung.dungeonsguide.Main; +import kr.syeyoung.dungeonsguide.launcher.DGInterface; +import kr.syeyoung.dungeonsguide.launcher.Main; import kr.syeyoung.dungeonsguide.mod.chat.ChatProcessor; import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter; import kr.syeyoung.dungeonsguide.mod.commands.CommandDgDebug; @@ -43,6 +44,7 @@ import lombok.Getter; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.*; import net.minecraft.client.resources.IReloadableResourceManager; +import net.minecraft.client.resources.IResourceManager; import net.minecraft.client.resources.IResourcePack; import net.minecraft.launchwrapper.LaunchClassLoader; import net.minecraftforge.client.ClientCommandHandler; @@ -59,7 +61,7 @@ import java.io.IOException; import java.util.List; import java.util.Set; -public class DungeonsGuide implements IDungeonGuide { +public class DungeonsGuide implements DGInterface { @Getter private static boolean firstTimeUsingDG = false; @@ -91,8 +93,28 @@ public class DungeonsGuide implements IDungeonGuide { - public void init() { + public void init(File f) { ProgressManager.ProgressBar progressbar = ProgressManager.push("DungeonsGuide", 4); + + progressbar.step("Creating Configuration"); + + File configFile = new File(Main.getConfigDir(), "config.json"); + if (!configFile.exists()) { + Main.getConfigDir().mkdirs(); + firstTimeUsingDG = true; + } + + Config.f = configFile; + Minecraft.getMinecraft().getFramebuffer().enableStencil(); + + try { + List<IResourcePack> resourcePackList = ReflectionHelper.getPrivateValue(Minecraft.class, Minecraft.getMinecraft(), "defaultResourcePacks", "aA", "field_110449_ao"); + resourcePackList.add(new DGTexturePack()); + Minecraft.getMinecraft().refreshResources(); + } catch (Exception e) { + e.printStackTrace(); + } + MinecraftForge.EVENT_BUS.register(this); progressbar.step("Registering Events & Commands"); @@ -133,8 +155,7 @@ public class DungeonsGuide implements IDungeonGuide { MinecraftForge.EVENT_BUS.register(command); MinecraftForge.EVENT_BUS.register(commandDungeonsGuide); - commandReparty = new CommandReparty(); - MinecraftForge.EVENT_BUS.register(commandReparty); + MinecraftForge.EVENT_BUS.register(commandReparty = new CommandReparty()); MinecraftForge.EVENT_BUS.register(new FeatureListener()); MinecraftForge.EVENT_BUS.register(new PacketListener()); @@ -148,8 +169,7 @@ public class DungeonsGuide implements IDungeonGuide { progressbar.step("Opening connection"); - cosmeticsManager = new CosmeticsManager(); - MinecraftForge.EVENT_BUS.register(cosmeticsManager); + MinecraftForge.EVENT_BUS.register(cosmeticsManager = new CosmeticsManager()); progressbar.step("Loading Config"); @@ -170,11 +190,22 @@ public class DungeonsGuide implements IDungeonGuide { MinecraftForge.EVENT_BUS.register(RichPresenceManager.INSTANCE); TimeScoreUtil.init(); - Main.finishUpProgressBar(progressbar); - ProgressManager.pop(progressbar); - ((IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager()).registerReloadListener(resourceManager -> GLCursors.setupCursors()); + } + + @Override + public void unload() { + // have FUN! + +// bar.step("Instantiating..."); +// partialLoad(obtainLoader(configuration)); + throw new UnsupportedOperationException("Who the heck registered events in features?? This will stay unsupported for now"); + } + + @Override + public void onResourceReload(IResourceManager a) { + GLCursors.setupCursors(); } private boolean showedStartUpGuide; @@ -227,26 +258,6 @@ public class DungeonsGuide implements IDungeonGuide { } - public void preinit(){ - - File configFile = new File(Main.getConfigDir(), "config.json"); - if (!configFile.exists()) { - Main.getConfigDir().mkdirs(); - firstTimeUsingDG = true; - } - - Config.f = configFile; - Minecraft.getMinecraft().getFramebuffer().enableStencil(); - - try { - List<IResourcePack> resourcePackList = ReflectionHelper.getPrivateValue(Minecraft.class, Minecraft.getMinecraft(), "defaultResourcePacks", "aA", "field_110449_ao"); - resourcePackList.add(new DGTexturePack()); - Minecraft.getMinecraft().refreshResources(); - } catch (Exception e) { - e.printStackTrace(); - } - - } public SkyblockStatus getSkyblockStatus() { return skyblockStatus; diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/IDungeonGuide.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/IDungeonGuide.java deleted file mode 100644 index d4ee724d..00000000 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/IDungeonGuide.java +++ /dev/null @@ -1,10 +0,0 @@ -package kr.syeyoung.dungeonsguide.mod; - -/** - * This exists, so we can reload the mod/ download a more recent version - */ -public interface IDungeonGuide { - void init(); - void preinit(); - -} diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/CosmeticsManager.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/CosmeticsManager.java index 3b23e0b8..4908a170 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/CosmeticsManager.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/CosmeticsManager.java @@ -22,6 +22,10 @@ package kr.syeyoung.dungeonsguide.mod.cosmetics; import kr.syeyoung.dungeonsguide.mod.cosmetics.chatreplacers.*; import kr.syeyoung.dungeonsguide.mod.events.impl.PlayerListItemPacketEvent; +import kr.syeyoung.dungeonsguide.mod.events.impl.StompConnectedEvent; +import kr.syeyoung.dungeonsguide.mod.stomp.StompHeader; +import kr.syeyoung.dungeonsguide.mod.stomp.StompManager; +import kr.syeyoung.dungeonsguide.mod.stomp.StompPayload; import lombok.Getter; import lombok.Setter; import net.minecraft.client.Minecraft; diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureDebuggableMap.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureDebuggableMap.java index 36a361e0..b4ad5708 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureDebuggableMap.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureDebuggableMap.java @@ -24,6 +24,8 @@ import kr.syeyoung.dungeonsguide.mod.SkyblockStatus; import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry; import kr.syeyoung.dungeonsguide.mod.features.GuiFeature; +import kr.syeyoung.dungeonsguide.mod.utils.MapUtils; +import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiChat; diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/resources/DGTexturePack.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/resources/DGTexturePack.java index 7b8c12d2..873ce17b 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/resources/DGTexturePack.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/resources/DGTexturePack.java @@ -18,7 +18,6 @@ package kr.syeyoung.dungeonsguide.mod.resources; -import kr.syeyoung.dungeonsguide.launcher.auth.ResourceManager; import lombok.AllArgsConstructor; import net.minecraft.client.resources.IResourcePack; import net.minecraft.client.resources.data.IMetadataSection; diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/stomp/StompManager.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/stomp/StompManager.java index 37e2792e..e7248484 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/stomp/StompManager.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/stomp/StompManager.java @@ -16,7 +16,6 @@ import java.util.concurrent.TimeUnit; public class StompManager { Logger logger = LogManager.getLogger("StompManager"); public static final String STOMP_URL = "wss://dungeons.guide/ws"; - // private String stompURL = "ws://localhost/ws"; static StompManager instance; public static StompManager getInstance() { @@ -62,12 +61,11 @@ public class StompManager { if (stompConnection != null) { stompConnection.disconnect(); } - stompConnection = new StompClient(new URI(StompManager.STOMP_URL), AuthManager.getInstance().getToken()); + stompConnection = new StompClient(new URI(StompManager.STOMP_URL), AuthManager.getInstance().getWorkingTokenOrNull()); MinecraftForge.EVENT_BUS.post(new StompConnectedEvent(stompConnection)); } catch (Exception e) { logger.error("Failed to connect to Stomp with message: {}", String.valueOf(Throwables.getRootCause(e))); } - }, 5L, TimeUnit.SECONDS); } } |