package org.saturnclient.client; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; import java.util.UUID; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; /** * Mojang's session server "join" call, the same one vanilla makes when joining * an online-mode server. The access token is only ever sent to Mojang; the * Saturn server then confirms the join with {@code hasJoined}. */ public final class MojangSession { private static final URI JOIN_URI = URI.create("https://sessionserver.mojang.com/session/minecraft/join"); private static final ObjectMapper MAPPER = new ObjectMapper(); public enum JoinResult { JOINED, /** Mojang refused the access token; retrying won't help. */ REJECTED, /** Network or server error; worth retrying. */ FAILED } private MojangSession() { } public static JoinResult join(HttpClient http, String accessToken, UUID profile, String serverId) { ObjectNode body = MAPPER.createObjectNode() .put("accessToken", accessToken) .put("selectedProfile", profile.toString().replace("-", "")) .put("serverId", serverId); HttpRequest request = HttpRequest.newBuilder(JOIN_URI) .timeout(Duration.ofSeconds(10)) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(body.toString())) .build(); try { int status = http.send(request, HttpResponse.BodyHandlers.discarding()).statusCode(); if (status == 204 || status == 200) { return JoinResult.JOINED; } return status == 401 || status == 403 ? JoinResult.REJECTED : JoinResult.FAILED; } catch (InterruptedException e) { Thread.currentThread().interrupt(); return JoinResult.FAILED; } catch (Exception e) { return JoinResult.FAILED; } } }