package launchserver.auth.provider; import com.eclipsesource.json.Json; import com.eclipsesource.json.JsonObject; import com.eclipsesource.json.JsonValue; import com.eclipsesource.json.WriterConfig; import launcher.helper.IOHelper; import launcher.helper.LogHelper; import launcher.serialize.config.entry.BlockConfigEntry; import launcher.serialize.config.entry.StringConfigEntry; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.UUID; import java.util.regex.Pattern; public class AuthlibAuthProvider extends AuthProvider { private static final Pattern UUID_REGEX = Pattern.compile("(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})"); private static final java.net.URL URL; private static String authUrl; // TODO: // https://wiki.vg/Authentication#Refresh // https://wiki.vg/Authentication#Signout static { try { // Docs: https://wiki.vg/Authentication#Authenticate URL = new URL(authUrl); // "https://authserver.mojang.com/authenticate" } catch (MalformedURLException e) { throw new InternalError(e); } } AuthlibAuthProvider(BlockConfigEntry block) { super(block); authUrl = block.getEntryValue("authUrl", StringConfigEntry.class); } public static JsonObject makeAuthlibRequest(URL url, JsonObject request) throws IOException { HttpURLConnection connection = request == null ? (HttpURLConnection) IOHelper.newConnection(url) : IOHelper.newConnectionPost(url); // Make request if (request != null) { connection.setRequestProperty("Content-Type", "application/json"); try (OutputStream output = connection.getOutputStream()) { output.write(request.toString(WriterConfig.MINIMAL).getBytes(StandardCharsets.UTF_8)); } } connection.getResponseCode(); // Actually make request // Read response InputStream errorInput = connection.getErrorStream(); try (InputStream input = errorInput == null ? connection.getInputStream() : errorInput) { String charset = connection.getContentEncoding(); Charset charsetObject = charset == null ? IOHelper.UNICODE_CHARSET : Charset.forName(charset); // Parse response String json = new String(IOHelper.read(input), charsetObject); LogHelper.subDebug("Raw Mojang response: '" + json + '\''); return json.isEmpty() ? null : Json.parse(json).asObject(); } } @Override public AuthProviderResult auth(String login, String password, String ip) throws Throwable { JsonObject request = Json.object(). add("agent", Json.object().add("name", "Minecraft").add("version", 1)). add("username", login).add("password", password); // Verify there's no error JsonObject response = makeAuthlibRequest(URL, request); if (response == null) { authError("Empty authlib response"); } JsonValue errorMessage = response.get("errorMessage"); if (errorMessage != null) { authError(errorMessage.asString()); } // Parse JSON data JsonObject selectedProfile = response.get("selectedProfile").asObject(); String username = selectedProfile.get("name").asString(); String accessToken = response.get("clientToken").asString(); UUID uuid = UUID.fromString(UUID_REGEX.matcher(selectedProfile.get("id").asString()).replaceFirst("$1-$2-$3-$4-$5")); String launcherToken = response.get("accessToken").asString(); // We're done return new AuthlibAuthProviderResult(username, accessToken, uuid, launcherToken); } @Override public void close() { // Do nothing } }