Newer
Older
KeeperJerry_Launcher / LaunchServer / source / auth / provider / AuthlibAuthProvider.java
@KeeperJerry KeeperJerry on 1 May 2021 4 KB HotFix для Authlib
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 URL URL;
    private static String authUrl;

    // TODO:
    //  https://wiki.vg/Authentication#Refresh
    //  https://wiki.vg/Authentication#Signout

    AuthlibAuthProvider(BlockConfigEntry block)
    {
        super(block);
        authUrl = block.getEntryValue("authUrl", StringConfigEntry.class);

        try
        {
            // Docs: https://wiki.vg/Authentication#Authenticate
            URL = new URL(authUrl); // "https://authserver.mojang.com/authenticate"
        }
        catch (MalformedURLException e)
        {
            throw new InternalError(e);
        }
    }

    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 Authlib 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
    }
}