diff options
Diffstat (limited to 'loader/src/main/java')
21 files changed, 728 insertions, 722 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 7cc0f806..921adca9 100755 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java @@ -61,7 +61,7 @@ public class Main private static Main main; - private File configDir; + private static File configDir; private DGInterface dgInterface; private Authenticator authenticator = new Authenticator(); @@ -69,6 +69,10 @@ public class Main private List<DungeonsGuideReloadListener> listeners = new ArrayList<>(); + public static File getConfigDir() { + return configDir; + } + public void addDGReloadListener(DungeonsGuideReloadListener dungeonsGuideReloadListener) { listeners.add(Objects.requireNonNull(dungeonsGuideReloadListener)); } @@ -111,7 +115,7 @@ public class Main listener.unloadReference(); } if (currentLoader != null) { - currentLoader.unloadJar(); + currentLoader.unloadDungeonsGuide(); } currentLoader = null; } @@ -126,8 +130,7 @@ public class Main } private void partialLoad(IDGLoader newLoader) throws ClassNotFoundException, InstantiationException, IllegalAccessException { if (dgInterface != null) throw new IllegalStateException("DG is loaded"); - newLoader.loadJar(authenticator); - dgInterface = newLoader.getInstance(); + dgInterface = newLoader.loadDungeonsGuide(); currentLoader = newLoader; } 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 new file mode 100644 index 00000000..23d9cf06 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthManager.java @@ -0,0 +1,140 @@ +package kr.syeyoung.dungeonsguide.launcher.auth; + +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 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 java.io.IOException; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.util.Objects; +import java.util.concurrent.*; + + +public class AuthManager { + Logger logger = LogManager.getLogger("AuthManger"); + + private static AuthManager INSTANCE; + + public static AuthManager getInstance() { + if(INSTANCE == null) INSTANCE = new AuthManager(); + return INSTANCE; + } + + @Setter + private String baseserverurl = "https://dungeons.guide"; + + private AuthToken currentToken = new NullToken(); + + public String getToken() { + return currentToken.getToken(); + } + + + public KeyPair getKeyPair(){ + return currentToken.getRSAKeyForAuth(); + } + + + private volatile boolean initlock = false; + + public void init() { + if (initlock) { + logger.info("Cannot init AuthManger twice"); + 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; + } + } + + + }, 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"); + } + + public String getPlanType(){ + if(getToken() == null) return null; + + + JsonObject jwt = DgAuthUtil.getJwtPayload(getToken()); + + if(!jwt.has("plan")) return null; + + return jwt.get("plan").getAsString(); + + } + + 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))); + } + + } + + +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthToken.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthToken.java new file mode 100644 index 00000000..cb7c03da --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthToken.java @@ -0,0 +1,17 @@ +package kr.syeyoung.dungeonsguide.launcher.auth; + +import java.security.KeyPair; +import java.security.interfaces.RSAKey; +import java.time.Instant; + +public interface AuthToken { + boolean isUserVerified(); + boolean hasFullCapability(); + boolean isAuthenticated(); + + Instant getExpiryInstant(); + + KeyPair getRSAKeyForAuth(); + + String getToken(); +} 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 new file mode 100644 index 00000000..9ce02643 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthUtil.java @@ -0,0 +1,70 @@ +package kr.syeyoung.dungeonsguide.launcher.auth; + +import com.google.gson.JsonElement; +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; +import java.net.URL; +import java.security.*; + +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)); + } +} 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 new file mode 100644 index 00000000..ebe78196 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/InvalidDungeonsGuideCredentialsException.java @@ -0,0 +1,8 @@ +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/NullToken.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/NullToken.java new file mode 100644 index 00000000..ddbfe58f --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/NullToken.java @@ -0,0 +1,36 @@ +package kr.syeyoung.dungeonsguide.launcher.auth; + +import java.security.KeyPair; +import java.time.Instant; + +public class NullToken implements AuthToken { + @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 KeyPair getRSAKeyForAuth() { + return null; + } + + @Override + public String getToken() { + return null; + } +} 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 new file mode 100644 index 00000000..721b629f --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/ResourceManager.java @@ -0,0 +1,164 @@ +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 new file mode 100644 index 00000000..d469c729 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/AuthProvider.java @@ -0,0 +1,16 @@ +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 new file mode 100644 index 00000000..dca9ce33 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/DgAuth/DgAuth.java @@ -0,0 +1,46 @@ +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 new file mode 100644 index 00000000..53b57e1a --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/DgAuth/DgAuthUtil.java @@ -0,0 +1,88 @@ +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 new file mode 100644 index 00000000..303cfb0a --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/authprovider/NullAuth.java @@ -0,0 +1,62 @@ +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/authentication/Authenticator.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/Authenticator.java deleted file mode 100755 index ac30c5e3..00000000 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/Authenticator.java +++ /dev/null @@ -1,257 +0,0 @@ -/* - * 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.authentication; - -import com.mojang.authlib.exceptions.AuthenticationException; -import com.mojang.authlib.minecraft.MinecraftSessionService; -import kr.syeyoung.dungeonsguide.launcher.Main; -import kr.syeyoung.dungeonsguide.launcher.exceptions.AuthServerException; -import kr.syeyoung.dungeonsguide.launcher.exceptions.PrivacyPolicyRequiredException; -import kr.syeyoung.dungeonsguide.launcher.exceptions.TokenExpiredException; -import lombok.Getter; -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 sun.reflect.Reflection; - -import javax.crypto.*; -import java.io.*; -import java.math.BigInteger; -import java.net.*; -import java.security.*; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; -import java.time.Instant; -import java.util.UUID; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -public class Authenticator { - private String dgAccessToken; - @Getter - private TokenStatus tokenStatus = TokenStatus.UNAUTHENTICATED; - - private final SecureRandom secureRandom = new SecureRandom(); - - private Lock authenticationLock = new ReentrantLock(); - - static { - Reflection.registerFieldsToFilter(Authenticator.class, "dgAccessToken"); // Please do not touch this field. I know there is a way to block it completely, but I won't do it here. - } - - public String getRawToken() { - return dgAccessToken; - } - public String getUnexpiredToken() { // THIS METHOD MAY BLOCK. - if (tokenStatus != TokenStatus.AUTHENTICATED) throw new IllegalStateException("Token is not available"); - long expiry = getJwtPayload(dgAccessToken).getLong("exp"); - if (System.currentTimeMillis() >= expiry-2000 || tokenStatus == TokenStatus.EXPIRED) { - tokenStatus = TokenStatus.EXPIRED; - try { - repeatAuthenticate(5); - } catch (Throwable t) { - Main.getMain().setLastFatalError(t); - throw new TokenExpiredException(t); - } - } - return dgAccessToken; - } - - - private byte[] generateSharedSecret() { - byte[] bts = new byte[32]; - secureRandom.nextBytes(bts); - return bts; - } - - public String repeatAuthenticate(int tries) { - int cnt = 0; - while(true) { - try { - reauthenticate(); - break; - } catch (IOException | AuthenticationException | NoSuchAlgorithmException e) { - e.printStackTrace(); - if (cnt == tries) throw new RuntimeException(e); - try { - Thread.sleep((long) Math.max(Math.pow(2, tries)* 100, 1000 * 10)); - } catch (InterruptedException ex) {} - } - cnt++; - } - return dgAccessToken; - } - public String reauthenticate() throws IOException, AuthenticationException, NoSuchAlgorithmException { - try { - authenticationLock.lock(); - - tokenStatus = TokenStatus.UNAUTHENTICATED; - dgAccessToken = null; - - MinecraftSessionService yggdrasilMinecraftSessionService = Minecraft.getMinecraft().getSessionService(); - - Session SECURE_USER_SESSION = Minecraft.getMinecraft().getSession(); - dgAccessToken = requestAuth(SECURE_USER_SESSION.getProfile().getId(), SECURE_USER_SESSION.getProfile().getName()); // id: uuid, name: username - - JSONObject d = getJwtPayload(dgAccessToken); - byte[] sharedSecret = generateSharedSecret(); // Notice.... shared secret is generated on the client side unlike dg 3.0. Yep, I was a stupid when making 3.0. - - String hash = calculateServerHash(sharedSecret, Base64.decodeBase64(d.getString("publicKey"))); // Public Key here is server's public key. - - byte[] encodedSharedSecret; - try { - Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.ENCRYPT_MODE, KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(Base64.decodeBase64(d.getString("publicKey"))))); - encodedSharedSecret = cipher.doFinal(sharedSecret); - } catch (NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | - InvalidKeySpecException | - InvalidKeyException e) { - throw new RuntimeException(e); - } // Server connection is SSL but I still encrypt it using publicKey. Additional layer of security considering the request goes through cloudflare. (it's not like I don't trust cloudflare, but idk) - - yggdrasilMinecraftSessionService.joinServer(SECURE_USER_SESSION.getProfile(), SECURE_USER_SESSION.getToken(), hash); // Sent to "MOJANG" Server. - - JSONObject furtherStuff = verifyAuth(dgAccessToken, encodedSharedSecret); - - dgAccessToken = furtherStuff.getString("jwt"); - if ("TOS_PRIVACY_POLICY_ACCEPT_REQUIRED".equals(furtherStuff.getString("result"))) { - tokenStatus = TokenStatus.PP_REQUIRED; - throw new PrivacyPolicyRequiredException(); - } - tokenStatus = TokenStatus.AUTHENTICATED; - return this.dgAccessToken; - } finally { - authenticationLock.unlock(); - } - } - - public String acceptLatestTOS() throws IOException { - try { - authenticationLock.lock(); - if (tokenStatus != TokenStatus.PP_REQUIRED) throw new IllegalStateException("Already accepted TOS"); - JSONObject furtherStuff = acceptPrivacyPolicy(dgAccessToken); - dgAccessToken = furtherStuff.getString("jwt"); - if ("TOS_PRIVACY_POLICY_ACCEPT_REQUIRED".equals(furtherStuff.getString("result"))) { - tokenStatus = TokenStatus.PP_REQUIRED; - throw new PrivacyPolicyRequiredException(); - } - tokenStatus = TokenStatus.AUTHENTICATED; - return this.dgAccessToken; - } finally { - authenticationLock.unlock(); - } - } - - public JSONObject getJwtPayload(String jwt) { - String midPart = jwt.split("\\.")[1].replace("+", "-").replace("/", "_"); - String base64Decode = new String(Base64.decodeBase64(midPart)); // padding - return new JSONObject(base64Decode); - } - - private String requestAuth(UUID uuid, String nickname) throws IOException { - HttpURLConnection urlConnection = request("POST", "/auth/v2/requestAuth"); - urlConnection.setRequestProperty("Content-Type", "application/json"); - - urlConnection.getOutputStream().write(("{\"uuid\":\""+uuid.toString()+"\",\"nickname\":\""+nickname+"\"}").getBytes()); - try (InputStream is = obtainInputStream(urlConnection)) { - String payload = String.join("\n", IOUtils.readLines(is)); - if (urlConnection.getResponseCode() != 200) - System.out.println("/auth/requestAuth :: Received " + urlConnection.getResponseCode() + " along with\n" + payload); - - JSONObject json = new JSONObject(payload); - - if ("Success".equals(json.getString("status"))) { - return json.getString("data"); - } else { - throw new AuthServerException(json); - } - } - } - private JSONObject verifyAuth(String tempToken, byte[] encryptedSecret) throws IOException { - HttpURLConnection urlConnection = request("POST", "/auth/v2/authenticate"); - urlConnection.setRequestProperty("Content-Type", "application/json"); - - urlConnection.getOutputStream().write(("{\"jwt\":\""+tempToken+"\",\"sharedSecret\":\""+Base64.encodeBase64String(encryptedSecret)+"\"}").getBytes()); - try (InputStream is = obtainInputStream(urlConnection)) { - String payload = String.join("\n", IOUtils.readLines(is)); - if (urlConnection.getResponseCode() != 200) - System.out.println("/auth/authenticate :: Received " + urlConnection.getResponseCode() + " along with\n" + payload); - - JSONObject json = new JSONObject(payload); - - if ("Success".equals(json.getString("status"))) { - return json.getJSONObject("data"); - } else { - throw new AuthServerException(json); - } - } - } - private JSONObject acceptPrivacyPolicy(String tempToken) throws IOException { - HttpURLConnection urlConnection = request("POST", "/auth/v2/acceptPrivacyPolicy"); - - urlConnection.getOutputStream().write(tempToken.getBytes()); - try (InputStream is = obtainInputStream(urlConnection)) { - String payload = String.join("\n", IOUtils.readLines(is)); - if (urlConnection.getResponseCode() != 200) - System.out.println("/auth/authenticate :: Received " + urlConnection.getResponseCode() + " along with\n" + payload); - - JSONObject json = new JSONObject(payload); - - if ("Success".equals(json.getString("status"))) { - return json.getJSONObject("data"); - } else { - throw new AuthServerException(json); - } - } - } - - - private 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); - } - - public InputStream obtainInputStream(HttpURLConnection huc) { - InputStream inputStream = null; - try { - inputStream = huc.getInputStream(); - } catch (Exception e) { - inputStream = huc.getErrorStream(); - } - return inputStream; - } - - public HttpURLConnection request(String method, String url) throws IOException { - HttpURLConnection urlConnection = (HttpURLConnection) new URL(Main.DOMAIN+url).openConnection(); - urlConnection.setRequestMethod(method); // TODO: setup SSL certificate here, because.... SOME PEOPLE HAVE THAT ISSUE, I HAVE NO IDEA WHY THEY DONT HAVE CLOUDFLARE CERTS INSTALLED ON THEM - urlConnection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); - urlConnection.setDoInput(true); - urlConnection.setDoOutput(true); - urlConnection.setAllowUserInteraction(true); - if (tokenStatus == TokenStatus.AUTHENTICATED) - urlConnection.setRequestProperty("Authorization", "Bearer "+getUnexpiredToken()); - return urlConnection; - } -} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/TokenStatus.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/TokenStatus.java deleted file mode 100644 index a83818b8..00000000 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/authentication/TokenStatus.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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.authentication; - -public enum TokenStatus { - UNAUTHENTICATED, - BANNED, - PP_REQUIRED, - AUTHENTICATED, - EXPIRED -} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/ModDownloader.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/ModDownloader.java deleted file mode 100644 index 45eacee5..00000000 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/branch/ModDownloader.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * 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.branch; - -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import kr.syeyoung.dungeonsguide.launcher.authentication.Authenticator; -import lombok.Getter; -import net.minecraftforge.fml.common.ProgressManager; -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.io.IOUtils; -import org.json.JSONArray; -import org.json.JSONObject; - -import javax.crypto.*; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import javax.net.ssl.HttpsURLConnection; -import java.io.*; -import java.net.HttpURLConnection; -import java.net.URL; -import java.security.*; -import java.security.cert.CertificateException; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.UUID; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -public class ModDownloader { - private Authenticator authenticator; - - @Getter - private List<UpdateBranch> accessibleBranches = null; - - public ModDownloader(Authenticator authenticator) { - this.authenticator = authenticator; - } - - public List<UpdateBranch> fetchAccessibleBranches() throws IOException { - HttpURLConnection urlConnection = authenticator.request("GET", "/updates/"); - try (InputStream is = authenticator.obtainInputStream(urlConnection)) { - String payload = String.join("\n", IOUtils.readLines(is)); - - JSONArray jsonArray = new JSONArray(payload); - List<UpdateBranch> branches = new ArrayList<>(); - for (Object o : jsonArray) { - if (o instanceof JSONObject) { - JSONObject branch = (JSONObject) o; - UpdateBranch updateBranch = new UpdateBranch(); - updateBranch.setId(branch.getLong("id")); - updateBranch.setName(branch.getString("name")); - updateBranch.setMetadata(branch.getJSONObject("metadata").getJSONObject("metadataSchema")); - branches.add(updateBranch); - } - } - return this.accessibleBranches = branches; - } - } - - public List<Update> fetchUpdates(Long branch, int page) throws IOException { - HttpURLConnection urlConnection = authenticator.request("GET", "/updates/"+branch+"/"); - try (InputStream is = authenticator.obtainInputStream(urlConnection)) { - String payload = String.join("\n", IOUtils.readLines(is)); - - JSONArray jsonArray = new JSONArray(payload); - List<Update> updates = new ArrayList<>(); - for (Object o : jsonArray) { - if (o instanceof JSONObject) { - JSONObject json = (JSONObject) o; - Update update = new Update(); - update.setId(json.getLong("id")); - update.setBranchId(json.getLong("branchId")); - update.setName(json.getString("versionName")); - update.setUpdateLog(json.getString("updateLog")); - update.setMetadata(json.getJSONObject("metadata")); - for (Object assets : json.getJSONObject("assets").getJSONArray("assets")) { - if (assets instanceof JSONObject) { - JSONObject a_json = (JSONObject) assets; - Update.Asset asset = new Update.Asset(); - asset.setName(a_json.getString("name")); - asset.setSize(a_json.getLong("size")); - asset.setObjectId(a_json.getString("objectId")); - asset.setAssetId(UUID.fromString(a_json.getString("assetID"))); - update.getAssets().add(asset); - } - } - updates.add(update); - } - } - return updates; - } - } - - /* - pls Close after done - */ - public InputStream fetchAsset(Update update, UUID assetId) throws IOException { - HttpURLConnection urlConnection = authenticator.request("GET", "/updates/"+update.getBranchId()+"/"+update.getId()+"/"+assetId.toString()); - try (InputStream is = authenticator.obtainInputStream(urlConnection)) { - String payload = String.join("\n", IOUtils.readLines(is)); - JSONObject object = new JSONObject(payload); - - HttpURLConnection connection = (HttpURLConnection) new URL(object.getString("url")).openConnection(); - connection.setRequestMethod(object.getString("method")); - urlConnection.setRequestProperty("User-Agent", "DungeonsGuide/1.0"); - urlConnection.setDoInput(true); - urlConnection.setDoOutput(true); - urlConnection.setAllowUserInteraction(true); - return authenticator.obtainInputStream(connection); - } - } - - - - - - - private ProgressManager.ProgressBar progressBar; - - private PublicKey dgPublicKey; - private PublicKey getDGPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException { - if (dgPublicKey != null) return dgPublicKey; - X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decodeBase64("MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxO89qtwG67jNucQ9Y44c" + - "IUs/B+5BeJPs7G+RG2gfs4/2+tzF/c1FLDc33M7yKw8aKk99vsBUY9Oo8gxxiEPB" + - "JitP/qfon2THp94oM77ZTpHlmFoqbZMcKGZVI8yfvEL4laTM8Hw+qh5poQwtpEbK" + - "Xo47AkxygxJasUnykER2+aSTZ6kWU2D4xiNtFA6lzqN+/oA+NaYfPS0amAvyVlHR" + - "n/8IuGkxb5RrlqVssQstFnxsJuv88qdGSEqlcKq2tLeg9hb8eCnl2OFzvXmgbVER" + - "0JaV+4Z02fVG1IlR3Xo1mSit7yIU6++3usRCjx2yfXpnGGJUW5pe6YETjNew3ax+" + - "FAZ4GePWCdmS7FvBnbbABKo5pE06ZTfDUTCjQlAJQiUgoF6ntMJvQAXPu48Vr8q/" + - "mTcuZWVnI6CDgyE7nNq3WNoq3397sBzxRohMxuqzl3T19zkfPKF05iV2Ju1HQMW5" + - "I119bYrmVD240aGESZc20Sx/9g1BFpNzQbM5PGUlWJ0dhLjl2ge4ip2hHciY3OEY" + - "p2Qy2k+xEdenpKdL+WMRimCQoO9gWe2Tp4NmP5dppDXZgPjXqjZpnGs0Uxs+fXqW" + - "cwlg3MbX3rFl9so/fhVf4p9oXZK3ve7z5D6XSSDRYECvsKIa08WAxJ/U6n204E/4" + - "xUF+3ZgFPdzZGn2PU7SsnOsCAwEAAQ==")); - return dgPublicKey = KeyFactory.getInstance("RSA").generatePublic(spec); - } - - - - - private KeyPair rsaKey; - private KeyPair getKeyPair() { - KeyPairGenerator a = null; - try { - a = KeyPairGenerator.getInstance("RSA"); - } catch (NoSuchAlgorithmException b) { } - a.initialize(1024); - this.rsaKey = a.generateKeyPair(); - return this.rsaKey; - } - - - private final HashMap<String, byte[]> loadedResources = new HashMap<String, byte[]>(); - - public HashMap<String, byte[]> getResources() { - return loadedResources; - } - - private void downloadSafe(String dgToken, String url, boolean isValidateSignature) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, CertificateException, KeyStoreException, KeyManagementException, 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", dgToken); - 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, this.rsaKey.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 = null; - if (isValidateSignature) { - progressBar.step("Validating Signature"); - 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(getDGPublicKey()); - 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 = 0; - while((p = zipInputStream.read(buffer)) > 0) { - byteArrayOutputStream.write(buffer, 0, p); - } - this.loadedResources.put(zipEntry.getName(), byteArrayOutputStream.toByteArray()); - } - dgConnection.disconnect(); - } - - public JsonElement getJsonSecured(String u) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException, CertificateException, KeyStoreException, KeyManagementException { - 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", authenticator.getUnexpiredToken()); - httpsURLConnection.setDoInput(true); - httpsURLConnection.setDoOutput(true); - - InputStream inputStream = httpsURLConnection.getInputStream(); - byte[] lengthPayload = new byte[4]; - inputStream.read(lengthPayload); - int 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, this.rsaKey.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 cipherInputStream = new CipherInputStream(inputStream, cipher); - cipherInputStream.read(lengthPayload); - length = ((lengthPayload[0] & 0xFF) << 24) | - ((lengthPayload[1] & 0xFF) << 16) | - ((lengthPayload[2] & 0xFF) << 8) | - ((lengthPayload[3] & 0xFF)); - JsonElement l = new JsonParser().parse(new InputStreamReader(cipherInputStream)); - httpsURLConnection.disconnect(); - return l; - } -} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/GuiLoadingError.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/GuiLoadingError.java index f7cc5972..f699b1d7 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/GuiLoadingError.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/GuiLoadingError.java @@ -18,64 +18,34 @@ package kr.syeyoung.dungeonsguide.launcher.gui; -import kr.syeyoung.dungeonsguide.launcher.util.QRCodeGenerator; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.*; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.client.renderer.texture.DynamicTexture; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.common.FMLCommonHandler; import org.lwjgl.opengl.GL11; -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.Base64; -import java.util.zip.GZIPOutputStream; +import java.io.PrintStream; public class GuiLoadingError extends GuiScreen { - private String stacktrace; - private Throwable throwable; + static Throwable cause; + private final String stacktrace; + private final GuiScreen originalGUI; + public GuiLoadingError(GuiScreen originalGUI) { - private DynamicTexture texture; - private ResourceLocation location; - private BufferedImage qrCode; - private Runnable clear; + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + PrintStream printStream = new PrintStream(byteArrayOutputStream); + cause.printStackTrace(printStream); + this.stacktrace = byteArrayOutputStream.toString(); - public GuiLoadingError(Throwable t, Runnable clear) { - this.throwable = t; - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - t.printStackTrace(pw); - stacktrace = sw.toString(); - - - try { - qrCode = QRCodeGenerator.generateQRCode(stacktrace.getBytes()); - } catch (IOException e) { - throw new RuntimeException(e); - } - texture = new DynamicTexture(qrCode.getWidth(), qrCode.getHeight()); - location = Minecraft.getMinecraft().getTextureManager().getDynamicTextureLocation("dg/errorqr", texture); - - qrCode.getRGB(0,0,qrCode.getWidth(), qrCode.getHeight(), texture.getTextureData(), 0, qrCode.getWidth()); - - texture.updateDynamicTexture(); - this.clear = clear; + this.originalGUI = originalGUI; } @Override public void initGui() { ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft()); - this.buttonList.add(new GuiButton(0, sr.getScaledWidth()/2-100,sr.getScaledHeight()-40 ,"Close Minecraft")); - this.buttonList.add(new GuiButton(1, sr.getScaledWidth()/2-100,sr.getScaledHeight()-70 ,"Play Without DG")); - clear.run(); + this.buttonList.add(new GuiButton(0, sr.getScaledWidth()/2-100,sr.getScaledHeight()-70 ,"Close Minecraft")); + this.buttonList.add(new GuiButton(1, sr.getScaledWidth()/2-100,sr.getScaledHeight()-40 ,"Play Without DG")); } @Override @@ -84,7 +54,7 @@ public class GuiLoadingError extends GuiScreen { if (button.id == 0) { FMLCommonHandler.instance().exitJava(-1,true); } else if (button.id == 1) { - Minecraft.getMinecraft().displayGuiScreen(null); + Minecraft.getMinecraft().displayGuiScreen(originalGUI); } } @@ -94,8 +64,8 @@ public class GuiLoadingError extends GuiScreen { ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft()); FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj; - fontRenderer.drawString("DungeonsGuide has ran into unknown error while loading itself", (sr.getScaledWidth()-fontRenderer.getStringWidth("DungeonsGuide has ran into unknown error while loading itself"))/2,40,0xFFFF0000); - fontRenderer.drawString("Please contact DungeonsGuide support with this screen", (sr.getScaledWidth()-fontRenderer.getStringWidth("Please contact DungeonsGuide support with this screen"))/2, (int) (40+fontRenderer.FONT_HEIGHT*1.5),0xFFFF0000); + fontRenderer.drawString("DungeonsGuide has ran into error while loading itself", (sr.getScaledWidth()-fontRenderer.getStringWidth("DungeonsGuide has ran into error while loading itself"))/2,40,0xFFFF0000); + fontRenderer.drawString("Please contact DungeonsGuide support with this screen", (sr.getScaledWidth()-fontRenderer.getStringWidth("Please contact developer with this screen"))/2, (int) (40+fontRenderer.FONT_HEIGHT*1.5),0xFFFF0000); int tenth = sr.getScaledWidth() / 10; @@ -108,27 +78,6 @@ public class GuiLoadingError extends GuiScreen { } GL11.glDisable(GL11.GL_SCISSOR_TEST); - - GlStateManager.pushMatrix(); - GlStateManager.scale(1.0/sr.getScaleFactor(), 1.0/sr.getScaleFactor(), 1); - GlStateManager.translate(0, Minecraft.getMinecraft().displayHeight - qrCode.getHeight() * 3, 0); - Tessellator tessellator = Tessellator.getInstance(); - WorldRenderer worldrenderer = tessellator.getWorldRenderer(); - float f = 0.0F; - Minecraft.getMinecraft().getTextureManager().bindTexture(this.location); - GlStateManager.enableBlend(); - GlStateManager.tryBlendFuncSeparate(1, 771, 0, 1); - GlStateManager.disableAlpha(); - worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); - worldrenderer.pos(0, qrCode.getHeight()*3, 0).tex(0.0D, 1.0D).endVertex(); - worldrenderer.pos(qrCode.getWidth()*3, qrCode.getHeight()*3, 0).tex(1.0D, 1.0D).endVertex(); - worldrenderer.pos(qrCode.getWidth()*3, 0, 0).tex(1.0D, 0.0D).endVertex(); - worldrenderer.pos(0, 0, 0).tex(0.0D, 0.0D).endVertex(); - tessellator.draw(); - GlStateManager.enableAlpha(); - GlStateManager.disableBlend(); - GlStateManager.popMatrix(); - super.drawScreen(mouseX, mouseY, partialTicks); } 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 53d9b70d..820ce0c8 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/IDGLoader.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/IDGLoader.java @@ -19,21 +19,17 @@ package kr.syeyoung.dungeonsguide.launcher.loader; import kr.syeyoung.dungeonsguide.launcher.DGInterface; -import kr.syeyoung.dungeonsguide.launcher.authentication.Authenticator; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; -import net.minecraftforge.common.config.Configuration; - -import java.io.InputStream; public interface IDGLoader { - void loadJar(Authenticator authenticator) throws InstantiationException, IllegalAccessException, ClassNotFoundException; + DGInterface loadDungeonsGuide() throws InstantiationException, IllegalAccessException, ClassNotFoundException; DGInterface getInstance(); - void unloadJar() throws ReferenceLeakedException; + void unloadDungeonsGuide() throws ReferenceLeakedException; boolean isUnloadable(); boolean isLoaded(); - String strategyName(); + String branchName(); 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 0b6cf124..fff63a07 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/JarLoader.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/JarLoader.java @@ -20,7 +20,6 @@ package kr.syeyoung.dungeonsguide.launcher.loader; import kr.syeyoung.dungeonsguide.launcher.DGInterface; import kr.syeyoung.dungeonsguide.launcher.Main; -import kr.syeyoung.dungeonsguide.launcher.authentication.Authenticator; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; import java.io.InputStream; @@ -84,7 +83,7 @@ public class JarLoader implements IDGLoader { private JarClassLoader classLoader; @Override - public void loadJar(Authenticator authenticator) throws ClassNotFoundException, InstantiationException, IllegalAccessException { + public DGInterface loadDungeonsGuide() throws ClassNotFoundException, InstantiationException, IllegalAccessException { if (dgInterface != null) throw new IllegalStateException("Already loaded"); classLoader = new JarClassLoader(new URL[] { @@ -93,6 +92,7 @@ public class JarLoader implements IDGLoader { dgInterface = (DGInterface) classLoader.loadClassResolve("kr.syeyoung.dungeonsguide.DungeonsGuide", true).newInstance(); phantomReference = new PhantomReference<>(classLoader, refQueue); + return dgInterface; } @Override @@ -101,7 +101,7 @@ public class JarLoader implements IDGLoader { } @Override - public void unloadJar() throws ReferenceLeakedException { + public void unloadDungeonsGuide() throws ReferenceLeakedException { classLoader = null; dgInterface.unload(); dgInterface = null; @@ -123,7 +123,7 @@ public class JarLoader implements IDGLoader { } @Override - public String strategyName() { + public String branchName() { 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 1338138d..01159b34 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/LocalLoader.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/LocalLoader.java @@ -19,7 +19,6 @@ package kr.syeyoung.dungeonsguide.launcher.loader; import kr.syeyoung.dungeonsguide.launcher.DGInterface; -import kr.syeyoung.dungeonsguide.launcher.authentication.Authenticator; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; import java.io.InputStream; @@ -28,9 +27,9 @@ public class LocalLoader implements IDGLoader { private DGInterface dgInterface; @Override - public void loadJar(Authenticator authenticator) throws ClassNotFoundException, InstantiationException, IllegalAccessException { + public DGInterface loadDungeonsGuide() throws ClassNotFoundException, InstantiationException, IllegalAccessException { if (dgInterface != null) throw new IllegalStateException("Already loaded"); - dgInterface = (DGInterface) Class.forName("kr.syeyoung.dungeonsguide.DungeonsGuide").newInstance(); + return dgInterface = (DGInterface) Class.forName("kr.syeyoung.dungeonsguide.DungeonsGuide").newInstance(); } @Override @@ -39,7 +38,7 @@ public class LocalLoader implements IDGLoader { } @Override - public void unloadJar() throws ReferenceLeakedException { + public void unloadDungeonsGuide() throws ReferenceLeakedException { throw new UnsupportedOperationException(); } @Override @@ -53,7 +52,7 @@ public class LocalLoader implements IDGLoader { } @Override - public String strategyName() { + public String branchName() { return "local"; } 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 649dfdc5..5a310738 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 @@ -1,35 +1,37 @@ /* - * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod - * Copyright (C) 2021 cyoung06 + * 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 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. + * 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/>. + * 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.url; -import kr.syeyoung.dungeonsguide.launcher.authentication.Authenticator; +import kr.syeyoung.dungeonsguide.launcher.auth.ResourceManager; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; import java.net.URL; import java.net.URLConnection; public class DGConnection extends URLConnection { - private final Authenticator authenticator; - protected DGConnection(URL url, Authenticator a) { + + protected DGConnection(URL url) { super(url); connected = false; - this.authenticator = a; } @Override @@ -37,10 +39,10 @@ public class DGConnection extends URLConnection { } @Override public InputStream getInputStream() throws IOException { - if (authenticator != null) { + if (ResourceManager.getInstance().getResources() != null) { String path = url.getPath().substring(1); -// if (!authenticator.getResources().containsKey(path)) throw new FileNotFoundException(); -// return new ByteArrayInputStream(authenticator.getResources().get(path)); + if (!ResourceManager.getInstance().getResources().containsKey(path)) throw new FileNotFoundException(); + return new ByteArrayInputStream(ResourceManager.getInstance().getResources().get(path)); } throw new FileNotFoundException(); } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandler.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandler.java index 82ddff18..456e7f8c 100755 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandler.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandler.java @@ -1,24 +1,23 @@ /* - * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod - * Copyright (C) 2021 cyoung06 + * 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 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. + * 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/>. + * 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.url; -import kr.syeyoung.dungeonsguide.launcher.authentication.Authenticator; import lombok.AllArgsConstructor; import java.io.IOException; @@ -28,9 +27,8 @@ import java.net.URLStreamHandler; @AllArgsConstructor public class DGStreamHandler extends URLStreamHandler { - private final Authenticator auth; @Override protected URLConnection openConnection(URL url) throws IOException { - return new DGConnection(url, this.auth); + return new DGConnection(url); } } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandlerFactory.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandlerFactory.java index a7b50046..a7eefa37 100755 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandlerFactory.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/url/DGStreamHandlerFactory.java @@ -1,24 +1,23 @@ /* - * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod - * Copyright (C) 2021 cyoung06 + * 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 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. + * 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/>. + * 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.url; -import kr.syeyoung.dungeonsguide.launcher.authentication.Authenticator; import lombok.AllArgsConstructor; import java.net.URLStreamHandler; @@ -26,11 +25,10 @@ import java.net.URLStreamHandlerFactory; @AllArgsConstructor public class DGStreamHandlerFactory implements URLStreamHandlerFactory { - private final Authenticator auth; @Override public URLStreamHandler createURLStreamHandler(String protocol) { if ("z".equals(protocol)) { - return new DGStreamHandler(this.auth); + return new DGStreamHandler(); } return null; } |