diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java b/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java index a6599cbd..bf36474a 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/HDSkinManager.java @@ -24,6 +24,7 @@ import com.mumfrey.liteloader.util.log.LiteLoaderLogger; import com.voxelmodpack.hdskins.gui.GuiSkins; import com.voxelmodpack.hdskins.resource.SkinResourceManager; import com.voxelmodpack.hdskins.skins.AsyncCacheLoader; +import com.voxelmodpack.hdskins.skins.BethlehemSkinServer; import com.voxelmodpack.hdskins.skins.LegacySkinServer; import com.voxelmodpack.hdskins.skins.ServerType; import com.voxelmodpack.hdskins.skins.SkinServer; @@ -98,6 +99,7 @@ public final class HDSkinManager implements IResourceManagerReloadListener { // register default skin server types addSkinServerType(LegacySkinServer.class); addSkinServerType(ValhallaSkinServer.class); + addSkinServerType(BethlehemSkinServer.class); } public void setPrefferedSkinsGuiClass(Class clazz) { diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/BethlehemSkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/BethlehemSkinServer.java index 504dfa50..6b05aa88 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/skins/BethlehemSkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/BethlehemSkinServer.java @@ -1,39 +1,21 @@ package com.voxelmodpack.hdskins.skins; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; import java.net.URI; -import java.net.URL; import java.util.Locale; import java.util.Map; import java.util.Optional; -import java.util.UUID; import java.util.concurrent.CompletableFuture; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; +import com.google.common.collect.ImmutableMap.Builder; import com.google.gson.JsonObject; import com.google.gson.annotations.Expose; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.exceptions.AuthenticationException; -import com.mojang.authlib.minecraft.MinecraftProfileTexture; -import com.mojang.authlib.minecraft.MinecraftSessionService; import com.mojang.authlib.minecraft.MinecraftProfileTexture.Type; import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload; import com.mojang.util.UUIDTypeAdapter; import com.voxelmodpack.hdskins.HDSkinManager; -import com.voxelmodpack.hdskins.upload.ThreadMultipartPostUpload; - -import net.minecraft.client.Minecraft; import net.minecraft.util.Session; @ServerType("bethlehem") @@ -41,8 +23,6 @@ public class BethlehemSkinServer implements SkinServer { private static final String SERVER_ID = "7853dfddc358333843ad55a2c7485c4aa0380a51"; - private static final Logger logger = LogManager.getLogger(); - @Expose private final String address; @@ -50,52 +30,18 @@ public class BethlehemSkinServer implements SkinServer { this.address = address; } - private static final Gson gson = new GsonBuilder().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create(); - @Override public Optional loadProfileData(GameProfile profile) { + NetClient client = new NetClient("GET", getPath(profile)); - String url = getPath(profile); + String json = client.getResponseText(); - HttpURLConnection urlConnection = null; - BufferedReader reader = null; + JsonObject s = gson.fromJson(json, JsonObject.class); - try { - urlConnection = (HttpURLConnection) new URL(url).openConnection(Minecraft.getMinecraft().getProxy()); - urlConnection.setDoInput(true); - urlConnection.setDoOutput(false); - urlConnection.connect(); + if (s.has("success") && s.get("success").getAsBoolean()) { + s = s.get("data").getAsJsonObject(); - if (urlConnection.getResponseCode() / 100 != 2) { - throw new IOException("Bad response code: " + urlConnection.getResponseCode()); - } - - reader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); - - StringBuilder builder = new StringBuilder(); - - int ch; - while ((ch = reader.read()) != -1) { - builder.append((char)ch); - } - - String json = builder.toString(); - - JsonObject s = gson.fromJson(json, JsonObject.class); - - if (s.has("success") && s.get("success").getAsBoolean()) { - s = s.get("data").getAsJsonObject(); - - return Optional.ofNullable(gson.fromJson(s, MinecraftTexturesPayload.class)); - } - } catch (IOException e) { - logger.trace("Couldn't reach skin server for {} at {}", profile.getName(), url, e); - } finally { - if (urlConnection != null) { - urlConnection.disconnect(); - } - - IOUtils.closeQuietly(reader); + return Optional.ofNullable(gson.fromJson(s, MinecraftTexturesPayload.class)); } return Optional.empty(); @@ -103,55 +49,37 @@ public class BethlehemSkinServer implements SkinServer { @Override public CompletableFuture uploadSkin(Session session, URI image, Type type, Map metadata) { - - if (Strings.isNullOrEmpty(address)) { - return CallableFutures.failedFuture(new NullPointerException("gateway url is blank")); - } - return CallableFutures.asyncFailableFuture(() -> { - verifyServerConnection(session, SERVER_ID); + SkinServer.verifyServerConnection(session, SERVER_ID); - Map data = image == null ? getClearData(session, type) : getUploadData(session, type, metadata.getOrDefault("mode", "default"), image); + NetClient client = new NetClient("POST", address).putHeaders(createHeaders(session, type, image, metadata)); - ThreadMultipartPostUpload upload = new ThreadMultipartPostUpload(address, data); + if (image != null) { + client.putFile(type.toString().toLowerCase(Locale.US), "image/png", image); + } - String response = upload.uploadMultipart(); - - return new SkinUploadResponse(response.equalsIgnoreCase("OK"), response); + return new SkinUploadResponse(client.send(), client.getResponseText()); }, HDSkinManager.skinUploadExecutor); } - protected static ImmutableMap.Builder getData(Session session, MinecraftProfileTexture.Type type) { - return ImmutableMap.builder() - .put("accessToken", session.getToken()) - .put("user", session.getUsername()) - .put("uuid", UUIDTypeAdapter.fromUUID(session.getProfile().getId())) - .put("type", type.toString().toLowerCase(Locale.US)); - } + protected Map createHeaders(Session session, Type type, URI image, Map metadata) { + Builder builder = ImmutableMap.builder() + .put("accessToken", session.getToken()) + .put("user", session.getUsername()) + .put("uuid", UUIDTypeAdapter.fromUUID(session.getProfile().getId())) + .put("type", type.toString().toLowerCase(Locale.US)); - protected static Map getClearData(Session session, MinecraftProfileTexture.Type type) { - return getData(session, type) - .put("clear", "1") - .build(); - } + if (image == null) { + builder.put("clear", "1"); + } else { + builder.put("model", metadata.getOrDefault("mode", "default")); + } - protected static Map getUploadData(Session session, MinecraftProfileTexture.Type type, String model, URI skinFile) { - return getData(session, type) - .put("model", model) - .put(type.toString().toLowerCase(Locale.US), skinFile) - .build(); + return builder.build(); } private String getPath(GameProfile profile) { - - String uuid = UUIDTypeAdapter.fromUUID(profile.getId()); - - return String.format("%s/profile/%s", address, uuid); - } - - protected static void verifyServerConnection(Session session, String serverId) throws AuthenticationException { - MinecraftSessionService service = Minecraft.getMinecraft().getSessionService(); - service.joinServer(session.getProfile(), session.getToken(), serverId); + return String.format("%s/profile/%s", address, UUIDTypeAdapter.fromUUID(profile.getId())); } @Override diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java index 887aa096..80c22d5c 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java @@ -4,14 +4,11 @@ import com.google.common.base.Strings; import com.google.common.collect.ImmutableMap; import com.google.gson.annotations.Expose; import com.mojang.authlib.GameProfile; -import com.mojang.authlib.exceptions.AuthenticationException; import com.mojang.authlib.minecraft.MinecraftProfileTexture; -import com.mojang.authlib.minecraft.MinecraftSessionService; import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload; import com.mojang.util.UUIDTypeAdapter; import com.voxelmodpack.hdskins.HDSkinManager; import com.voxelmodpack.hdskins.upload.ThreadMultipartPostUpload; -import net.minecraft.client.Minecraft; import net.minecraft.util.Session; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.logging.log4j.LogManager; @@ -100,7 +97,7 @@ public class LegacySkinServer implements SkinServer { } return CallableFutures.asyncFailableFuture(() -> { - verifyServerConnection(session, SERVER_ID); + SkinServer.verifyServerConnection(session, SERVER_ID); String model = metadata.getOrDefault("model", "default"); Map data = image == null ? getClearData(session, type) : getUploadData(session, type, model, image); ThreadMultipartPostUpload upload = new ThreadMultipartPostUpload(this.gateway, data); @@ -136,11 +133,6 @@ public class LegacySkinServer implements SkinServer { return String.format("%s/%s/%s.png", address, path, uuid); } - private static void verifyServerConnection(Session session, String serverId) throws AuthenticationException { - MinecraftSessionService service = Minecraft.getMinecraft().getSessionService(); - service.joinServer(session.getProfile(), session.getToken(), serverId); - } - @Override public String toString() { return new ToStringBuilder(this, IndentedToStringStyle.INSTANCE) diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/NetClient.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/NetClient.java new file mode 100644 index 00000000..0e91c50d --- /dev/null +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/NetClient.java @@ -0,0 +1,102 @@ +package com.voxelmodpack.hdskins.skins; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URI; +import java.util.Map; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.mime.MultipartEntityBuilder; +import org.apache.http.impl.client.HttpClients; + +/** + * Ew. Why so many builders? >.< + */ +public class NetClient { + + private final RequestBuilder rqBuilder; + + private Map headers; + + private CloseableHttpResponse response = null; + + public NetClient(String method, String uri) { + rqBuilder = RequestBuilder.create(method).setUri(uri); + } + + public NetClient putFile(String key, String contentType, URI file) { + File f = new File(file); + HttpEntity entity = MultipartEntityBuilder.create().addBinaryBody(key, f, ContentType.create(contentType), f.getName()).build(); + + rqBuilder.setEntity(entity); + + return this; + } + + public NetClient putHeaders(Map headers) { + this.headers = headers; + + return this; + } + + public boolean send() { + HttpUriRequest request = rqBuilder.build(); + + for (Map.Entry parameter : headers.entrySet()) { + request.addHeader(parameter.getKey(), parameter.getValue().toString()); + } + + try { + response = HttpClients.createSystem().execute(request); + + return getResponseCode() == HttpStatus.SC_OK; + } catch (IOException e) { } + + return false; + } + + public int getResponseCode() { + if (response == null) { + send(); + } + + return response.getStatusLine().getStatusCode(); + } + + public String getResponseText() { + if (response == null) { + if (!send()) { + return ""; + } + } + + BufferedReader reader = null; + + try { + reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); + + StringBuilder builder = new StringBuilder(); + + int ch; + while ((ch = reader.read()) != -1) { + builder.append((char)ch); + } + + return builder.toString(); + } catch (IOException e) { + + } finally { + IOUtils.closeQuietly(reader); + } + + return ""; + } +} diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/SkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/SkinServer.java index c787cb42..dce9d855 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/skins/SkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/SkinServer.java @@ -4,11 +4,14 @@ import com.google.common.collect.Lists; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.mojang.authlib.GameProfile; +import com.mojang.authlib.exceptions.AuthenticationException; import com.mojang.authlib.minecraft.MinecraftProfileTexture; +import com.mojang.authlib.minecraft.MinecraftSessionService; import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload; import com.mojang.util.UUIDTypeAdapter; import com.mumfrey.liteloader.modconfig.Exposable; +import net.minecraft.client.Minecraft; import net.minecraft.util.Session; import java.net.URI; @@ -39,4 +42,9 @@ public interface SkinServer extends Exposable { CompletableFuture uploadSkin(Session session, @Nullable URI image, MinecraftProfileTexture.Type type, Map metadata); + + public static void verifyServerConnection(Session session, String serverId) throws AuthenticationException { + MinecraftSessionService service = Minecraft.getMinecraft().getSessionService(); + service.joinServer(session.getProfile(), session.getToken(), serverId); + } } diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/ValhallaSkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/ValhallaSkinServer.java index 96f0c2c1..81637d1e 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/skins/ValhallaSkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/ValhallaSkinServer.java @@ -45,7 +45,7 @@ public class ValhallaSkinServer implements SkinServer { @Expose private final String address; - private String accessToken; + private transient String accessToken; public ValhallaSkinServer(String address) { this.address = address; @@ -68,8 +68,7 @@ public class ValhallaSkinServer implements SkinServer { } @Override - public CompletableFuture uploadSkin(Session session, @Nullable URI image, - MinecraftProfileTexture.Type type, Map metadata) { + public CompletableFuture uploadSkin(Session session, @Nullable URI image, MinecraftProfileTexture.Type type, Map metadata) { return CallableFutures.asyncFailableFuture(() -> { try (CloseableHttpClient client = HttpClients.createSystem()) { authorize(client, session); @@ -99,8 +98,7 @@ public class ValhallaSkinServer implements SkinServer { .build()); } - private SkinUploadResponse uploadFile(CloseableHttpClient client, File file, GameProfile profile, MinecraftProfileTexture.Type type, - Map metadata) throws IOException { + private SkinUploadResponse uploadFile(CloseableHttpClient client, File file, GameProfile profile, MinecraftProfileTexture.Type type, Map metadata) throws IOException { MultipartEntityBuilder b = MultipartEntityBuilder.create(); b.addBinaryBody("file", file, ContentType.create("image/png"), file.getName()); metadata.forEach(b::addTextBody); @@ -112,8 +110,7 @@ public class ValhallaSkinServer implements SkinServer { .build()); } - private SkinUploadResponse uploadUrl(CloseableHttpClient client, URI uri, GameProfile profile, MinecraftProfileTexture.Type type, - Map metadata) throws IOException { + private SkinUploadResponse uploadUrl(CloseableHttpClient client, URI uri, GameProfile profile, MinecraftProfileTexture.Type type, Map metadata) throws IOException { return upload(client, RequestBuilder.post() .setUri(buildUserTextureUri(profile, type))