aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsyeyoung <42869671+cyoung06@users.noreply.github.com>2020-12-08 14:54:17 +0900
committersyeyoung <42869671+cyoung06@users.noreply.github.com>2020-12-08 14:54:17 +0900
commit87e89fd42ca44400a3d3d3d5477cd1525b24d91a (patch)
tree02023a2650c2a9e4fd2d47f64cb91ec614a28556
parent055520e1d8313a302f58babc6526d95bf22b471f (diff)
downloadSkyblock-Dungeons-Guide-87e89fd42ca44400a3d3d3d5477cd1525b24d91a.tar.gz
Skyblock-Dungeons-Guide-87e89fd42ca44400a3d3d3d5477cd1525b24d91a.tar.bz2
Skyblock-Dungeons-Guide-87e89fd42ca44400a3d3d3d5477cd1525b24d91a.zip
authentication stuff and network loading
-rw-r--r--build.gradle1
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/Authenticator.java133
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/DungeonsGuide.java90
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/NetworkClassLoader.java57
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/commands/CommandLoadData.java26
-rw-r--r--src/main/java/kr/syeyoung/dungeonsguide/dungeon/roomfinder/DungeonRoomInfoRegistry.java23
-rw-r--r--src/main/resources/roomdata/datas.txt11
7 files changed, 333 insertions, 8 deletions
diff --git a/build.gradle b/build.gradle
index 6ed97f83..a1260803 100644
--- a/build.gradle
+++ b/build.gradle
@@ -40,6 +40,7 @@ minecraft {
dependencies {
implementation 'org.jetbrains:annotations-java5:19.0.0'
+ implementation 'com.auth0:java-jwt:3.11.0'
// you may put jars on which you depend on in ./libs
// or you may define them like so..
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/Authenticator.java b/src/main/java/kr/syeyoung/dungeonsguide/Authenticator.java
new file mode 100644
index 00000000..15b238c6
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/Authenticator.java
@@ -0,0 +1,133 @@
+package kr.syeyoung.dungeonsguide;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.interfaces.DecodedJWT;
+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 lombok.Getter;
+import net.minecraft.client.Minecraft;
+import net.minecraft.util.Session;
+
+import javax.crypto.*;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.xml.bind.DatatypeConverter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.math.BigInteger;
+import java.net.*;
+import java.security.*;
+import java.util.UUID;
+
+public class Authenticator {
+ @Getter
+ private KeyPair keyPair;
+ @Getter
+ private String token;
+ private KeyPair generate1024RSAKey() {
+ KeyPairGenerator generator = null;
+ try {
+ generator = KeyPairGenerator.getInstance("RSA");
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+ generator.initialize(1024);
+ keyPair = generator.generateKeyPair();
+ return keyPair;
+ }
+
+ public Authenticator() {
+ generate1024RSAKey();
+ }
+
+ private static final String DOMAIN = "http://localhost:8080/";
+
+ public String authenticate() throws IOException, AuthenticationException, NoSuchAlgorithmException {
+ Session session = Minecraft.getMinecraft().getSession();
+ String token = session.getToken();
+
+ String jwt = requestAuth(session.getProfile());
+ MinecraftSessionService yggdrasilMinecraftSessionService = Minecraft.getMinecraft().getSessionService();
+ DecodedJWT jwt2 = JWT.decode(jwt);
+ String hash = calculateAuthHash(DatatypeConverter.parseBase64Binary(jwt2.getClaim("sharedSecret").asString()),
+ DatatypeConverter.parseBase64Binary(jwt2.getClaim("publicKey").asString()));
+ yggdrasilMinecraftSessionService.joinServer(session.getProfile(), token, hash);
+ token = requestAuth2(jwt, keyPair.getPublic());
+ return token;
+ }
+
+ private String requestAuth(GameProfile profile) throws IOException {
+ HttpURLConnection huc = (HttpURLConnection) new URL(DOMAIN+"auth/requestAuth").openConnection();
+ huc.setRequestProperty("User-Agent", "DungeonsGuide/1.0");
+ huc.setRequestProperty("Content-Type", "application/json");
+ huc.setRequestMethod("POST");
+ huc.setDoInput(true);
+ huc.setDoOutput(true);
+
+ huc.getOutputStream().write(("{\"uuid\":\""+profile.getId().toString()+"\",\"nickname\":\""+profile.getName()+"\"}").getBytes());
+ InputStreamReader inputStreamReader = new InputStreamReader(huc.getInputStream());
+ JsonObject object = (JsonObject) new JsonParser().parse(inputStreamReader);
+ if (!"ok".equals(object.get("status").getAsString())) {
+ return null;
+ }
+ return object.get("data").getAsString();
+ }
+ private String requestAuth2(String token, PublicKey publicKey) throws IOException {
+ HttpURLConnection huc = (HttpURLConnection) new URL(DOMAIN+"auth/authenticate").openConnection();
+ huc.setRequestMethod("POST");
+ huc.setRequestProperty("User-Agent", "DungeonsGuide/1.0");
+ huc.setRequestProperty("Content-Type", "application/json");
+ huc.setDoInput(true);
+ huc.setDoOutput(true);
+
+ huc.getOutputStream().write(("{\"jwt\":\""+token+"\",\"publicKey\":\""+DatatypeConverter.printBase64Binary(publicKey.getEncoded())+"\"}").getBytes());
+ InputStreamReader inputStreamReader = new InputStreamReader(huc.getInputStream());
+ JsonObject object = (JsonObject) new JsonParser().parse(inputStreamReader);
+ if (!"ok".equals(object.get("status").getAsString())) {
+ return null;
+ }
+ return object.get("data").getAsString();
+ }
+ public String calculateAuthHash(byte[] sharedSecret, byte[] pk) throws NoSuchAlgorithmException {
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ md.update("".getBytes());
+ md.update(sharedSecret);
+ md.update(pk);
+ byte[] result = md.digest();
+ return new BigInteger(result).toString(16);
+ }
+ public InputStream getInputStream(String resource) throws IOException, BadPaddingException, IllegalBlockSizeException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException {
+ HttpURLConnection huc = (HttpURLConnection) new URL(DOMAIN+"resource/resource?class="+ URLEncoder.encode(resource)).openConnection();
+ huc.setRequestProperty("User-Agent", "DungeonsGuide/1.0");
+ huc.setRequestProperty("Content-Type", "application/json");
+ huc.setRequestProperty("Authorization", token);
+ huc.setDoInput(true);
+ huc.setDoOutput(true);
+
+ InputStream inputStream = huc.getInputStream();
+ byte[] bytes = new byte[4];
+ inputStream.read(bytes);
+ int len = ((bytes[0] & 0xFF) << 24) |
+ ((bytes[1] & 0xFF) << 16) |
+ ((bytes[2] & 0xFF) << 8 ) |
+ ((bytes[3] & 0xFF));
+
+ byte[] pubKey = new byte[len];
+ inputStream.read(pubKey);
+
+ Cipher cipher = Cipher.getInstance("RSA");
+ byte[] byteEncrypted = pubKey;
+ cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate());
+ byte[] bytePlain = cipher.doFinal(byteEncrypted);
+
+ cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
+ SecretKeySpec keySpec = new SecretKeySpec(bytePlain, "AES");
+ IvParameterSpec ivSpec = new IvParameterSpec(bytePlain);
+ cipher.init(Cipher.DECRYPT_MODE,keySpec,ivSpec);
+ return new CipherInputStream(inputStream, cipher);
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/DungeonsGuide.java b/src/main/java/kr/syeyoung/dungeonsguide/DungeonsGuide.java
index bcbcbe0a..de1b0067 100644
--- a/src/main/java/kr/syeyoung/dungeonsguide/DungeonsGuide.java
+++ b/src/main/java/kr/syeyoung/dungeonsguide/DungeonsGuide.java
@@ -1,21 +1,32 @@
package kr.syeyoung.dungeonsguide;
+import com.mojang.authlib.exceptions.AuthenticationException;
import kr.syeyoung.dungeonsguide.commands.*;
import kr.syeyoung.dungeonsguide.dungeon.roomfinder.DungeonRoomInfoRegistry;
import lombok.Getter;
import net.minecraft.client.Minecraft;
-import net.minecraft.command.CommandDebug;
-import net.minecraft.init.Blocks;
+import net.minecraft.client.gui.FontRenderer;
+import net.minecraft.client.gui.GuiErrorScreen;
+import net.minecraft.client.gui.GuiScreen;
import net.minecraft.util.IChatComponent;
import net.minecraftforge.client.ClientCommandHandler;
+import net.minecraftforge.client.event.GuiOpenEvent;
import net.minecraftforge.common.MinecraftForge;
+import net.minecraftforge.fml.client.CustomModLoadingErrorDisplayException;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
+import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import org.apache.commons.io.IOUtils;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
import java.io.*;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
@Mod(modid = DungeonsGuide.MODID, version = DungeonsGuide.VERSION)
public class DungeonsGuide
@@ -72,7 +83,23 @@ public class DungeonsGuide
}
}
}
- DungeonRoomInfoRegistry.loadAll(configDir);
+ try {
+ DungeonRoomInfoRegistry.loadAll();
+ } catch (BadPaddingException e) {
+ e.printStackTrace();
+ } catch (InvalidAlgorithmParameterException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (IllegalBlockSizeException e) {
+ e.printStackTrace();
+ } catch (NoSuchPaddingException e) {
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ e.printStackTrace();
+ }
Keybinds.register();
}
@@ -88,9 +115,66 @@ public class DungeonsGuide
@Getter
private File configDir;
+ @Getter
+ private Authenticator authenticator;
+ private NetworkClassLoader classLoader;
@EventHandler
public void pre(FMLPreInitializationEvent event) {
configDir = new File(event.getModConfigurationDirectory(),"dungeonsguide");
+
+ authenticator = new Authenticator();
+ String token = null;
+ try {
+ token = authenticator.authenticate();
+ System.out.println(token);
+ if (token != null) {
+ classLoader = new NetworkClassLoader(authenticator);
+ Thread.currentThread().setContextClassLoader(classLoader);
+ return;
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (AuthenticationException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+
+ final GuiScreen errorGui = new GuiErrorScreen(null, null) {
+
+ @Override
+ public void handleMouseInput() {
+ }
+
+ @Override
+ public void handleKeyboardInput() {
+ }
+
+ @Override
+ public void drawScreen(int par1, int par2, float par3) {
+ drawDefaultBackground();
+ String[] s_msg = new String[] {
+ "Can't validate current installation of Dungeons Guide",
+ "Please contact mod author if you purchased this mod and getting this error",
+ "And if you haven't purchased the mod, please consider doing so"
+ };
+ for (int i = 0; i < s_msg.length; ++i) {
+ drawCenteredString(fontRendererObj, s_msg[i], width / 2, height / 3 + 12 * i, 0xFFFFFFFF);
+ }
+ }
+ };
+ @SuppressWarnings("serial") CustomModLoadingErrorDisplayException e = new CustomModLoadingErrorDisplayException() {
+
+ @Override
+ public void initGui(GuiErrorScreen errorScreen, FontRenderer fontRenderer) {
+ Minecraft.getMinecraft().displayGuiScreen(errorGui);
+ }
+
+ @Override
+ public void drawScreen(GuiErrorScreen errorScreen, FontRenderer fontRenderer, int mouseRelX, int mouseRelY, float tickTime) {
+ }
+ };
+ throw e;
}
public SkyblockStatus getSkyblockStatus() {
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/NetworkClassLoader.java b/src/main/java/kr/syeyoung/dungeonsguide/NetworkClassLoader.java
new file mode 100644
index 00000000..564eeb11
--- /dev/null
+++ b/src/main/java/kr/syeyoung/dungeonsguide/NetworkClassLoader.java
@@ -0,0 +1,57 @@
+package kr.syeyoung.dungeonsguide;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+public class NetworkClassLoader extends ClassLoader {
+ Authenticator authenticator;
+
+ public NetworkClassLoader(Authenticator authenticator) {
+ super();
+ this.authenticator = authenticator;
+ }
+
+ @Override
+ public Class findClass(String name) throws ClassNotFoundException {
+ byte[] b = new byte[0];
+ try {
+ b = loadClassFromFile(name);
+ return defineClass(name, b, 0, b.length);
+ } catch (BadPaddingException e) {
+ e.printStackTrace();
+ } catch (InvalidAlgorithmParameterException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (IllegalBlockSizeException e) {
+ e.printStackTrace();
+ } catch (NoSuchPaddingException e) {
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ e.printStackTrace();
+ }
+ throw new ClassNotFoundException();
+ }
+
+ private byte[] loadClassFromFile(String fileName) throws BadPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException, IllegalBlockSizeException, NoSuchPaddingException, InvalidKeyException {
+ byte[] buffer;
+ InputStream inputStream = authenticator.getInputStream(fileName.replace('.', '/')+ ".class");
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ int nextValue = 0;
+ while ( (nextValue = inputStream.read()) != -1 ) {
+ byteStream.write(nextValue);
+ }
+ buffer = byteStream.toByteArray();
+ return buffer;
+ }
+}
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandLoadData.java b/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandLoadData.java
index c1d3512e..637ec398 100644
--- a/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandLoadData.java
+++ b/src/main/java/kr/syeyoung/dungeonsguide/commands/CommandLoadData.java
@@ -5,6 +5,14 @@ import kr.syeyoung.dungeonsguide.dungeon.roomfinder.DungeonRoomInfoRegistry;
import net.minecraft.command.CommandBase;
import net.minecraft.command.ICommandSender;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
public class CommandLoadData extends CommandBase {
@Override
public String getCommandName() {
@@ -18,7 +26,23 @@ public class CommandLoadData extends CommandBase {
@Override
public void processCommand(ICommandSender sender, String[] args) {
- DungeonRoomInfoRegistry.loadAll(DungeonsGuide.getDungeonsGuide().getConfigDir());
+ try {
+ DungeonRoomInfoRegistry.loadAll();
+ } catch (BadPaddingException e) {
+ e.printStackTrace();
+ } catch (InvalidAlgorithmParameterException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (IllegalBlockSizeException e) {
+ e.printStackTrace();
+ } catch (NoSuchPaddingException e) {
+ e.printStackTrace();
+ } catch (InvalidKeyException e) {
+ e.printStackTrace();
+ }
}
@Override
public int getRequiredPermissionLevel() {
diff --git a/src/main/java/kr/syeyoung/dungeonsguide/dungeon/roomfinder/DungeonRoomInfoRegistry.java b/src/main/java/kr/syeyoung/dungeonsguide/dungeon/roomfinder/DungeonRoomInfoRegistry.java
index d9df6a8d..383aea08 100644
--- a/src/main/java/kr/syeyoung/dungeonsguide/dungeon/roomfinder/DungeonRoomInfoRegistry.java
+++ b/src/main/java/kr/syeyoung/dungeonsguide/dungeon/roomfinder/DungeonRoomInfoRegistry.java
@@ -1,8 +1,17 @@
package kr.syeyoung.dungeonsguide.dungeon.roomfinder;
+import jdk.internal.util.xml.impl.Input;
+import kr.syeyoung.dungeonsguide.Authenticator;
+import kr.syeyoung.dungeonsguide.DungeonsGuide;
import kr.syeyoung.dungeonsguide.dungeon.data.DungeonRoomInfo;
+import javax.crypto.BadPaddingException;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
import java.io.*;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
import java.util.*;
public class DungeonRoomInfoRegistry {
@@ -41,6 +50,7 @@ public class DungeonRoomInfoRegistry {
}
public static void saveAll(File dir) {
+ if (!DungeonsGuide.DEBUG) return;
dir.mkdirs();
for (DungeonRoomInfo dungeonRoomInfo : registered) {
try {
@@ -53,14 +63,19 @@ public class DungeonRoomInfoRegistry {
}
}
- public static void loadAll(File dir) {
+ public static void loadAll() throws BadPaddingException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException, IllegalBlockSizeException, NoSuchPaddingException, InvalidKeyException {
registered.clear();
shapeMap.clear();
uuidMap.clear();
- for (File f: dir.listFiles()) {
- if (!f.isFile() || !f.getName().endsWith(".roomdata")) continue;
+ Authenticator authenticator = DungeonsGuide.getDungeonsGuide().getAuthenticator();
+ InputStream inputStream = authenticator.getInputStream("roomdata/datas.txt");
+ BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
+ String name;
+ while ((name = br.readLine()) != null) {
+ System.out.println("Trying to load "+name);
+ if (name.endsWith(".roomdata")) continue;
try {
- FileInputStream fis = new FileInputStream(f);
+ InputStream fis = authenticator.getInputStream(name);
ObjectInputStream ois = new ObjectInputStream(fis);
DungeonRoomInfo dri = (DungeonRoomInfo) ois.readObject();
ois.close();
diff --git a/src/main/resources/roomdata/datas.txt b/src/main/resources/roomdata/datas.txt
new file mode 100644
index 00000000..6880da63
--- /dev/null
+++ b/src/main/resources/roomdata/datas.txt
@@ -0,0 +1,11 @@
+roomdata/990f6e4c-f7cf-4d27-ae91-11219b85861f.roomdata
+roomdata/5000be9d-3081-4a5e-8563-dd826705663a.roomdata
+roomdata/9139cb1c-b6f3-4bac-92de-909b1eb73449.roomdata
+roomdata/11982f7f-703e-4d98-9d27-4e07ba3fef71.roomdata
+roomdata/a053f4fa-d6b2-4aef-ae3e-97c7eee0252e.roomdata
+roomdata/c2ea0a41-d495-437f-86cc-235a71c49f22.roomdata
+roomdata/cf6d49d3-4f1e-4ec9-836e-049573793ddd.roomdata
+roomdata/cf44c95c-950e-49e0-aa4c-82c2b18d0acc.roomdata
+roomdata/d3e61abf-4198-4520-a950-a03761a0eb6f.roomdata
+roomdata/ffd5411b-6ff4-4f60-b387-72f00510ec50.roomdata
+roomdata/b2dce4ed-2bda-4303-a4d7-3ebb914db318.roomdata \ No newline at end of file