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();
}
}