aboutsummaryrefslogtreecommitdiff
path: root/loader/src
diff options
context:
space:
mode:
authorsyeyoung <cyoung06@naver.com>2022-11-15 23:26:59 +0900
committersyeyoung <cyoung06@naver.com>2022-11-15 23:52:55 +0900
commit2893b632b4239dfb116dce853d07369a9fea222d (patch)
tree2cd5a10264927d861d7d4573b76fb9181078beaa /loader/src
parent0b4ce8c26a3126530599786d4a31c4bae44f7ec6 (diff)
downloadSkyblock-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>
Diffstat (limited to 'loader/src')
-rwxr-xr-xloader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java16
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthManager.java137
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthUtil.java57
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DGResponse.java15
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/DgAuthUtil.java160
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/InvalidDungeonsGuideCredentialsException.java8
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/ResourceManager.java164
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/AuthProvider.java16
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/DgAuth/DgAuth.java46
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/DgAuth/DgAuthUtil.java88
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/NullAuth.java62
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/AuthToken.java (renamed from loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthToken.java)6
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/DGAuthToken.java57
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/FailedAuthToken.java41
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/NullToken.java (renamed from loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/NullToken.java)7
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/token/PrivacyPolicyRequiredToken.java56
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/events/AuthChangedEvent.java12
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthFailedExeption.java7
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthServerException.java14
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/ResponseParsingException.java33
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/IDGLoader.java2
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/JarLoader.java2
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/LocalLoader.java2
-rw-r--r--loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/RemoteLoader.java44
-rwxr-xr-xloader/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGConnection.java2
25 files changed, 521 insertions, 533 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;