Patch legacy versions to respect -Dminecraft.api.*.host

This commit is contained in:
Evan Goode 2024-08-17 17:10:18 -04:00
parent a716d40e21
commit ba792d4bdd
4 changed files with 107 additions and 16 deletions

View File

@ -28,6 +28,7 @@ set(LEGACY_SRC
legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java legacy/org/prismlauncher/legacy/fix/online/OnlineModeFix.java
legacy/org/prismlauncher/legacy/fix/online/SkinFix.java legacy/org/prismlauncher/legacy/fix/online/SkinFix.java
legacy/org/prismlauncher/legacy/utils/Base64.java legacy/org/prismlauncher/legacy/utils/Base64.java
legacy/org/prismlauncher/legacy/utils/api/ApiServers.java
legacy/org/prismlauncher/legacy/utils/api/MojangApi.java legacy/org/prismlauncher/legacy/utils/api/MojangApi.java
legacy/org/prismlauncher/legacy/utils/api/Texture.java legacy/org/prismlauncher/legacy/utils/api/Texture.java
legacy/org/prismlauncher/legacy/utils/json/JsonParseException.java legacy/org/prismlauncher/legacy/utils/json/JsonParseException.java

View File

@ -35,32 +35,80 @@
package org.prismlauncher.legacy.fix.online; package org.prismlauncher.legacy.fix.online;
import org.prismlauncher.legacy.utils.api.ApiServers;
import org.prismlauncher.legacy.utils.api.MojangApi;
import org.prismlauncher.legacy.utils.url.ByteArrayUrlConnection;
import org.prismlauncher.legacy.utils.url.UrlUtils; import org.prismlauncher.legacy.utils.url.UrlUtils;
import java.io.IOException; import java.io.IOException;
import java.net.MalformedURLException; import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.Proxy; import java.net.Proxy;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
public final class OnlineModeFix { public final class OnlineModeFix {
public static URLConnection openConnection(URL address, Proxy proxy) throws IOException { public static URLConnection openConnection(URL address, Proxy proxy) throws IOException {
// we start with "http://www.minecraft.net/game/joinserver.jsp?user=..." // we start with "http://www.minecraft.net/game/joinserver.jsp?user=..."
if (!(address.getHost().equals("www.minecraft.net") && address.getPath().equals("/game/joinserver.jsp"))) if (!(address.getHost().equals("www.minecraft.net") && address.getPath().equals("/game/joinserver.jsp"))) {
return null; return null;
// change it to "https://session.minecraft.net/game/joinserver.jsp?user=..."
// this seems to be the modern version of the same endpoint...
// maybe Mojang planned to patch old versions of the game to use it
// if it ever disappears this should be changed to use sessionserver.mojang.com/session/minecraft/join
// which of course has a different usage requiring JSON serialisation...
URL url;
try {
url = new URL("https", "session.minecraft.net", address.getPort(), address.getFile());
} catch (MalformedURLException e) {
throw new AssertionError("url should be valid", e);
} }
return UrlUtils.openConnection(url, proxy); Map<String, String> params = new HashMap<>();
String query = address.getQuery();
String[] entries = query.split("&");
for (String entry : entries) {
String[] pair = entry.split("=");
if (pair.length == 2) {
params.put(pair[0], pair[1]);
}
}
String user = params.get("user");
if (user == null) {
throw new AssertionError("missing user");
}
String serverId = params.get("serverId");
if (serverId == null) {
throw new AssertionError("missing serverId");
}
String sessionId = params.get("sessionId");
if (sessionId == null) {
throw new AssertionError("missing sessionId");
}
// sessionId hashas the form:
// token:<accessToken>:<player UUID>
String accessToken = sessionId.split(":")[1];
String uuid = null;
uuid = MojangApi.getUuid(user);
if (uuid == null) {
return new ByteArrayUrlConnection(("Couldn't find UUID of " + user).getBytes("utf-8"));
}
URL url = new URL(ApiServers.getSessionURL() + "/session/minecraft/join");
HttpURLConnection connection = (HttpURLConnection) UrlUtils.openConnection(url, proxy);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Accept", "application/json");
try (OutputStream os = connection.getOutputStream()) {
String payload = "{"
+ "\"accessToken\": \"" + accessToken + "\","
+ "\"selectedProfile\": \"" + uuid + "\","
+ "\"serverId\": \"" + serverId + "\""
+ "}";
os.write(payload.getBytes("utf-8"));
}
int responseCode = connection.getResponseCode();
if (responseCode == 204) {
return new ByteArrayUrlConnection("OK".getBytes("utf-8"));
} else {
return new ByteArrayUrlConnection("Bad login".getBytes("utf-8"));
}
} }
} }

View File

@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Fjord Launcher - Minecraft Launcher
* Copyright (C) 2024 Evan Goode <mail@evangoo.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.prismlauncher.legacy.utils.api;
public class ApiServers {
public static String getAuthURL() {
return getPropertyWithFallback("minecraft.api.auth.host", "https://authserver.mojang.com");
}
public static String getAccountURL() {
return getPropertyWithFallback("minecraft.api.account.host", "https://api.mojang.com");
}
public static String getSessionURL() {
return getPropertyWithFallback("minecraft.api.session.host", "https://sessionserver.mojang.com");
}
public static String getServicesURL() {
return getPropertyWithFallback("minecraft.api.services.host", "https://api.minecraftservices.com");
}
private static String getPropertyWithFallback(String key, String fallback) {
String value = System.getProperty(key);
if (value == null) {
return fallback;
}
return value;
}
}

View File

@ -36,6 +36,7 @@
package org.prismlauncher.legacy.utils.api; package org.prismlauncher.legacy.utils.api;
import org.prismlauncher.legacy.utils.Base64; import org.prismlauncher.legacy.utils.Base64;
import org.prismlauncher.legacy.utils.api.ApiServers;
import org.prismlauncher.legacy.utils.json.JsonParser; import org.prismlauncher.legacy.utils.json.JsonParser;
import java.io.IOException; import java.io.IOException;
@ -49,7 +50,7 @@ import java.util.Map;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final class MojangApi { public final class MojangApi {
public static String getUuid(String username) throws IOException { public static String getUuid(String username) throws IOException {
try (InputStream in = new URL("https://api.mojang.com/users/profiles/minecraft/" + username).openStream()) { try (InputStream in = new URL(ApiServers.getAccountURL() + "/users/profiles/minecraft/" + username).openStream()) {
Map<String, Object> map = (Map<String, Object>) JsonParser.parse(in); Map<String, Object> map = (Map<String, Object>) JsonParser.parse(in);
return (String) map.get("id"); return (String) map.get("id");
} }
@ -79,7 +80,7 @@ public final class MojangApi {
} }
public static Map<String, Object> getTextures(String player) throws IOException { public static Map<String, Object> getTextures(String player) throws IOException {
try (InputStream profileIn = new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + player).openStream()) { try (InputStream profileIn = new URL(ApiServers.getSessionURL() + "/session/minecraft/profile/" + player).openStream()) {
Map<String, Object> profile = (Map<String, Object>) JsonParser.parse(profileIn); Map<String, Object> profile = (Map<String, Object>) JsonParser.parse(profileIn);
for (Map<String, Object> property : (Iterable<Map<String, Object>>) profile.get("properties")) { for (Map<String, Object> property : (Iterable<Map<String, Object>>) profile.get("properties")) {