aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java
diff options
context:
space:
mode:
authorRoman / Linnea Gräf <roman.graef@gmail.com>2022-09-29 17:25:37 +0200
committerGitHub <noreply@github.com>2022-09-29 17:25:37 +0200
commit2dd4a2b36211c380c0bf4e231859dfafd3c04a5b (patch)
tree20cde26c05f32699ccb91cda1d37b67f4eea6c62 /src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java
parentcbcc4c3b4004cbf3f86aeab515ea94a93b4efd1e (diff)
downloadnotenoughupdates-2dd4a2b36211c380c0bf4e231859dfafd3c04a5b.tar.gz
notenoughupdates-2dd4a2b36211c380c0bf4e231859dfafd3c04a5b.tar.bz2
notenoughupdates-2dd4a2b36211c380c0bf4e231859dfafd3c04a5b.zip
Add custom keystore and refactor HypixelApi.java (#318)
* Add custom keystore and refactor HypixelApi.java * Fix inputstream leak (+ less console spam) * Fix HOTM crash * Use api selected variable to find best profile * Number formatting * Make old profiles show again Co-authored-by: nopo <nopotheemail@gmail.com>
Diffstat (limited to 'src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java')
-rw-r--r--src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java203
1 files changed, 203 insertions, 0 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java
new file mode 100644
index 00000000..8c594911
--- /dev/null
+++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2022 NotEnoughUpdates contributors
+ *
+ * This file is part of NotEnoughUpdates.
+ *
+ * NotEnoughUpdates is free software: you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * NotEnoughUpdates 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with NotEnoughUpdates. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package io.github.moulberry.notenoughupdates.util;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import io.github.moulberry.notenoughupdates.NotEnoughUpdates;
+import org.apache.commons.io.IOUtils;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.message.BasicNameValuePair;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManagerFactory;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.zip.GZIPInputStream;
+
+public class ApiUtil {
+ private static final Gson gson = new Gson();
+ private static final ExecutorService executorService = Executors.newFixedThreadPool(3);
+ private static final String USER_AGENT = "NotEnoughUpdates/" + NotEnoughUpdates.VERSION;
+ private static SSLContext ctx;
+
+ static {
+ try {
+ KeyStore letsEncryptStore = KeyStore.getInstance("JKS");
+ letsEncryptStore.load(ApiUtil.class.getResourceAsStream("/neukeystore.jks"), "neuneu".toCharArray());
+ ctx = SSLContext.getInstance("TLS");
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ kmf.init(letsEncryptStore, null);
+ tmf.init(letsEncryptStore);
+ ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ } catch (KeyStoreException | NoSuchAlgorithmException | KeyManagementException | UnrecoverableKeyException |
+ IOException | CertificateException e) {
+ System.out.println("Failed to load NEU keystore. A lot of API requests won't work");
+ e.printStackTrace();
+ }
+ }
+
+ public static class Request {
+
+ private final List<NameValuePair> queryArguments = new ArrayList<>();
+ private String baseUrl = null;
+ private boolean shouldGunzip = false;
+ private String method = "GET";
+
+ public Request method(String method) {
+ this.method = method;
+ return this;
+ }
+
+ public Request url(String baseUrl) {
+ this.baseUrl = baseUrl;
+ return this;
+ }
+
+ public Request queryArgument(String key, String value) {
+ queryArguments.add(new BasicNameValuePair(key, value));
+ return this;
+ }
+
+ public Request queryArguments(Collection<NameValuePair> queryArguments) {
+ this.queryArguments.addAll(queryArguments);
+ return this;
+ }
+
+ public Request gunzip() {
+ shouldGunzip = true;
+ return this;
+ }
+
+ private CompletableFuture<URL> buildUrl() {
+ CompletableFuture<URL> fut = new CompletableFuture<>();
+ try {
+ fut.complete(new URIBuilder(baseUrl)
+ .addParameters(queryArguments)
+ .build()
+ .toURL());
+ } catch (URISyntaxException |
+ MalformedURLException |
+ NullPointerException e) { // Using CompletableFuture as an exception monad, isn't that exiting?
+ fut.completeExceptionally(e);
+ }
+ return fut;
+ }
+
+ public CompletableFuture<String> requestString() {
+ return buildUrl().thenApplyAsync(url -> {
+ try {
+ InputStream inputStream = null;
+ URLConnection conn = null;
+ try {
+ conn = url.openConnection();
+ if (conn instanceof HttpsURLConnection && ctx != null) {
+ HttpsURLConnection sslConn = (HttpsURLConnection) conn;
+ sslConn.setSSLSocketFactory(ctx.getSocketFactory());
+ }
+ if (conn instanceof HttpURLConnection) {
+ ((HttpURLConnection) conn).setRequestMethod(method);
+ }
+ conn.setConnectTimeout(10000);
+ conn.setReadTimeout(10000);
+ conn.setRequestProperty("User-Agent", USER_AGENT);
+
+ inputStream = conn.getInputStream();
+
+ if (shouldGunzip) {
+ inputStream = new GZIPInputStream(inputStream);
+ }
+
+ // While the assumption of UTF8 isn't always true; it *should* always be true.
+ // Not in the sense that this will hold in most cases (although that as well),
+ // but in the sense that any violation of this better have a good reason.
+ return IOUtils.toString(inputStream, StandardCharsets.UTF_8);
+ } finally {
+ try {
+ if (inputStream != null) {
+ inputStream.close();
+ }
+ } finally {
+ if (conn instanceof HttpURLConnection) {
+ ((HttpURLConnection) conn).disconnect();
+ }
+ }
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e); // We can rethrow, since supplyAsync catches exceptions.
+ }
+ }, executorService);
+ }
+
+ public CompletableFuture<JsonObject> requestJson() {
+ return requestJson(JsonObject.class);
+ }
+
+ public <T> CompletableFuture<T> requestJson(Class<? extends T> clazz) {
+ return requestString().thenApply(str -> gson.fromJson(str, clazz));
+ }
+
+ }
+
+ public Request request() {
+ return new Request();
+ }
+
+ public Request newHypixelApiRequest(String apiPath) {
+ return newAnonymousHypixelApiRequest(apiPath)
+ .queryArgument("key", NotEnoughUpdates.INSTANCE.config.apiData.apiKey);
+ }
+
+ public Request newAnonymousHypixelApiRequest(String apiPath) {
+ return new Request()
+ .url("https://api.hypixel.net/" + apiPath);
+ }
+
+ public Request newMoulberryRequest(String path) {
+ return new Request()
+ .url(getMyApiURL() + path);
+ }
+
+ private String getMyApiURL() {
+ return String.format("https://%s/", NotEnoughUpdates.INSTANCE.config.apiData.moulberryCodesApi);
+ }
+}