1
0
mirror of https://github.com/Suiranoil/SkinRestorer.git synced 2026-01-16 04:42:12 +00:00

update WebUtils to use HttpClient

This commit is contained in:
2024-06-29 21:52:33 +03:00
parent 799ec9d52e
commit bed53909a8
3 changed files with 126 additions and 50 deletions

View File

@@ -2,24 +2,25 @@ package net.lionarius.skinrestorer.skin.provider;
import com.google.gson.JsonObject;
import com.mojang.authlib.properties.Property;
import com.mojang.datafixers.util.Either;
import net.lionarius.skinrestorer.skin.SkinVariant;
import net.lionarius.skinrestorer.util.JsonUtils;
import net.lionarius.skinrestorer.util.PlayerUtils;
import net.lionarius.skinrestorer.util.Result;
import net.lionarius.skinrestorer.util.WebUtils;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpRequest;
import java.util.Optional;
public final class MineskinSkinProvider implements SkinProvider {
private static final URI API_URL;
private static final URI API_URI;
static {
try {
API_URL = new URI("https://api.mineskin.org/generate/url");
API_URI = new URI("https://api.mineskin.org/");
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
@@ -38,15 +39,31 @@ public final class MineskinSkinProvider implements SkinProvider {
@Override
public Result<Optional<Property>, Exception> getSkin(String url, SkinVariant variant) {
try {
String body = ("{\"variant\":\"%s\",\"name\":\"%s\",\"visibility\":%d,\"url\":\"%s\"}")
.formatted(variant.toString(), "none", 1, url);
JsonObject texture = JsonUtils.parseJson(WebUtils.postRequest(API_URL.toURL(), "application/json", body))
.getAsJsonObject("data").getAsJsonObject("texture");
var result = MineskinSkinProvider.uploadToMineskin(url, variant);
var texture = result.getAsJsonObject("data").getAsJsonObject("texture");
return Result.ofNullable(new Property(PlayerUtils.TEXTURES_KEY, texture.get("value").getAsString(), texture.get("signature").getAsString()));
} catch (Exception e) {
return Result.error(e);
}
}
private static JsonObject uploadToMineskin(String url, SkinVariant variant) throws IOException {
var body = ("{\"variant\":\"%s\",\"name\":\"%s\",\"visibility\":%d,\"url\":\"%s\"}")
.formatted(variant.toString(), "none", 0, url);
var request = HttpRequest.newBuilder()
.uri(MineskinSkinProvider.API_URI.resolve("generate/url"))
.POST(HttpRequest.BodyPublishers.ofString(body))
.header("Content-Type", "application/json")
.build();
var response = WebUtils.executeRequest(request);
WebUtils.throwOnClientErrors(response);
if (response.statusCode() != 200)
throw new IllegalArgumentException("could not get mineskin skin");
return JsonUtils.parseJson(response.body());
}
}

View File

@@ -11,18 +11,18 @@ import net.lionarius.skinrestorer.util.WebUtils;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpRequest;
import java.util.Optional;
import java.util.UUID;
public final class MojangSkinProvider implements SkinProvider {
private static final URI API_URL;
private static final URI SESSION_SERVER_URL;
private static final URI API_URI;
private static final URI SESSION_SERVER_URI;
static {
try {
API_URL = new URI("https://api.mojang.com/users/profiles/minecraft/");
SESSION_SERVER_URL = new URI("https://sessionserver.mojang.com/session/minecraft/profile/");
API_URI = new URI("https://api.mojang.com/");
SESSION_SERVER_URI = new URI("https://sessionserver.mojang.com/");
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
@@ -42,9 +42,10 @@ public final class MojangSkinProvider implements SkinProvider {
@Override
public Result<Optional<Property>, Exception> getSkin(String username, SkinVariant variant) {
try {
UUID uuid = getUUID(username);
JsonObject texture = JsonUtils.parseJson(WebUtils.getRequest(SESSION_SERVER_URL.resolve(uuid + "?unsigned=false").toURL()))
.getAsJsonArray("properties").get(0).getAsJsonObject();
var uuid = MojangSkinProvider.getUuid(username);
var profile = MojangSkinProvider.getMojangProfile(uuid);
var texture = profile.getAsJsonArray("properties").get(0).getAsJsonObject();
return Result.ofNullable(new Property(PlayerUtils.TEXTURES_KEY, texture.get("value").getAsString(), texture.get("signature").getAsString()));
} catch (Exception e) {
@@ -52,8 +53,43 @@ public final class MojangSkinProvider implements SkinProvider {
}
}
private static UUID getUUID(String name) throws IOException {
return UUID.fromString(JsonUtils.parseJson(WebUtils.getRequest(API_URL.resolve(name).toURL())).get("id").getAsString()
.replaceFirst("(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)", "$1-$2-$3-$4-$5"));
private static String getUuid(final String name) throws IOException {
var request = HttpRequest.newBuilder()
.uri(MojangSkinProvider.API_URI
.resolve("users/profiles/minecraft/")
.resolve(name)
)
.GET()
.build();
var response = WebUtils.executeRequest(request);
WebUtils.throwOnClientErrors(response);
if (response.statusCode() != 200)
throw new IllegalArgumentException("no profile with name " + name);
var profile = JsonUtils.parseJson(response.body());
if (profile == null)
return null;
return profile.get("id").getAsString();
}
private static JsonObject getMojangProfile(final String uuid) throws IOException {
var request = HttpRequest.newBuilder()
.uri(MojangSkinProvider.SESSION_SERVER_URI
.resolve("session/minecraft/profile/")
.resolve(uuid + "?unsigned=false")
)
.GET()
.build();
var response = WebUtils.executeRequest(request);
WebUtils.throwOnClientErrors(response);
if (response.statusCode() != 200)
throw new IllegalArgumentException("no profile with uuid " + uuid);
return JsonUtils.parseJson(response.body());
}
}

View File

@@ -1,46 +1,69 @@
package net.lionarius.skinrestorer.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.Date;
public final class WebUtils {
private WebUtils() {}
public static final String USER_AGENT = "SkinRestorer";
public static final String USER_AGENT;
public static String postRequest(URL url, String contentType, String body)
throws IOException {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", contentType);
connection.setRequestProperty("User-Agent", WebUtils.USER_AGENT);
connection.setDoOutput(true);
connection.setDoInput(true);
try (OutputStream os = connection.getOutputStream()) {
os.write(body.getBytes(StandardCharsets.UTF_8), 0, body.length());
}
try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
return StringUtils.readString(br);
static {
var date = new Date();
USER_AGENT = String.format("SkinRestorer/%d", date.getTime() % 65535);
}
private static final HttpClient HTTP_CLIENT = HttpClient.newBuilder().build();
public static HttpResponse<String> executeRequest(HttpRequest request) throws IOException {
try {
var modifiedRequest = HttpRequest.newBuilder(request, (name, value) -> true)
.header("User-Agent", WebUtils.USER_AGENT)
.build();
final var response = WebUtils.HTTP_CLIENT.send(modifiedRequest, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() >= 500)
throw new IOException("server error " + response.statusCode());
return response;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException(e);
}
}
public static String getRequest(URL url) throws IOException {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
return StringUtils.readString(br);
public static void throwOnClientErrors(HttpResponse<?> response) {
String message = null;
switch (response.statusCode()) {
case 400:
message = "bad request";
break;
case 401:
message = "unauthorized";
break;
case 403:
message = "forbidden";
break;
case 404:
message = "not found";
break;
case 405:
message = "method not allowed";
break;
case 408:
message = "request timeout";
break;
case 429:
message = "too many requests";
break;
}
if (message != null)
throw new IllegalStateException(message);
}
}