package sk.tomsik68.mclauncher.util; import net.minidev.json.JSONStyle; import sk.tomsik68.mclauncher.api.json.IJSONSerializable; import sk.tomsik68.mclauncher.impl.login.yggdrasil.YDServiceAuthenticationException; import javax.net.ssl.HttpsURLConnection; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.security.cert.Certificate; /** * Http communication utilities */ public final class HttpUtils { /** * Executes a simple HTTP-GET request * @param url URL to request * @return The result of request * @throws Exception I/O Exception or HTTP errors */ public static String httpGet(String url) throws Exception { URL u = new URL(url); HttpURLConnection connection = (HttpURLConnection) u.openConnection(); InputStream is = connection.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is)); String line; StringBuilder response = new StringBuilder(); while ((line = br.readLine()) != null) { response = response.append(line).append('\r'); } connection.disconnect(); return response.toString(); } /** * Execute a secured POST request * @param url URL to request * @param keyInput the secret key to be used * @param parameters Parameters in form <code>name=Tom&password=pass123</code>. They needn't to be URL-encoded(it will be done automatically) * @return The result of request * @throws Exception I/O Exception, HTTP errors or invalid key */ public static String securePostWithKey(String url, InputStream keyInput, String parameters) throws Exception { URL u = new URL(url); HttpsURLConnection connection = (HttpsURLConnection) u.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); connection.setRequestProperty("Content-Length", "" + parameters.getBytes().length); connection.setRequestProperty("Content-Language", "en-US"); connection.setUseCaches(false); connection.setDoInput(true); connection.setDoOutput(true); connection.connect(); Certificate cert = connection.getServerCertificates()[0]; byte[] serverKey = cert.getPublicKey().getEncoded(); DataInputStream dis = new DataInputStream(keyInput); for (int i = 0; i < serverKey.length; ++i) { if (dis.readByte() != serverKey[i]) { throw new SecurityException("Invalid Server Key!"); } } DataOutputStream dos = new DataOutputStream(connection.getOutputStream()); dos.writeBytes(URLEncoder.encode(parameters, "utf-8")); dos.flush(); dos.close(); BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; StringBuilder response = new StringBuilder(); while ((line = br.readLine()) != null) { response = response.append(line).append('\r'); } br.close(); connection.disconnect(); return response.toString(); } /** * Posts a JSON object to URL and returns result * @param url URL to request * @param request the object to send using post. It will be serialized to JSON string * @return Result of request * @throws IOException I/O Exception or HTTP errors */ public static String doJSONPost(String url, IJSONSerializable request) throws IOException { URL u = new URL(url); String json = request.toJSON().toJSONString(JSONStyle.LT_COMPRESS); byte[] bytes = json.getBytes(); HttpURLConnection connection = (HttpURLConnection) u.openConnection(); connection.setConnectTimeout(15000); connection.setReadTimeout(15000); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/json"); connection.setRequestProperty("Content-Length", "" + bytes.length); connection.setRequestProperty("Content-Language", "en-US"); connection.setUseCaches(false); connection.setDoInput(true); connection.setDoOutput(true); DataOutputStream dos = new DataOutputStream(connection.getOutputStream()); dos.write(bytes); dos.flush(); dos.close(); BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; StringBuilder result = new StringBuilder(); while ((line = br.readLine()) != null) { result = result.append(line).append('\r'); } br.close(); connection.disconnect(); return result.toString(); } public static String doJSONAuthenticationPost(String url, IJSONSerializable request) throws IOException, YDServiceAuthenticationException { URL u = new URL(url); String json = request.toJSON().toJSONString(JSONStyle.LT_COMPRESS); byte[] bytes = json.getBytes(); HttpURLConnection connection = (HttpURLConnection) u.openConnection(); connection.setConnectTimeout(15000); connection.setReadTimeout(15000); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/json"); connection.setRequestProperty("Content-Length", "" + bytes.length); connection.setRequestProperty("Content-Language", "en-US"); connection.setUseCaches(false); connection.setDoInput(true); connection.setDoOutput(true); /* Removed flush as will throw error if authentication fails and DataOutputStream will not close properley, Close will happily handle this for us */ DataOutputStream dos = new DataOutputStream(connection.getOutputStream()); dos.write(bytes); dos.close(); /* * At this point we should be checking for a successful response code before moving forward * Monjang will actually return a 403 error if a invalid username or password is given and * attempting to get the InputStream will throw an IOException without knowing what caused this */ int response = connection.getResponseCode(); if(response == 403) { throw new YDServiceAuthenticationException("Failed to log in, Invalid Username / Password."); } // 400 Response = Invalid Request if(response == 400) { throw new YDServiceAuthenticationException("Failed to authenticate, Bad Authentication Request."); } // Now we can read from the connection input stream BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line; StringBuilder result = new StringBuilder(); while ((line = br.readLine()) != null) { result = result.append(line).append('\r'); } br.close(); connection.disconnect(); return result.toString(); } }