mirror of
https://github.com/GeyserMC/Geyser.git
synced 2025-12-19 14:59:27 +00:00
Updated to MinecraftAuth 5 (#5989)
This commit is contained in:
@@ -38,6 +38,8 @@ import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.raphimc.minecraftauth.msa.data.MsaConstants;
|
||||
import net.raphimc.minecraftauth.msa.model.MsaApplicationConfig;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
@@ -145,9 +147,9 @@ public class GeyserImpl implements GeyserApi, EventRegistrar {
|
||||
public static final boolean IS_DEV = BuildData.isDevBuild();
|
||||
|
||||
/**
|
||||
* Oauth client ID for Microsoft authentication
|
||||
* Oauth config for Microsoft authentication
|
||||
*/
|
||||
public static final String OAUTH_CLIENT_ID = "204cefd1-4818-4de1-b98d-513fae875d88";
|
||||
public static final MsaApplicationConfig OAUTH_CONFIG = new MsaApplicationConfig("204cefd1-4818-4de1-b98d-513fae875d88", MsaConstants.SCOPE_OFFLINE_ACCESS);
|
||||
|
||||
private static final Pattern IP_REGEX = Pattern.compile("\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b");
|
||||
|
||||
|
||||
@@ -41,10 +41,11 @@ import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.raphimc.minecraftauth.responsehandler.exception.MinecraftRequestException;
|
||||
import net.raphimc.minecraftauth.step.java.StepMCProfile;
|
||||
import net.raphimc.minecraftauth.step.java.StepMCToken;
|
||||
import net.raphimc.minecraftauth.step.java.session.StepFullJavaSession;
|
||||
import net.raphimc.minecraftauth.java.JavaAuthManager;
|
||||
import net.raphimc.minecraftauth.java.exception.MinecraftProfileNotFoundException;
|
||||
import net.raphimc.minecraftauth.java.model.MinecraftProfile;
|
||||
import net.raphimc.minecraftauth.java.model.MinecraftToken;
|
||||
import net.raphimc.minecraftauth.util.MinecraftAuth4To5Migrator;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.checkerframework.checker.index.qual.Positive;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
@@ -113,7 +114,6 @@ import org.geysermc.cumulus.form.util.FormBuilder;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.api.bedrock.camera.CameraData;
|
||||
import org.geysermc.geyser.api.bedrock.camera.CameraShake;
|
||||
import org.geysermc.geyser.input.InputLocksFlag;
|
||||
import org.geysermc.geyser.api.connection.GeyserConnection;
|
||||
import org.geysermc.geyser.api.entity.EntityData;
|
||||
import org.geysermc.geyser.api.entity.type.GeyserEntity;
|
||||
@@ -143,6 +143,7 @@ import org.geysermc.geyser.erosion.GeyserboundHandshakePacketHandler;
|
||||
import org.geysermc.geyser.event.type.SessionDisconnectEventImpl;
|
||||
import org.geysermc.geyser.impl.camera.CameraDefinitions;
|
||||
import org.geysermc.geyser.impl.camera.GeyserCameraData;
|
||||
import org.geysermc.geyser.input.InputLocksFlag;
|
||||
import org.geysermc.geyser.inventory.Inventory;
|
||||
import org.geysermc.geyser.inventory.InventoryHolder;
|
||||
import org.geysermc.geyser.inventory.LecternContainer;
|
||||
@@ -196,7 +197,6 @@ import org.geysermc.geyser.util.EntityUtils;
|
||||
import org.geysermc.geyser.util.InventoryUtils;
|
||||
import org.geysermc.geyser.util.LoginEncryptionUtils;
|
||||
import org.geysermc.geyser.util.MathUtils;
|
||||
import org.geysermc.geyser.util.MinecraftAuthLogger;
|
||||
import org.geysermc.mcprotocollib.auth.GameProfile;
|
||||
import org.geysermc.mcprotocollib.network.BuiltinFlags;
|
||||
import org.geysermc.mcprotocollib.network.ClientSession;
|
||||
@@ -925,23 +925,28 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
loggingIn = true;
|
||||
|
||||
CompletableFuture.supplyAsync(() -> {
|
||||
StepFullJavaSession step = PendingMicrosoftAuthentication.AUTH_FLOW.apply(true, 30);
|
||||
StepFullJavaSession.FullJavaSession response;
|
||||
JavaAuthManager authManager;
|
||||
MinecraftProfile mcProfile;
|
||||
MinecraftToken mcToken;
|
||||
try {
|
||||
response = step.refresh(MinecraftAuthLogger.INSTANCE, PendingMicrosoftAuthentication.AUTH_CLIENT, step.fromJson(GSON.fromJson(authChain, JsonObject.class)));
|
||||
JsonObject parsedAuthChain = GSON.fromJson(authChain, JsonObject.class);
|
||||
if (parsedAuthChain.has("mcProfile")) { // Old Minecraft v4 auth chain
|
||||
parsedAuthChain = MinecraftAuth4To5Migrator.migrateJavaSave(parsedAuthChain, GeyserImpl.OAUTH_CONFIG);
|
||||
}
|
||||
|
||||
authManager = JavaAuthManager.fromJson(PendingMicrosoftAuthentication.AUTH_CLIENT, parsedAuthChain);
|
||||
mcProfile = authManager.getMinecraftProfile().getUpToDate();
|
||||
mcToken = authManager.getMinecraftToken().getUpToDate();
|
||||
} catch (Exception e) {
|
||||
geyser.getLogger().error("Error while attempting to use auth chain for " + bedrockUsername() + "!", e);
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
StepMCProfile.MCProfile mcProfile = response.getMcProfile();
|
||||
StepMCToken.MCToken mcToken = mcProfile.getMcToken();
|
||||
|
||||
protocol = new MinecraftProtocol(
|
||||
new GameProfile(mcProfile.getId(), mcProfile.getName()),
|
||||
mcToken.getAccessToken()
|
||||
mcToken.getToken()
|
||||
);
|
||||
geyser.saveAuthChain(bedrockUsername(), GSON.toJson(step.toJson(response)));
|
||||
geyser.saveAuthChain(bedrockUsername(), GSON.toJson(JavaAuthManager.toJson(authManager)));
|
||||
return Boolean.TRUE;
|
||||
}).whenComplete((successful, ex) -> {
|
||||
if (this.closed) {
|
||||
@@ -1009,9 +1014,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
return task.getAuthentication().handle((result, ex) -> {
|
||||
if (ex != null) {
|
||||
geyser.getLogger().error("Failed to log in with Microsoft code!", ex);
|
||||
if (ex instanceof CompletionException ce
|
||||
&& ce.getCause() instanceof MinecraftRequestException mre
|
||||
&& mre.getResponse().getStatusCode() == 404) {
|
||||
if (ex instanceof CompletionException ce && ce.getCause() instanceof MinecraftProfileNotFoundException) {
|
||||
// Player is trying to join with a Microsoft account that doesn't have Java Edition purchased
|
||||
disconnect(GeyserLocale.getPlayerLocaleString("geyser.network.remote.invalid_account", locale()));
|
||||
} else {
|
||||
@@ -1020,12 +1023,12 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
return false;
|
||||
}
|
||||
|
||||
StepMCProfile.MCProfile mcProfile = result.session().getMcProfile();
|
||||
StepMCToken.MCToken mcToken = mcProfile.getMcToken();
|
||||
MinecraftProfile mcProfile = result.getMinecraftProfile().getCached();
|
||||
MinecraftToken mcToken = result.getMinecraftToken().getCached();
|
||||
|
||||
this.protocol = new MinecraftProtocol(
|
||||
new GameProfile(mcProfile.getId(), mcProfile.getName()),
|
||||
mcToken.getAccessToken()
|
||||
mcToken.getToken()
|
||||
);
|
||||
|
||||
try {
|
||||
@@ -1036,7 +1039,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
||||
}
|
||||
|
||||
// Save our auth chain for later use
|
||||
geyser.saveAuthChain(bedrockUsername(), GSON.toJson(result.step().toJson(result.session())));
|
||||
geyser.saveAuthChain(bedrockUsername(), GSON.toJson(JavaAuthManager.toJson(result)));
|
||||
return true;
|
||||
}).getNow(false);
|
||||
}
|
||||
|
||||
@@ -33,20 +33,21 @@ import lombok.Setter;
|
||||
import lombok.SneakyThrows;
|
||||
import net.lenni0451.commons.httpclient.HttpClient;
|
||||
import net.raphimc.minecraftauth.MinecraftAuth;
|
||||
import net.raphimc.minecraftauth.step.java.session.StepFullJavaSession;
|
||||
import net.raphimc.minecraftauth.step.msa.StepMsaDeviceCode;
|
||||
import net.raphimc.minecraftauth.util.MicrosoftConstants;
|
||||
import net.raphimc.minecraftauth.java.JavaAuthManager;
|
||||
import net.raphimc.minecraftauth.msa.data.MsaConstants;
|
||||
import net.raphimc.minecraftauth.msa.model.MsaApplicationConfig;
|
||||
import net.raphimc.minecraftauth.msa.model.MsaDeviceCode;
|
||||
import net.raphimc.minecraftauth.msa.model.MsaToken;
|
||||
import net.raphimc.minecraftauth.msa.service.impl.DeviceCodeMsaAuthService;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
import org.geysermc.geyser.util.MinecraftAuthLogger;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
@@ -55,14 +56,6 @@ import java.util.function.Consumer;
|
||||
*/
|
||||
public class PendingMicrosoftAuthentication {
|
||||
public static final HttpClient AUTH_CLIENT = MinecraftAuth.createHttpClient();
|
||||
public static final BiFunction<Boolean, Integer, StepFullJavaSession> AUTH_FLOW = (offlineAccess, timeoutSec) -> MinecraftAuth.builder()
|
||||
.withClientId(GeyserImpl.OAUTH_CLIENT_ID)
|
||||
.withScope(offlineAccess ? "XboxLive.signin XboxLive.offline_access" : "XboxLive.signin")
|
||||
.withTimeout(timeoutSec)
|
||||
.deviceCode()
|
||||
.withoutDeviceToken()
|
||||
.regularAuthentication(MicrosoftConstants.JAVA_XSTS_RELYING_PARTY)
|
||||
.buildMinecraftJavaProfileStep(false);
|
||||
/**
|
||||
* For GeyserConnect usage.
|
||||
*/
|
||||
@@ -100,7 +93,7 @@ public class PendingMicrosoftAuthentication {
|
||||
private final String userKey;
|
||||
private final int timeoutSec;
|
||||
@Getter
|
||||
private CompletableFuture<StepChainResult> authentication;
|
||||
private CompletableFuture<JavaAuthManager> authentication;
|
||||
|
||||
private AuthenticationTask(String userKey, int timeoutSec) {
|
||||
this.userKey = userKey;
|
||||
@@ -124,11 +117,16 @@ public class PendingMicrosoftAuthentication {
|
||||
authentications.invalidate(userKey);
|
||||
}
|
||||
|
||||
public CompletableFuture<StepChainResult> performLoginAttempt(boolean offlineAccess, Consumer<StepMsaDeviceCode.MsaDeviceCode> deviceCodeConsumer) {
|
||||
public CompletableFuture<JavaAuthManager> performLoginAttempt(boolean offlineAccess, Consumer<MsaDeviceCode> deviceCodeConsumer) {
|
||||
MsaApplicationConfig applicationConfig = GeyserImpl.OAUTH_CONFIG.withScope(offlineAccess ? MsaConstants.SCOPE_OFFLINE_ACCESS : MsaConstants.SCOPE_NO_OFFLINE_ACCESS);
|
||||
DeviceCodeMsaAuthService authService = new DeviceCodeMsaAuthService(AUTH_CLIENT, applicationConfig, deviceCodeConsumer, timeoutSec * 1000);
|
||||
return authentication = CompletableFuture.supplyAsync(() -> {
|
||||
try {
|
||||
StepFullJavaSession step = AUTH_FLOW.apply(offlineAccess, timeoutSec);
|
||||
return new StepChainResult(step, step.getFromInput(MinecraftAuthLogger.INSTANCE, AUTH_CLIENT, new StepMsaDeviceCode.MsaDeviceCodeCallback(deviceCodeConsumer)));
|
||||
MsaToken msaToken = authService.acquireToken();
|
||||
JavaAuthManager authManager = JavaAuthManager.create(AUTH_CLIENT).msaApplicationConfig(applicationConfig).login(msaToken);
|
||||
authManager.getMinecraftToken().refresh(); // Preload the Minecraft token
|
||||
authManager.getMinecraftProfile().refresh(); // Preload the Minecraft profile
|
||||
return authManager;
|
||||
} catch (Exception e) {
|
||||
throw new CompletionException(e);
|
||||
}
|
||||
@@ -154,7 +152,4 @@ public class PendingMicrosoftAuthentication {
|
||||
super(userKey, timeoutSec);
|
||||
}
|
||||
}
|
||||
|
||||
public record StepChainResult(StepFullJavaSession step, StepFullJavaSession.FullJavaSession session) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ package org.geysermc.geyser.util;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import net.raphimc.minecraftauth.step.msa.StepMsaDeviceCode;
|
||||
import net.raphimc.minecraftauth.msa.model.MsaDeviceCode;
|
||||
import org.cloudburstmc.protocol.bedrock.data.auth.AuthPayload;
|
||||
import org.cloudburstmc.protocol.bedrock.data.auth.CertificateChainPayload;
|
||||
import org.cloudburstmc.protocol.bedrock.data.auth.TokenPayload;
|
||||
@@ -215,7 +215,7 @@ public class LoginEncryptionUtils {
|
||||
/**
|
||||
* Shows the code that a user must input into their browser
|
||||
*/
|
||||
public static void buildAndShowMicrosoftCodeWindow(GeyserSession session, StepMsaDeviceCode.MsaDeviceCode msCode) {
|
||||
public static void buildAndShowMicrosoftCodeWindow(GeyserSession session, MsaDeviceCode msCode) {
|
||||
String locale = session.locale();
|
||||
|
||||
StringBuilder message = new StringBuilder("%xbox.signin.website\n")
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024 GeyserMC. http://geysermc.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author GeyserMC
|
||||
* @link https://github.com/GeyserMC/Geyser
|
||||
*/
|
||||
|
||||
package org.geysermc.geyser.util;
|
||||
|
||||
import net.raphimc.minecraftauth.util.logging.ILogger;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
|
||||
public class MinecraftAuthLogger implements ILogger {
|
||||
|
||||
public static final MinecraftAuthLogger INSTANCE = new MinecraftAuthLogger();
|
||||
|
||||
@Override
|
||||
public void info(String message) {
|
||||
GeyserImpl.getInstance().getLogger().debug(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String message) {
|
||||
GeyserImpl.getInstance().getLogger().warning(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String message) {
|
||||
GeyserImpl.getInstance().getLogger().error(message);
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ protocol-connection = "3.0.0.Beta10-20251014.180344-2"
|
||||
protocol-common = "3.0.0.Beta10-20251014.180344-2"
|
||||
protocol-codec = "3.0.0.Beta10-20251014.180344-2"
|
||||
raknet = "1.0.0.CR3-20250811.214335-20"
|
||||
minecraftauth = "4.1.1"
|
||||
minecraftauth = "5.0.0"
|
||||
mcprotocollib = "1.21.9-20251029.184056-18"
|
||||
adventure = "4.25.0"
|
||||
adventure-platform = "4.4.1"
|
||||
|
||||
Reference in New Issue
Block a user