mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-08-14 23:57:35 +00:00
Add migration from refresh tokens to auth chains
This commit is contained in:
parent
59495d8cc1
commit
450af559b5
4 changed files with 86 additions and 6 deletions
|
|
@ -39,6 +39,8 @@ public final class Constants {
|
|||
public static final String GEYSER_DOWNLOAD_LOCATION = "https://geysermc.org/download";
|
||||
public static final String UPDATE_PERMISSION = "geyser.update";
|
||||
|
||||
@Deprecated
|
||||
static final String SAVED_REFRESH_TOKEN_FILE = "saved-refresh-tokens.json";
|
||||
static final String SAVED_AUTH_CHAINS_FILE = "saved-auth-chains.json";
|
||||
|
||||
public static final String GEYSER_CUSTOM_NAMESPACE = "geyser_custom";
|
||||
|
|
@ -54,4 +56,4 @@ public final class Constants {
|
|||
}
|
||||
GLOBAL_API_WS_URI = wsUri;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import com.fasterxml.jackson.core.JsonParser;
|
|||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.gson.Gson;
|
||||
import io.netty.channel.epoll.Epoll;
|
||||
import io.netty.util.NettyRuntime;
|
||||
import io.netty.util.concurrent.DefaultThreadFactory;
|
||||
|
|
@ -38,6 +39,8 @@ import lombok.Getter;
|
|||
import lombok.Setter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.raphimc.minecraftauth.step.java.session.StepFullJavaSession;
|
||||
import net.raphimc.minecraftauth.step.msa.StepRefreshTokenMsaCode;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
|
@ -55,7 +58,11 @@ import org.geysermc.geyser.api.GeyserApi;
|
|||
import org.geysermc.geyser.api.command.CommandSource;
|
||||
import org.geysermc.geyser.api.event.EventBus;
|
||||
import org.geysermc.geyser.api.event.EventRegistrar;
|
||||
import org.geysermc.geyser.api.event.lifecycle.*;
|
||||
import org.geysermc.geyser.api.event.lifecycle.GeyserPostInitializeEvent;
|
||||
import org.geysermc.geyser.api.event.lifecycle.GeyserPostReloadEvent;
|
||||
import org.geysermc.geyser.api.event.lifecycle.GeyserPreInitializeEvent;
|
||||
import org.geysermc.geyser.api.event.lifecycle.GeyserPreReloadEvent;
|
||||
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;
|
||||
|
|
@ -85,7 +92,13 @@ import org.geysermc.geyser.skin.SkinProvider;
|
|||
import org.geysermc.geyser.text.GeyserLocale;
|
||||
import org.geysermc.geyser.text.MinecraftLocale;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.*;
|
||||
import org.geysermc.geyser.util.AssetUtils;
|
||||
import org.geysermc.geyser.util.CooldownUtils;
|
||||
import org.geysermc.geyser.util.DimensionUtils;
|
||||
import org.geysermc.geyser.util.Metrics;
|
||||
import org.geysermc.geyser.util.NewsHandler;
|
||||
import org.geysermc.geyser.util.VersionCheckUtils;
|
||||
import org.geysermc.geyser.util.WebUtils;
|
||||
import org.geysermc.mcprotocollib.network.tcp.TcpSession;
|
||||
|
||||
import java.io.File;
|
||||
|
|
@ -97,7 +110,14 @@ import java.net.UnknownHostException;
|
|||
import java.nio.file.Path;
|
||||
import java.security.Key;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
|
|
@ -536,6 +556,54 @@ public class GeyserImpl implements GeyserApi {
|
|||
// May be written/read to on multiple threads from each GeyserSession as well as writing the config
|
||||
savedAuthChains = new ConcurrentHashMap<>();
|
||||
|
||||
boolean doWrite = false;
|
||||
|
||||
// Remove after a while - just a migration help
|
||||
//noinspection deprecation
|
||||
File refreshTokensFile = bootstrap.getSavedUserLoginsFolder().resolve(Constants.SAVED_REFRESH_TOKEN_FILE).toFile();
|
||||
if (refreshTokensFile.exists()) {
|
||||
TypeReference<Map<String, String>> type = new TypeReference<>() { };
|
||||
Map<String, String> authChainFile = null;
|
||||
try {
|
||||
authChainFile = JSON_MAPPER.readValue(refreshTokensFile, type);
|
||||
} catch (IOException e) {
|
||||
// ignored - we'll just delete this file :))
|
||||
}
|
||||
|
||||
if (authChainFile != null) {
|
||||
List<String> validUsers = config.getSavedUserLogins();
|
||||
final Gson gson = new Gson();
|
||||
for (Map.Entry<String, String> entry : authChainFile.entrySet()) {
|
||||
String user = entry.getKey();
|
||||
if (!validUsers.contains(user)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Migrate refresh tokens to auth chains
|
||||
try {
|
||||
StepFullJavaSession javaSession = PendingMicrosoftAuthentication.REFRESH_TOKEN_UPDATE_AUTH_FLOW.apply(true, 10);
|
||||
StepFullJavaSession.FullJavaSession fullJavaSession = javaSession.getFromInput(
|
||||
PendingMicrosoftAuthentication.AUTH_CLIENT,
|
||||
new StepRefreshTokenMsaCode.RefreshToken(entry.getValue())
|
||||
);
|
||||
|
||||
String authChain = gson.toJson(javaSession.toJson(fullJavaSession));
|
||||
GeyserImpl.getInstance().getLogger().warning("new auth chain: " + authChain);
|
||||
savedAuthChains.put(user, authChain);
|
||||
} catch (Exception e) {
|
||||
GeyserImpl.getInstance().getLogger().warning("Could not migrate " + entry.getKey() + " to an auth chain! " +
|
||||
"They will need to sign in the next time they join Geyser.");
|
||||
}
|
||||
|
||||
// Ensure the new additions are written to the file
|
||||
doWrite = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally: Delete it. Goodbye!
|
||||
//refreshTokensFile.delete();
|
||||
}
|
||||
|
||||
File authChainsFile = bootstrap.getSavedUserLoginsFolder().resolve(Constants.SAVED_AUTH_CHAINS_FILE).toFile();
|
||||
if (authChainsFile.exists()) {
|
||||
TypeReference<Map<String, String>> type = new TypeReference<>() { };
|
||||
|
|
@ -548,7 +616,6 @@ public class GeyserImpl implements GeyserApi {
|
|||
}
|
||||
if (authChainFile != null) {
|
||||
List<String> validUsers = config.getSavedUserLogins();
|
||||
boolean doWrite = false;
|
||||
for (Map.Entry<String, String> entry : authChainFile.entrySet()) {
|
||||
String user = entry.getKey();
|
||||
if (!validUsers.contains(user)) {
|
||||
|
|
|
|||
|
|
@ -709,7 +709,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
try {
|
||||
response = step.refresh(PendingMicrosoftAuthentication.AUTH_CLIENT, step.fromJson(gson.fromJson(authChain, JsonObject.class)));
|
||||
} catch (Exception e) {
|
||||
geyser.getLogger().error("Error while attempting to use refresh token for " + bedrockUsername() + "!", e);
|
||||
geyser.getLogger().error("Error while attempting to use auth chain for " + bedrockUsername() + "!", e);
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ 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.step.msa.StepRefreshTokenMsaCode;
|
||||
import net.raphimc.minecraftauth.util.MicrosoftConstants;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
|
|
@ -58,6 +59,16 @@ public class PendingMicrosoftAuthentication {
|
|||
.withoutDeviceToken()
|
||||
.regularAuthentication(MicrosoftConstants.JAVA_XSTS_RELYING_PARTY)
|
||||
.buildMinecraftJavaProfileStep(false);
|
||||
|
||||
public static final BiFunction<Boolean, Integer, StepFullJavaSession> REFRESH_TOKEN_UPDATE_AUTH_FLOW = (offlineAccess, timeoutSec) -> MinecraftAuth.builder()
|
||||
.withClientId(GeyserImpl.OAUTH_CLIENT_ID)
|
||||
.withScope(offlineAccess ? "XboxLive.signin XboxLive.offline_access" : "XboxLive.signin")
|
||||
.withTimeout(timeoutSec)
|
||||
.customMsaCodeStep(StepRefreshTokenMsaCode::new)
|
||||
.withoutDeviceToken()
|
||||
.regularAuthentication(MicrosoftConstants.JAVA_XSTS_RELYING_PARTY)
|
||||
.buildMinecraftJavaProfileStep(false);
|
||||
|
||||
/**
|
||||
* For GeyserConnect usage.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue