Remove Mojang account sign-in option (#4147)

* Remove Mojang auth

* Yeet Connector wrapper, ensure that empty config arrays (e.g. saved user logins) are empty lists instead of null to avoid NPE exceptions
This commit is contained in:
chris 2023-10-03 01:12:54 +02:00 committed by GitHub
parent 7d489c7354
commit 7983448ce6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 13 additions and 462 deletions

View file

@ -1,91 +0,0 @@
/*
* Copyright (c) 2019-2022 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.connector;
import org.geysermc.api.Geyser;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.connector.network.session.GeyserSession;
import org.geysermc.geyser.GeyserImpl;
import java.util.UUID;
/**
* Deprecated, please use {@link Geyser} or {@link GeyserImpl}.
*
* @deprecated legacy code
*/
@Deprecated
public class GeyserConnector {
public static final String NAME = GeyserImpl.NAME;
public static final String GIT_VERSION = GeyserImpl.GIT_VERSION; // A fallback for running in IDEs
public static final String VERSION = GeyserImpl.VERSION; // A fallback for running in IDEs
public static final String OAUTH_CLIENT_ID = GeyserImpl.OAUTH_CLIENT_ID;
private static final GeyserConnector INSTANCE = new GeyserConnector();
public static GeyserConnector getInstance() {
return INSTANCE;
}
public boolean isShuttingDown() {
return GeyserImpl.getInstance().isShuttingDown();
}
public PlatformType getPlatformType() {
return GeyserImpl.getInstance().getPlatformType();
}
public void shutdown() {
GeyserImpl.getInstance().shutdown();
}
public void reload() {
GeyserImpl.getInstance().reload();
}
public GeyserSession getPlayerByXuid(String xuid) {
org.geysermc.geyser.session.GeyserSession session = GeyserImpl.getInstance().connectionByXuid(xuid);
if (session != null) {
return new GeyserSession(session);
} else {
return null;
}
}
public GeyserSession getPlayerByUuid(UUID uuid) {
org.geysermc.geyser.session.GeyserSession session = GeyserImpl.getInstance().connectionByUuid(uuid);
if (session != null) {
return new GeyserSession(session);
} else {
return null;
}
}
public boolean isProductionEnvironment() {
return GeyserImpl.getInstance().isProductionEnvironment();
}
}

View file

@ -1,161 +0,0 @@
/*
* Copyright (c) 2019-2022 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.connector.network.session;
import com.github.steveice10.packetlib.packet.Packet;
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
import org.geysermc.connector.network.session.auth.AuthData;
/**
* Deprecated, legacy code. Serves as a wrapper around
* the class used now.
*
* @deprecated legacy code
*/
@Deprecated
public class GeyserSession {
private final org.geysermc.geyser.session.GeyserSession handle;
public GeyserSession(org.geysermc.geyser.session.GeyserSession handle) {
this.handle = handle;
}
public AuthData getAuthData() {
return new AuthData(this.handle.getAuthData());
}
public boolean isMicrosoftAccount() {
return this.handle.isMicrosoftAccount();
}
public boolean isClosed() {
return this.handle.isClosed();
}
public String getRemoteAddress() {
return this.handle.remoteServer().address();
}
public int getRemotePort() {
return this.handle.remoteServer().port();
}
public int getRenderDistance() {
return this.handle.getServerRenderDistance();
}
public boolean isSentSpawnPacket() {
return this.handle.isSentSpawnPacket();
}
public boolean isLoggedIn() {
return this.handle.isLoggedIn();
}
public boolean isLoggingIn() {
return this.handle.isLoggingIn();
}
public boolean isSpawned() {
return this.handle.isSpawned();
}
public boolean isInteracting() {
return this.handle.isInteracting();
}
public boolean isCanFly() {
return this.handle.isCanFly();
}
public boolean isFlying() {
return this.handle.isFlying();
}
public void connect() {
this.handle.connect();
}
public void login() {
throw new UnsupportedOperationException();
}
public void authenticate(String username) {
this.handle.authenticate(username);
}
public void authenticate(String username, String password) {
this.handle.authenticate(username, password);
}
public void authenticateWithMicrosoftCode() {
this.handle.authenticateWithMicrosoftCode();
}
public void disconnect(String reason) {
this.handle.disconnect(reason);
}
public void close() {
throw new UnsupportedOperationException();
}
public void executeInEventLoop(Runnable runnable) {
this.handle.executeInEventLoop(runnable);
}
public String getName() {
return this.handle.bedrockUsername();
}
public boolean isConsole() {
return this.handle.isConsole();
}
public String getLocale() {
return this.handle.locale();
}
public void sendUpstreamPacket(BedrockPacket packet) {
this.handle.sendUpstreamPacket(packet);
}
public void sendUpstreamPacketImmediately(BedrockPacket packet) {
this.handle.sendUpstreamPacketImmediately(packet);
}
public void sendDownstreamPacket(Packet packet) {
this.handle.sendDownstreamPacket(packet);
}
public boolean hasPermission(String permission) {
return this.handle.hasPermission(permission);
}
public void sendAdventureSettings() {
this.handle.sendAdventureSettings();
}
}

View file

@ -1,55 +0,0 @@
/*
* Copyright (c) 2019-2022 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.connector.network.session.auth;
import java.util.UUID;
/**
* Deprecated, legacy code. Serves as a wrapper around
* the class used now.
*
* @deprecated legacy code
*/
@Deprecated
public class AuthData {
private final org.geysermc.geyser.session.auth.AuthData handle;
public AuthData(org.geysermc.geyser.session.auth.AuthData handle) {
this.handle = handle;
}
public String getName() {
return this.handle.name();
}
public UUID getUUID() {
return this.handle.uuid();
}
public String getXboxUUID() {
return this.handle.xuid();
}
}

View file

@ -43,7 +43,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.api.Geyser;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.cumulus.form.Form;
import org.geysermc.cumulus.form.util.FormBuilder;
import org.geysermc.erosion.packet.Packets;
@ -61,6 +60,7 @@ import org.geysermc.geyser.api.event.lifecycle.GeyserShutdownEvent;
import org.geysermc.geyser.api.network.AuthType;
import org.geysermc.geyser.api.network.BedrockListener;
import org.geysermc.geyser.api.network.RemoteServer;
import org.geysermc.geyser.api.util.PlatformType;
import org.geysermc.geyser.command.GeyserCommandManager;
import org.geysermc.geyser.configuration.GeyserConfiguration;
import org.geysermc.geyser.entity.EntityDefinitions;
@ -478,12 +478,6 @@ public class GeyserImpl implements GeyserApi {
}
if (config.getRemote().authType() == AuthType.ONLINE) {
if (config.getUserAuths() != null && !config.getUserAuths().isEmpty()) {
getLogger().warning("The 'userAuths' config section is now deprecated, and will be removed in the near future! " +
"Please migrate to the new 'saved-user-logins' config option: " +
"https://wiki.geysermc.org/geyser/understanding-the-config/");
}
// May be written/read to on multiple threads from each GeyserSession as well as writing the config
savedRefreshTokens = new ConcurrentHashMap<>();

View file

@ -36,7 +36,6 @@ import org.geysermc.geyser.text.GeyserLocale;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
public interface GeyserConfiguration {
/**
@ -53,9 +52,6 @@ public interface GeyserConfiguration {
List<String> getSavedUserLogins();
@Deprecated
Map<String, ? extends IUserAuthenticationInfo> getUserAuths();
boolean isCommandSuggestions();
@JsonIgnore
@ -147,8 +143,6 @@ public interface GeyserConfiguration {
void setPort(int port);
boolean isPasswordAuthentication();
boolean isUseProxyProtocol();
boolean isForwardHost();
@ -164,18 +158,6 @@ public interface GeyserConfiguration {
void setAuthType(AuthType authType);
}
interface IUserAuthenticationInfo {
String getEmail();
String getPassword();
/**
* Will be removed after Microsoft accounts are fully migrated
*/
@Deprecated
boolean isMicrosoftAccount();
}
interface IMetricsInfo {
boolean isEnabled();

View file

@ -44,7 +44,6 @@ import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;
@ -67,8 +66,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
public abstract Path getFloodgateKeyPath();
private Map<String, UserAuthenticationInfo> userAuths;
@JsonProperty("command-suggestions")
private boolean commandSuggestions = true;
@ -275,10 +272,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
return false;
}
@Getter
@JsonProperty("allow-password-authentication")
private boolean passwordAuthentication = true;
@Getter
@JsonProperty("use-proxy-protocol")
private boolean useProxyProtocol = false;
@ -288,19 +281,6 @@ public abstract class GeyserJacksonConfiguration implements GeyserConfiguration
private boolean forwardHost = false;
}
@Getter
@JsonIgnoreProperties(ignoreUnknown = true) // DO NOT REMOVE THIS! Otherwise, after we remove microsoft-account configs will not load
public static class UserAuthenticationInfo implements IUserAuthenticationInfo {
@AsteriskSerializer.Asterisk()
private String email;
@AsteriskSerializer.Asterisk()
private String password;
@JsonProperty("microsoft-account")
private boolean microsoftAccount = false;
}
@Getter
@JsonIgnoreProperties(ignoreUnknown = true)
public static class MetricsInfo implements IMetricsInfo {

View file

@ -52,7 +52,6 @@ import org.geysermc.geyser.api.network.AuthType;
import org.geysermc.geyser.api.pack.PackCodec;
import org.geysermc.geyser.api.pack.ResourcePack;
import org.geysermc.geyser.api.pack.ResourcePackManifest;
import org.geysermc.geyser.configuration.GeyserConfiguration;
import org.geysermc.geyser.event.type.SessionLoadResourcePacksEventImpl;
import org.geysermc.geyser.pack.GeyserResourcePack;
import org.geysermc.geyser.registry.BlockRegistries;
@ -257,21 +256,9 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
return true;
}
}
if (geyser.getConfig().getUserAuths() != null) {
GeyserConfiguration.IUserAuthenticationInfo info = geyser.getConfig().getUserAuths().get(bedrockUsername);
if (info != null) {
geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.auth.stored_credentials", session.getAuthData().name()));
session.setMicrosoftAccount(info.isMicrosoftAccount());
session.authenticate(info.getEmail(), info.getPassword());
return true;
}
}
PendingMicrosoftAuthentication.AuthenticationTask task = geyser.getPendingMicrosoftAuthentication().getTask(session.getAuthData().xuid());
if (task != null) {
if (task.getAuthentication().isDone() && session.onMicrosoftLoginComplete(task)) {
return true;
}
return task.getAuthentication().isDone() && session.onMicrosoftLoginComplete(task);
}
return false;

View file

@ -26,10 +26,7 @@
package org.geysermc.geyser.session;
import com.github.steveice10.mc.auth.data.GameProfile;
import com.github.steveice10.mc.auth.exception.request.InvalidCredentialsException;
import com.github.steveice10.mc.auth.exception.request.RequestException;
import com.github.steveice10.mc.auth.service.AuthenticationService;
import com.github.steveice10.mc.auth.service.MojangAuthenticationService;
import com.github.steveice10.mc.auth.service.MsaAuthenticationService;
import com.github.steveice10.mc.protocol.MinecraftConstants;
import com.github.steveice10.mc.protocol.MinecraftProtocol;
@ -190,10 +187,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
@Setter
private RemoteServer remoteServer;
@Deprecated
@Setter
private boolean microsoftAccount;
private final SessionPlayerEntity playerEntity;
private final AdvancementsCache advancementsCache;
@ -701,76 +694,20 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
}
public void authenticate(String username) {
authenticate(username, "");
}
public void authenticate(String username, String password) {
if (loggedIn) {
geyser.getLogger().severe(GeyserLocale.getLocaleStringLog("geyser.auth.already_loggedin", username));
return;
}
loggingIn = true;
// Always replace spaces with underscores to avoid illegal nicknames, e.g. with GeyserConnect
protocol = new MinecraftProtocol(username.replace(' ', '_'));
// Use a future to prevent timeouts as all the authentication is handled sync
CompletableFuture.supplyAsync(() -> {
try {
if (password != null && !password.isEmpty()) {
AuthenticationService authenticationService;
if (microsoftAccount) {
authenticationService = new MsaAuthenticationService(GeyserImpl.OAUTH_CLIENT_ID);
} else {
authenticationService = new MojangAuthenticationService();
}
authenticationService.setUsername(username);
authenticationService.setPassword(password);
authenticationService.login();
GameProfile profile = authenticationService.getSelectedProfile();
if (profile == null) {
// Java account is offline
disconnect(GeyserLocale.getPlayerLocaleString("geyser.network.remote.invalid_account", clientData.getLanguageCode()));
return null;
}
protocol = new MinecraftProtocol(profile, authenticationService.getAccessToken());
} else {
// always replace spaces when using Floodgate,
// as usernames with spaces cause issues with Bungeecord's login cycle.
// However, this doesn't affect the final username as Floodgate is still in charge of that.
// So if you have (for example) replace spaces enabled on Floodgate the spaces will re-appear.
String validUsername = username;
if (this.remoteServer.authType() == AuthType.FLOODGATE) {
validUsername = username.replace(' ', '_');
}
protocol = new MinecraftProtocol(validUsername);
}
} catch (InvalidCredentialsException | IllegalArgumentException e) {
geyser.getLogger().info(GeyserLocale.getLocaleStringLog("geyser.auth.login.invalid", username));
disconnect(GeyserLocale.getPlayerLocaleString("geyser.auth.login.invalid.kick", getClientData().getLanguageCode()));
} catch (RequestException ex) {
disconnect(ex.getMessage());
}
return null;
}).whenComplete((aVoid, ex) -> {
if (ex != null) {
disconnect(ex.toString());
}
if (this.closed) {
if (ex != null) {
geyser.getLogger().error("", ex);
}
// Client disconnected during the authentication attempt
return;
}
try {
connectDownstream();
} catch (Throwable t) {
t.printStackTrace();
}
});
try {
connectDownstream();
} catch (Throwable t) {
t.printStackTrace();
}
}
public void authenticateWithRefreshToken(String refreshToken) {

View file

@ -25,6 +25,8 @@
package org.geysermc.geyser.util;
import com.fasterxml.jackson.annotation.JsonSetter;
import com.fasterxml.jackson.annotation.Nulls;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.geysermc.geyser.GeyserBootstrap;
@ -53,7 +55,8 @@ public class FileUtils {
* @throws IOException if the config could not be loaded
*/
public static <T> T loadConfig(File src, Class<T> valueType) throws IOException {
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory());
ObjectMapper objectMapper = new ObjectMapper(new YAMLFactory())
.setDefaultSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));
return objectMapper.readValue(src, valueType);
}

View file

@ -34,14 +34,12 @@ import org.cloudburstmc.protocol.bedrock.packet.ServerToClientHandshakePacket;
import org.cloudburstmc.protocol.bedrock.util.ChainValidationResult;
import org.cloudburstmc.protocol.bedrock.util.ChainValidationResult.IdentityData;
import org.cloudburstmc.protocol.bedrock.util.EncryptionUtils;
import org.geysermc.cumulus.form.CustomForm;
import org.geysermc.cumulus.form.ModalForm;
import org.geysermc.cumulus.form.SimpleForm;
import org.geysermc.cumulus.response.SimpleFormResponse;
import org.geysermc.cumulus.response.result.FormResponseResult;
import org.geysermc.cumulus.response.result.ValidFormResponseResult;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.configuration.GeyserConfiguration;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.auth.AuthData;
import org.geysermc.geyser.session.auth.BedrockClientData;
@ -137,26 +135,16 @@ public class LoginEncryptionUtils {
// Set DoDaylightCycle to false so the time doesn't accelerate while we're here
session.setDaylightCycle(false);
GeyserConfiguration config = session.getGeyser().getConfig();
boolean isPasswordAuthEnabled = config.getRemote().isPasswordAuthentication();
session.sendForm(
SimpleForm.builder()
.translator(GeyserLocale::getPlayerLocaleString, session.locale())
.title("geyser.auth.login.form.notice.title")
.content("geyser.auth.login.form.notice.desc")
.optionalButton("geyser.auth.login.form.notice.btn_login.mojang", isPasswordAuthEnabled)
.button("geyser.auth.login.form.notice.btn_login.microsoft")
.button("geyser.auth.login.form.notice.btn_disconnect")
.closedOrInvalidResultHandler(() -> buildAndShowLoginWindow(session))
.validResultHandler((response) -> {
if (response.clickedButtonId() == 0) {
session.setMicrosoftAccount(false);
buildAndShowLoginDetailsWindow(session);
return;
}
if (response.clickedButtonId() == 1) {
session.authenticateWithMicrosoftCode();
return;
}
@ -212,19 +200,6 @@ public class LoginEncryptionUtils {
};
}
public static void buildAndShowLoginDetailsWindow(GeyserSession session) {
session.sendForm(
CustomForm.builder()
.translator(GeyserLocale::getPlayerLocaleString, session.locale())
.title("geyser.auth.login.form.details.title")
.label("geyser.auth.login.form.details.desc")
.input("geyser.auth.login.form.details.email", "account@geysermc.org", "")
.input("geyser.auth.login.form.details.pass", "123456", "")
.invalidResultHandler(() -> buildAndShowLoginDetailsWindow(session))
.closedResultHandler(() -> buildAndShowLoginWindow(session))
.validResultHandler((response) -> session.authenticate(response.next(), response.next())));
}
/**
* Shows the code that a user must input into their browser
*/