aboutsummaryrefslogtreecommitdiff
path: root/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth
diff options
context:
space:
mode:
authorsyeyoung <cyoung06@naver.com>2022-11-17 00:02:21 +0900
committersyeyoung <cyoung06@naver.com>2022-11-17 00:12:48 +0900
commitd07321fe03f6316f28d8421b7cd4e93dfdfd6b2e (patch)
treeae5b92754216c0a660a826ef8d208ce1b0fd2ced /loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth
parentff17b30c4b585622ca3b8e06eb77794aa21f4285 (diff)
downloadSkyblock-Dungeons-Guide-d07321fe03f6316f28d8421b7cd4e93dfdfd6b2e.tar.gz
Skyblock-Dungeons-Guide-d07321fe03f6316f28d8421b7cd4e93dfdfd6b2e.tar.bz2
Skyblock-Dungeons-Guide-d07321fe03f6316f28d8421b7cd4e93dfdfd6b2e.zip
- Better Exception handling
Signed-off-by: syeyoung <cyoung06@naver.com>
Diffstat (limited to 'loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth')
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthManager.java30
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthUtil.java6
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DGResponse.java1
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DgAuthUtil.java130
4 files changed, 90 insertions, 77 deletions
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) {