diff options
author | Roman / Linnea Gräf <roman.graef@gmail.com> | 2023-07-21 09:28:48 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-21 09:28:48 +0200 |
commit | 34835697e889799e2b4e97c3bbf0ea73c04d5a64 (patch) | |
tree | 421de44a9dcff26b44bab18fcde9ed89ef066f28 /src/main/java/io | |
parent | 3184880b31e9dc8d8985411468112c6b49e5b480 (diff) | |
download | NotEnoughUpdates-34835697e889799e2b4e97c3bbf0ea73c04d5a64.tar.gz NotEnoughUpdates-34835697e889799e2b4e97c3bbf0ea73c04d5a64.tar.bz2 NotEnoughUpdates-34835697e889799e2b4e97c3bbf0ea73c04d5a64.zip |
Use ursa-minor as API proxy (#762)
* Use ursa-minor as API proxy
* Allow setting a ursa server url
* Make client aware of x-ursa-expires
* Make profile data syncer work using legacy api
* Add better header support
* Add manual call functionality
* Improve callUrsa to allow for raw strings
* Save tokens better and add logs on http failure status codes
* Remove API key requirement for PV
* Make museum in pv also use ursa
Diffstat (limited to 'src/main/java/io')
9 files changed, 86 insertions, 37 deletions
diff --git a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java index cbc3ce3b..c60e7317 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/NEUManager.java @@ -39,6 +39,7 @@ import io.github.moulberry.notenoughupdates.util.ApiUtil; import io.github.moulberry.notenoughupdates.util.Constants; import io.github.moulberry.notenoughupdates.util.ItemResolutionQuery; import io.github.moulberry.notenoughupdates.util.ItemUtils; +import io.github.moulberry.notenoughupdates.util.UrsaClient; import io.github.moulberry.notenoughupdates.util.Utils; import net.minecraft.client.Minecraft; import net.minecraft.client.settings.KeyBinding; @@ -130,6 +131,7 @@ public class NEUManager { public long viewItemAttemptTime = 0; public final ApiUtil apiUtils = new ApiUtil(); + public final UrsaClient ursaClient = new UrsaClient(apiUtils); private final Map<String, ItemStack> itemstackCache = new HashMap<>(); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/customtypes/NEUDebugFlag.java b/src/main/java/io/github/moulberry/notenoughupdates/options/customtypes/NEUDebugFlag.java index ab1a6516..ba638b9b 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/customtypes/NEUDebugFlag.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/customtypes/NEUDebugFlag.java @@ -19,7 +19,9 @@ package io.github.moulberry.notenoughupdates.options.customtypes; +import io.github.moulberry.notenoughupdates.util.MinecraftExecutor; import io.github.moulberry.notenoughupdates.util.NEUDebugLogger; +import net.minecraft.client.Minecraft; import java.util.Arrays; import java.util.List; @@ -46,7 +48,7 @@ public enum NEUDebugFlag { } public void log(String message) { - NEUDebugLogger.log(this, message); + NEUDebugLogger.log(this, message); } public boolean isSet() { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ApiData.java b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ApiData.java index 6d93b98d..ef871b83 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ApiData.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/options/seperateSections/ApiData.java @@ -127,6 +127,15 @@ public class ApiData { @ConfigEditorText public String moulberryCodesApi = "moulberry.codes"; + + @Expose + @ConfigOption( + name = "Ursa Minor Proxy", + desc = "§4Do §lNOT §r§4change this, unless you know exactly what you are doing" + ) + @ConfigEditorText + public String ursaApi = "https://ursa.notenoughupdates.org/"; + public String getCommitApiUrl() { return String.format("https://api.github.com/repos/%s/%s/commits/%s", repoUser, repoName, repoBranch); } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java index a81956f2..ed3cf8ef 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/ProfileViewer.java @@ -22,6 +22,7 @@ package io.github.moulberry.notenoughupdates.profileviewer; import com.google.gson.JsonObject; import io.github.moulberry.notenoughupdates.NEUManager; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; +import io.github.moulberry.notenoughupdates.util.UrsaClient; import io.github.moulberry.notenoughupdates.util.Utils; import lombok.Getter; import net.minecraft.init.Blocks; @@ -474,7 +475,7 @@ public class ProfileViewer { updatingResourceCollection.set(true); NotEnoughUpdates.INSTANCE.manager.apiUtils - .newHypixelApiRequest("resources/skyblock/collections") + .newAnonymousHypixelApiRequest("resources/skyblock/collections") .requestJson() .thenAccept(jsonObject -> { updatingResourceCollection.set(false); @@ -528,11 +529,8 @@ public class ProfileViewer { callback.accept(null); } else { if (!uuidToHypixelProfile.containsKey(uuid)) { - manager.apiUtils - .newHypixelApiRequest("player") - .queryArgument("uuid", uuid) - .maxCacheAge(Duration.ofSeconds(30)) - .requestJson() + manager.ursaClient + .get(UrsaClient.player(Utils.parseDashlessUUID(uuid))) .thenAccept(playerJson -> { if ( playerJson != null && diff --git a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/SkyblockProfiles.java b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/SkyblockProfiles.java index 88251d32..61872980 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/SkyblockProfiles.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/profileviewer/SkyblockProfiles.java @@ -28,6 +28,7 @@ import io.github.moulberry.notenoughupdates.profileviewer.bestiary.BestiaryData; import io.github.moulberry.notenoughupdates.profileviewer.weight.senither.SenitherWeight; import io.github.moulberry.notenoughupdates.profileviewer.weight.weight.Weight; import io.github.moulberry.notenoughupdates.util.Constants; +import io.github.moulberry.notenoughupdates.util.UrsaClient; import io.github.moulberry.notenoughupdates.util.Utils; import io.github.moulberry.notenoughupdates.util.hypixelapi.ProfileCollectionInfo; import lombok.Getter; @@ -84,6 +85,7 @@ public class SkyblockProfiles { "social" ); private final ProfileViewer profileViewer; + // TODO: replace with UUID type private final String uuid; private final AtomicBoolean updatingSkyblockProfilesState = new AtomicBoolean(false); private final AtomicBoolean updatingGuildInfoState = new AtomicBoolean(false); @@ -119,10 +121,8 @@ public class SkyblockProfiles { lastStatusInfoState = currentTime; updatingPlayerStatusState.set(true); - profileViewer.getManager().apiUtils - .newHypixelApiRequest("status") - .queryArgument("uuid", uuid) - .requestJson() + profileViewer.getManager().ursaClient + .get(UrsaClient.status(Utils.parseDashlessUUID(uuid))) .handle((jsonObject, ex) -> { updatingPlayerStatusState.set(false); @@ -143,10 +143,8 @@ public class SkyblockProfiles { lastBingoInfoState = currentTime; updatingBingoInfo.set(true); - NotEnoughUpdates.INSTANCE.manager.apiUtils - .newHypixelApiRequest("skyblock/bingo") - .queryArgument("uuid", uuid) - .requestJson() + NotEnoughUpdates.INSTANCE.manager.ursaClient + .get(UrsaClient.bingo(Utils.parseDashlessUUID(uuid))) .handle(((jsonObject, throwable) -> { updatingBingoInfo.set(false); @@ -317,10 +315,8 @@ public class SkyblockProfiles { lastPlayerInfoState = currentTime; updatingSkyblockProfilesState.set(true); - profileViewer.getManager().apiUtils - .newHypixelApiRequest("skyblock/profiles") - .queryArgument("uuid", uuid) - .requestJson() + profileViewer.getManager().ursaClient + .get(UrsaClient.profiles(Utils.parseDashlessUUID(uuid))) .handle((profilesJson, throwable) -> { if (profilesJson != null && profilesJson.has("success") && profilesJson.get("success").getAsBoolean() && profilesJson.has("profiles")) { @@ -388,10 +384,8 @@ public class SkyblockProfiles { lastGuildInfoState = currentTime; updatingGuildInfoState.set(true); - profileViewer.getManager().apiUtils - .newHypixelApiRequest("guild") - .queryArgument("player", uuid) - .requestJson() + profileViewer.getManager().ursaClient + .get(UrsaClient.guild(Utils.parseDashlessUUID(uuid))) .handle((jsonObject, ex) -> { updatingGuildInfoState.set(false); @@ -649,9 +643,7 @@ public class SkyblockProfiles { updatingMuseumData.set(true); String profileId = getOuterProfileJson().get("profile_id").getAsString(); - profileViewer.getManager().apiUtils.newHypixelApiRequest("skyblock/museum") - .queryArgument("profile", profileId) - .requestJson() + profileViewer.getManager().ursaClient.get(UrsaClient.museumForProfile(profileId)) .handle((museumJson, throwable) -> { if (museumJson != null && museumJson.has("success") && museumJson.get("success").getAsBoolean() && museumJson.has("members")) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java index 4cb1abc8..3b6aed84 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ApiUtil.java @@ -58,10 +58,12 @@ import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.stream.Collectors; import java.util.zip.GZIPInputStream; public class ApiUtil { @@ -90,16 +92,17 @@ public class ApiUtil { 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 = SSLContext.getInstance("TLS"); 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(); + ctx = null; } } @@ -129,6 +132,8 @@ public class ApiUtil { private Duration maxCacheAge = Duration.ofSeconds(500); private String method = "GET"; private String postData = null; + private final Map<String, String> headers = new HashMap<>(); + private Map<String, List<String>> responseHeaders = new HashMap<>(); private String postContentType = null; public Request method(String method) { @@ -136,6 +141,11 @@ public class ApiUtil { return this; } + public Request header(String key, String value) { + this.headers.put(key, value); + return this; + } + /** * Specify a cache timeout of {@code null} to signify an uncacheable request. * Non {@code GET} requests are always uncacheable. @@ -196,9 +206,17 @@ public class ApiUtil { return new ApiCache.CacheKey(baseUrl, queryArguments, shouldGunzip); } + /** + * Note: This map may be empty on cache hits. + */ + public Map<String, List<String>> getResponseHeaders() { + return responseHeaders; + } + private CompletableFuture<String> requestString0() { return buildUrl().thenApplyAsync(url -> { InputStream inputStream = null; + int httpStatusCode = 200; URLConnection conn = null; try { try { @@ -212,6 +230,9 @@ public class ApiUtil { conn.setConnectTimeout(10000); conn.setReadTimeout(10000); conn.setRequestProperty("User-Agent", getUserAgent()); + for (Map.Entry<String, String> header : headers.entrySet()) { + conn.setRequestProperty(header.getKey(), header.getValue()); + } if (this.postContentType != null) { conn.setRequestProperty("Content-Type", this.postContentType); } @@ -228,16 +249,33 @@ public class ApiUtil { } } - inputStream = conn.getInputStream(); + if (conn instanceof HttpURLConnection) { + HttpURLConnection httpConn = (HttpURLConnection) conn; + httpStatusCode = httpConn.getResponseCode(); + if (httpStatusCode >= 400) { + inputStream = httpConn.getErrorStream(); + } + } + if (inputStream == null) + inputStream = conn.getInputStream(); if (shouldGunzip || "gzip".equals(conn.getContentEncoding())) { inputStream = new GZIPInputStream(inputStream); } + responseHeaders = conn.getHeaderFields().entrySet().stream() + .collect(Collectors.toMap( + it -> it.getKey() == null ? null : it.getKey().toLowerCase(Locale.ROOT), + it -> new ArrayList<>(it.getValue()) + )); // 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); + String response = IOUtils.toString(inputStream, StandardCharsets.UTF_8); + if (httpStatusCode >= 400) { + throw new HttpStatusCodeException(url, httpStatusCode, response); + } + return response; } finally { try { if (inputStream != null) { @@ -298,13 +336,15 @@ public class ApiUtil { } public static void patchHttpsRequest(HttpsURLConnection connection) { - connection.setSSLSocketFactory(ctx.getSocketFactory()); + if (ctx != null && connection != null) + connection.setSSLSocketFactory(ctx.getSocketFactory()); } public Request request() { return new Request(); } + @Deprecated public Request newHypixelApiRequest(String apiPath) { return newAnonymousHypixelApiRequest(apiPath) .queryArgument("key", NotEnoughUpdates.INSTANCE.config.apiData.apiKey); diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/NEUDebugLogger.java b/src/main/java/io/github/moulberry/notenoughupdates/util/NEUDebugLogger.java index e5d00a66..d73a500c 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/NEUDebugLogger.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/NEUDebugLogger.java @@ -22,7 +22,6 @@ package io.github.moulberry.notenoughupdates.util; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.options.customtypes.NEUDebugFlag; import net.minecraft.client.Minecraft; -import net.minecraft.util.ChatComponentText; import net.minecraft.util.EnumChatFormatting; import java.util.function.Consumer; @@ -34,7 +33,7 @@ public class NEUDebugLogger { public static boolean allFlagsEnabled = false; private static void chatLogger(String message) { - Utils.addChatMessage(EnumChatFormatting.YELLOW + "[NEU DEBUG] " + message); + mc.addScheduledTask(() -> Utils.addChatMessage(EnumChatFormatting.YELLOW + "[NEU DEBUG] " + message)); } public static boolean isFlagEnabled(NEUDebugFlag flag) { diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/ProfileApiSyncer.java b/src/main/java/io/github/moulberry/notenoughupdates/util/ProfileApiSyncer.java index 67ed7c7b..ed88a6a5 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/ProfileApiSyncer.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/ProfileApiSyncer.java @@ -19,6 +19,7 @@ package io.github.moulberry.notenoughupdates.util; +import com.google.gson.JsonObject; import io.github.moulberry.notenoughupdates.NotEnoughUpdates; import io.github.moulberry.notenoughupdates.profileviewer.SkyblockProfiles; import net.minecraft.client.Minecraft; @@ -89,9 +90,15 @@ public class ProfileApiSyncer { if (Minecraft.getMinecraft().thePlayer == null) return; String uuid = Minecraft.getMinecraft().thePlayer.getUniqueID().toString().replace("-", ""); - NotEnoughUpdates.profileViewer.getOrLoadSkyblockProfiles(uuid, (profile) -> { - for (Consumer<SkyblockProfiles> c : finishSyncCallbacks.values()) c.accept(profile); - finishSyncCallbacks.clear(); - }); + NotEnoughUpdates.INSTANCE.manager.apiUtils + .newHypixelApiRequest("/skyblock/profiles") + .queryArgument("uuid", uuid) + .requestJson() + .thenAcceptAsync((profile) -> { + SkyblockProfiles skyblockProfiles = new SkyblockProfiles(NotEnoughUpdates.profileViewer, uuid); + for (Consumer<SkyblockProfiles> c : finishSyncCallbacks.values()) + c.accept((skyblockProfiles)); + finishSyncCallbacks.clear(); + }, MinecraftExecutor.OnThread); } } diff --git a/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java b/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java index 2d637ab8..e5a0e1b8 100644 --- a/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java +++ b/src/main/java/io/github/moulberry/notenoughupdates/util/SBInfo.java @@ -459,7 +459,7 @@ public class SBInfo { public void updateMayor() { NotEnoughUpdates.INSTANCE.manager.apiUtils - .newHypixelApiRequest("resources/skyblock/election") + .newAnonymousHypixelApiRequest("resources/skyblock/election") .requestJson() .thenAccept(newJson -> mayorJson = newJson); } |