From a8022004dff7e3d2e427360d43506aff98ce820c Mon Sep 17 00:00:00 2001 From: 33 Date: Thu, 2 Feb 2023 02:14:50 +0800 Subject: [PATCH] Add: clientid and auth_xuid --- jmccc-cli/src/main/java/jmccc/cli/Main.java | 14 +- .../jmccc/cli/download/CliDownloader.java | 38 +++-- .../jmccc/cli/launch/CliAuthenticator.java | 8 +- .../main/java/jmccc/cli/launch/CliConfig.java | 6 +- .../java/jmccc/cli/launch/CliLauncher.java | 1 + .../provider/forge/ForgeDownloadProvider.java | 147 ++++++------------ .../LiteloaderDownloadProvider.java | 11 +- .../microsoft/MicrosoftAuthenticator.java | 32 ++-- .../MicrosoftAuthenticationController.java | 44 +++--- .../core/MicrosoftAuthenticationService.java | 4 +- ...cationToken.java => MicrosoftSession.java} | 6 +- .../java/org/to2mbn/jmccc/auth/AuthInfo.java | 37 ++++- .../org/to2mbn/jmccc/launch/LauncherImpl.java | 8 +- .../java/org/to2mbn/jmccc/util/UUIDUtils.java | 5 + 14 files changed, 187 insertions(+), 174 deletions(-) rename jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/entity/{AuthenticationToken.java => MicrosoftSession.java} (76%) diff --git a/jmccc-cli/src/main/java/jmccc/cli/Main.java b/jmccc-cli/src/main/java/jmccc/cli/Main.java index 337ebe6..b55bcd3 100644 --- a/jmccc-cli/src/main/java/jmccc/cli/Main.java +++ b/jmccc-cli/src/main/java/jmccc/cli/Main.java @@ -5,6 +5,7 @@ import jmccc.cli.launch.CliAuthenticator; import jmccc.cli.launch.CliConfig; import jmccc.cli.launch.CliLauncher; +import jmccc.microsoft.MicrosoftAuthenticator; import joptsimple.OptionParser; import joptsimple.OptionSet; import joptsimple.OptionSpec; @@ -20,7 +21,9 @@ public class Main { /** * Arguments: - * [--offline player_name] [--dir minecraft_directory] [version] + * Microsoft Account: [--microsoft] [--clientId client_id] + * Offline: [--offline player_name] + * [--bmclapi] [--dir minecraft_directory] [version] */ public static void main(String... args) { try { @@ -36,9 +39,12 @@ private static void internal(String... args) throws Exception { //Parse args OptionParser parser = new OptionParser(); parser.accepts("microsoft"); + parser.accepts("bmclapi"); OptionSpec offlineOption = parser.accepts("offline") .availableUnless("microsoft").withOptionalArg().defaultsTo("Player"); OptionSpec dirOption = parser.accepts("dir").withOptionalArg().defaultsTo(".minecraft"); + OptionSpec clientIdOption = parser.accepts("clientId") + .availableIf("microsoft").withOptionalArg(); OptionSpec versionOption = parser.nonOptions(); OptionSet options = parser.parse(args); @@ -47,9 +53,15 @@ private static void internal(String... args) throws Exception { String version = versionOption.value(options); MinecraftDirectory minecraftDirectory = new MinecraftDirectory(dir); boolean isMicrosoftAccount = options.has("microsoft"); + boolean isBmclApi = options.has("bmclapi"); + String clientId = clientIdOption.value(options); //Init config CliConfig.initConfig(minecraftDirectory); + if (clientId != null) { + MicrosoftAuthenticator.setClientId(clientId); + } + CliDownloader.init(isBmclApi); //Check special version version = parseVersion(version); diff --git a/jmccc-cli/src/main/java/jmccc/cli/download/CliDownloader.java b/jmccc-cli/src/main/java/jmccc/cli/download/CliDownloader.java index 4a6a1c6..dff4d12 100644 --- a/jmccc-cli/src/main/java/jmccc/cli/download/CliDownloader.java +++ b/jmccc-cli/src/main/java/jmccc/cli/download/CliDownloader.java @@ -4,6 +4,7 @@ import org.to2mbn.jmccc.mcdownloader.MinecraftDownloaderBuilder; import org.to2mbn.jmccc.mcdownloader.download.combine.CombinedDownloadTask; import org.to2mbn.jmccc.mcdownloader.provider.DownloadProviderChain; +import org.to2mbn.jmccc.mcdownloader.provider.MojangDownloadProvider; import org.to2mbn.jmccc.mcdownloader.provider.fabric.FabricDownloadProvider; import org.to2mbn.jmccc.mcdownloader.provider.forge.ForgeDownloadProvider; import org.to2mbn.jmccc.mcdownloader.provider.liteloader.LiteloaderDownloadProvider; @@ -15,21 +16,28 @@ import java.util.concurrent.ExecutionException; public class CliDownloader { - public static BmclApiProvider bmclApiProvider = new BmclApiProvider(); - public static ForgeDownloadProvider forgeProvider = new ForgeDownloadProvider(bmclApiProvider); - public static LiteloaderDownloadProvider liteloaderProvider = new LiteloaderDownloadProvider(bmclApiProvider); - public static FabricDownloadProvider fabricProvider = new FabricDownloadProvider(); - public static FabricDownloadProvider quiltProvider = new QuiltDownloadProvider(); - - public static MinecraftDownloader downloader = MinecraftDownloaderBuilder.create() - .providerChain(DownloadProviderChain.create() - .baseProvider(bmclApiProvider) - .addProvider(forgeProvider) - .addProvider(liteloaderProvider) - .addProvider(fabricProvider) - .addProvider(quiltProvider) - ) - .build(); + public static ForgeDownloadProvider forgeProvider; + public static LiteloaderDownloadProvider liteloaderProvider; + public static FabricDownloadProvider fabricProvider; + public static FabricDownloadProvider quiltProvider; + public static MinecraftDownloader downloader; + + public static void init(boolean isBmclApi) { + BmclApiProvider bmclApiProvider = isBmclApi ? new BmclApiProvider() : null; + forgeProvider = new ForgeDownloadProvider(bmclApiProvider); + liteloaderProvider = new LiteloaderDownloadProvider(bmclApiProvider); + fabricProvider = new FabricDownloadProvider(); + quiltProvider = new QuiltDownloadProvider(); + downloader = MinecraftDownloaderBuilder.create() + .providerChain(DownloadProviderChain.create() + .baseProvider(bmclApiProvider == null ? new MojangDownloadProvider() : bmclApiProvider) + .addProvider(forgeProvider) + .addProvider(liteloaderProvider) + .addProvider(fabricProvider) + .addProvider(quiltProvider) + ) + .build(); + } public static String getLatestRelease() throws ExecutionException, InterruptedException { return downloader.fetchRemoteVersionList(null).get().getLatestRelease(); diff --git a/jmccc-cli/src/main/java/jmccc/cli/launch/CliAuthenticator.java b/jmccc-cli/src/main/java/jmccc/cli/launch/CliAuthenticator.java index 7328236..0ad0302 100644 --- a/jmccc-cli/src/main/java/jmccc/cli/launch/CliAuthenticator.java +++ b/jmccc-cli/src/main/java/jmccc/cli/launch/CliAuthenticator.java @@ -1,7 +1,7 @@ package jmccc.cli.launch; import jmccc.microsoft.MicrosoftAuthenticator; -import jmccc.microsoft.entity.AuthenticationToken; +import jmccc.microsoft.entity.MicrosoftSession; import org.to2mbn.jmccc.auth.AuthenticationException; import org.to2mbn.jmccc.auth.Authenticator; @@ -10,16 +10,16 @@ public class CliAuthenticator { public static Authenticator getMicrosoftAuthenticator() throws AuthenticationException, IOException { CliConfig config = CliConfig.getConfig(); - AuthenticationToken token = config.token; + MicrosoftSession token = config.token; MicrosoftAuthenticator ma; if (token == null) { System.out.println("Minecraft and Microsoft token not found."); ma = MicrosoftAuthenticator.login(it -> System.out.println(it.message)); } else { System.out.println("Existing Minecraft and Microsoft token found."); - ma = MicrosoftAuthenticator.token(token, it -> System.out.println(it.message)); + ma = MicrosoftAuthenticator.session(token, it -> System.out.println(it.message)); } - config.token = ma.getAuthenticationToken(); + config.token = ma.getSession(); config.writeToFile(); return ma; } diff --git a/jmccc-cli/src/main/java/jmccc/cli/launch/CliConfig.java b/jmccc-cli/src/main/java/jmccc/cli/launch/CliConfig.java index 4755d28..99d2b35 100644 --- a/jmccc-cli/src/main/java/jmccc/cli/launch/CliConfig.java +++ b/jmccc-cli/src/main/java/jmccc/cli/launch/CliConfig.java @@ -2,8 +2,9 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import jmccc.microsoft.entity.AuthenticationToken; +import jmccc.microsoft.entity.MicrosoftSession; import org.to2mbn.jmccc.option.MinecraftDirectory; +import org.to2mbn.jmccc.util.UUIDUtils; import java.io.BufferedWriter; import java.io.IOException; @@ -11,7 +12,8 @@ import java.nio.file.Path; public class CliConfig { - public AuthenticationToken token; + public MicrosoftSession token; + public String clientId = UUIDUtils.randomUnsignedUuidBase64(); private static CliConfig instance; private static Path configFile; diff --git a/jmccc-cli/src/main/java/jmccc/cli/launch/CliLauncher.java b/jmccc-cli/src/main/java/jmccc/cli/launch/CliLauncher.java index d209b2e..1642f1c 100644 --- a/jmccc-cli/src/main/java/jmccc/cli/launch/CliLauncher.java +++ b/jmccc-cli/src/main/java/jmccc/cli/launch/CliLauncher.java @@ -15,6 +15,7 @@ public static void launch(LaunchOption option) throws Exception { Launcher launcher = LauncherBuilder.create().printDebugCommandline(true).build(); //Change Minecraft main menu bottom left text option.commandlineVariables().put("version_type", "JMCCC 3.0"); + option.commandlineVariables().put("clientid", CliConfig.getConfig().clientId); //Set memory to 2048MB option.setMaxMemory(2048); ProcessListener listener = new CliListener(); diff --git a/jmccc-mcdownloader/src/main/java/org/to2mbn/jmccc/mcdownloader/provider/forge/ForgeDownloadProvider.java b/jmccc-mcdownloader/src/main/java/org/to2mbn/jmccc/mcdownloader/provider/forge/ForgeDownloadProvider.java index eabf3e8..09c5314 100644 --- a/jmccc-mcdownloader/src/main/java/org/to2mbn/jmccc/mcdownloader/provider/forge/ForgeDownloadProvider.java +++ b/jmccc-mcdownloader/src/main/java/org/to2mbn/jmccc/mcdownloader/provider/forge/ForgeDownloadProvider.java @@ -16,11 +16,9 @@ import org.to2mbn.jmccc.version.parsing.Versions; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; +import java.nio.file.Files; import java.util.HashSet; -import java.util.Objects; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -37,7 +35,7 @@ public class ForgeDownloadProvider extends AbstractMinecraftDownloadProvider imp private static final String[] UNIVERSAL_TYPES = new String[]{"jar", "zip"}; - private ForgeDownloadSource source; + private final ForgeDownloadSource source; private MinecraftDownloadProvider upstreamProvider; @@ -46,20 +44,17 @@ public ForgeDownloadProvider() { } public ForgeDownloadProvider(ForgeDownloadSource source) { - this.source = Objects.requireNonNull(source); + if (source == null) { + source = new DefaultForgeDownloadSource(); + } + this.source = source; } public CombinedDownloadTask forgeVersionList() { return CombinedDownloadTask.single( new MemoryDownloadTask(source.getForgeVersionListUrl()) .andThen(new JsonDecoder()) - .andThen(new ResultProcessor() { - - @Override - public ForgeVersionList process(JSONObject json) throws IOException { - return ForgeVersionList.fromJson(json); - } - }) + .andThen(ForgeVersionList::fromJson) .cacheable() .cachePool(CacheNames.FORGE_VERSION_LIST)); } @@ -70,25 +65,19 @@ public CombinedDownloadTask gameVersionJson(final MinecraftDirectory mcd if (forgeInfo != null) { return forgeVersion(forgeInfo.getForgeVersion()) - .andThenDownload(new ResultProcessor>() { - - @Override - public CombinedDownloadTask process(final ForgeVersion forge) throws Exception { - return CombinedDownloadTask.any( - installerTask(forge.getMavenVersion()) - .andThen(new InstallProfileProcessor(mcdir)), - upstreamProvider.gameVersionJson(mcdir, forge.getMinecraftVersion()) - .andThen(new ResultProcessor() { - - // for old forge versions - @Override - public JSONObject process(String superversion) throws Exception { - return createForgeVersionJson(mcdir, forge); - } - }) - .andThen(new VersionJsonInstaller(mcdir))); - } - }); + .andThenDownload(forge -> CombinedDownloadTask.any( + installerTask(forge.getMavenVersion()) + .andThen(new InstallProfileProcessor(mcdir)), + upstreamProvider.gameVersionJson(mcdir, forge.getMinecraftVersion()) + .andThen(new ResultProcessor() { + + // for old forge versions + @Override + public JSONObject process(String superversion) throws Exception { + return createForgeVersionJson(mcdir, forge); + } + }) + .andThen(new VersionJsonInstaller(mcdir)))); } return null; @@ -103,13 +92,7 @@ public CombinedDownloadTask library(final MinecraftDirectory mcdir, final } else if (FORGE_OLD_ARTIFACT_ID.equals(library.getArtifactId())) { return forgeVersion(library.getVersion()) - .andThenDownload(new ResultProcessor>() { - - @Override - public CombinedDownloadTask process(ForgeVersion version) throws Exception { - return universalTask(version.getMavenVersion(), mcdir.getLibrary(library)); - } - }); + .andThenDownload(version -> universalTask(version.getMavenVersion(), mcdir.getLibrary(library))); } } return null; @@ -134,13 +117,7 @@ public CombinedDownloadTask gameJar(final MinecraftDirectory mcdir, final CombinedDownloadTask baseTask; if (forgeInfo.getMinecraftVersion() == null) { baseTask = forgeVersion(forgeInfo.getForgeVersion()) - .andThenDownload(new ResultProcessor>() { - - @Override - public CombinedDownloadTask process(ForgeVersion forge) throws Exception { - return downloadSuperVersion(mcdir, forge.getMinecraftVersion()); - } - }); + .andThenDownload(forge -> downloadSuperVersion(mcdir, forge.getMinecraftVersion())); } else { baseTask = downloadSuperVersion(mcdir, forgeInfo.getMinecraftVersion()); } @@ -154,39 +131,19 @@ public CombinedDownloadTask process(ForgeVersion forge) throws Exceptio // copy universal into the jar final File universalFile = mcdir.getLibrary(new Library("net.minecraftforge", "minecraftforge", forgeInfo.getForgeVersion())); return baseTask - .andThenDownload(new ResultProcessor>() { - - @Override - public CombinedDownloadTask process(final Version superVersion) throws Exception { - return forgeVersion(forgeInfo.getForgeVersion()) - .andThenDownload(new ResultProcessor>() { - - @Override - public CombinedDownloadTask process(ForgeVersion forge) throws Exception { - return universalTask(forge.getMavenVersion(), universalFile) - .andThenReturn(superVersion); - } - }); - } - }) - .andThen(new ResultProcessor() { - - @Override - public Void process(final Version superVersion) throws Exception { - mergeJar(mcdir.getVersionJar(superVersion), universalFile, targetJar); - return null; - } + .andThenDownload(superVersion -> forgeVersion(forgeInfo.getForgeVersion()) + .andThenDownload(forge -> universalTask(forge.getMavenVersion(), universalFile) + .andThenReturn(superVersion))) + .andThen(superVersion -> { + mergeJar(mcdir.getVersionJar(superVersion), universalFile, targetJar); + return null; }); } else { // copy its superversion's jar // remove META-INF - return baseTask.andThen(new ResultProcessor() { - - @Override - public Void process(final Version superVersion) throws Exception { - purgeMetaInf(mcdir.getVersionJar(superVersion), targetJar); - return null; - } + return baseTask.andThen(superVersion -> { + purgeMetaInf(mcdir.getVersionJar(superVersion), targetJar); + return null; }); } } @@ -235,9 +192,9 @@ protected JSONObject createForgeVersionJson(MinecraftDirectory mcdir, ForgeVersi protected void mergeJar(File parent, File universal, File target) throws IOException { FileUtils.prepareWrite(target); - try (ZipInputStream in = new ZipInputStream(new FileInputStream(parent)); - ZipInputStream universalIn = new ZipInputStream(new FileInputStream(universal)); - ZipOutputStream out = new ZipOutputStream(new FileOutputStream(target));) { + try (ZipInputStream in = new ZipInputStream(Files.newInputStream(parent.toPath())); + ZipInputStream universalIn = new ZipInputStream(Files.newInputStream(universal.toPath())); + ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(target.toPath()))) { ZipEntry entry; byte[] buf = new byte[8192]; int read; @@ -255,7 +212,7 @@ protected void mergeJar(File parent, File universal, File target) throws IOExcep } while ((entry = in.getNextEntry()) != null) { - if (!isMetaInfEntry(entry) && !universalEntries.contains(entry.getName())) { + if (isNotMetaInfEntry(entry) && !universalEntries.contains(entry.getName())) { out.putNextEntry(entry); while ((read = in.read(buf)) != -1) { out.write(buf, 0, read); @@ -269,13 +226,13 @@ protected void mergeJar(File parent, File universal, File target) throws IOExcep protected void purgeMetaInf(File src, File target) throws IOException { FileUtils.prepareWrite(target); - try (ZipInputStream in = new ZipInputStream(new FileInputStream(src)); - ZipOutputStream out = new ZipOutputStream(new FileOutputStream(target));) { + try (ZipInputStream in = new ZipInputStream(Files.newInputStream(src.toPath())); + ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(target.toPath()))) { ZipEntry entry; byte[] buf = new byte[8192]; int read; while ((entry = in.getNextEntry()) != null) { - if (!isMetaInfEntry(entry)) { + if (isNotMetaInfEntry(entry)) { out.putNextEntry(entry); while ((read = in.read(buf)) != -1) { out.write(buf, 0, read); @@ -289,32 +246,24 @@ protected void purgeMetaInf(File src, File target) throws IOException { private CombinedDownloadTask forgeVersion(final String forgeVersion) { return forgeVersionList() - .andThen(new ResultProcessor() { - - @Override - public ForgeVersion process(ForgeVersionList versionList) throws Exception { - ForgeVersion forge = versionList.get(forgeVersion); - if (forge == null) { - throw new IllegalArgumentException("Forge version not found: " + forgeVersion); - } - return forge; + .andThen(versionList -> { + ForgeVersion forge = versionList.get(forgeVersion); + if (forge == null) { + throw new IllegalArgumentException("Forge version not found: " + forgeVersion); } + return forge; }); } - private boolean isMetaInfEntry(ZipEntry entry) { - return entry.getName().startsWith("META-INF/"); + private boolean isNotMetaInfEntry(ZipEntry entry) { + return !entry.getName().startsWith("META-INF/"); } private CombinedDownloadTask downloadSuperVersion(final MinecraftDirectory mcdir, String version) { return upstreamProvider.gameVersionJson(mcdir, version) - .andThenDownload(new ResultProcessor>() { - - @Override - public CombinedDownloadTask process(String resolvedMcversion) throws Exception { - final Version superversion = Versions.resolveVersion(mcdir, resolvedMcversion); - return upstreamProvider.gameJar(mcdir, superversion).andThenReturn(superversion); - } + .andThenDownload(resolvedMcversion -> { + final Version superversion = Versions.resolveVersion(mcdir, resolvedMcversion); + return upstreamProvider.gameJar(mcdir, superversion).andThenReturn(superversion); }); } diff --git a/jmccc-mcdownloader/src/main/java/org/to2mbn/jmccc/mcdownloader/provider/liteloader/LiteloaderDownloadProvider.java b/jmccc-mcdownloader/src/main/java/org/to2mbn/jmccc/mcdownloader/provider/liteloader/LiteloaderDownloadProvider.java index 6c9e2e4..932fd61 100644 --- a/jmccc-mcdownloader/src/main/java/org/to2mbn/jmccc/mcdownloader/provider/liteloader/LiteloaderDownloadProvider.java +++ b/jmccc-mcdownloader/src/main/java/org/to2mbn/jmccc/mcdownloader/provider/liteloader/LiteloaderDownloadProvider.java @@ -7,14 +7,12 @@ import org.to2mbn.jmccc.mcdownloader.download.combine.CombinedDownloadTask; import org.to2mbn.jmccc.mcdownloader.download.tasks.FileDownloadTask; import org.to2mbn.jmccc.mcdownloader.download.tasks.MemoryDownloadTask; -import org.to2mbn.jmccc.mcdownloader.download.tasks.ResultProcessor; import org.to2mbn.jmccc.mcdownloader.provider.*; import org.to2mbn.jmccc.option.MinecraftDirectory; import org.to2mbn.jmccc.util.IOUtils; import org.to2mbn.jmccc.version.Library; import java.io.IOException; -import java.util.Objects; import java.util.Set; public class LiteloaderDownloadProvider extends AbstractMinecraftDownloadProvider implements ExtendedDownloadProvider { @@ -29,11 +27,11 @@ public class LiteloaderDownloadProvider extends AbstractMinecraftDownloadProvide public static final String LAUNCH_WRAPPER_LOWEST_VERSION = "1.7"; public static final String LAUNCH_WRAPPER_MAINCLASS = "net.minecraft.launchwrapper.Launch"; - private LiteloaderDownloadSource source; + private final LiteloaderDownloadSource source; private boolean upgradeLaunchWrapper = true; private String lowestLaunchWrapperVersion = LAUNCH_WRAPPER_LOWEST_VERSION; - private VersionComparator versionComparator = new VersionComparator(); + private final VersionComparator versionComparator = new VersionComparator(); private MinecraftDownloadProvider upstreamProvider; public LiteloaderDownloadProvider() { @@ -41,7 +39,10 @@ public LiteloaderDownloadProvider() { } public LiteloaderDownloadProvider(LiteloaderDownloadSource source) { - this.source = Objects.requireNonNull(source); + if (source == null) { + source = new DefaultLiteloaderDownloadSource(); + } + this.source = source; } public CombinedDownloadTask liteloaderVersionList() { diff --git a/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/MicrosoftAuthenticator.java b/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/MicrosoftAuthenticator.java index f31ae8b..4941861 100644 --- a/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/MicrosoftAuthenticator.java +++ b/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/MicrosoftAuthenticator.java @@ -1,7 +1,7 @@ package jmccc.microsoft; import jmccc.microsoft.core.MicrosoftAuthenticationController; -import jmccc.microsoft.entity.AuthenticationToken; +import jmccc.microsoft.entity.MicrosoftSession; import jmccc.microsoft.entity.MicrosoftVerification; import jmccc.microsoft.entity.MinecraftProfile; import org.to2mbn.jmccc.auth.AuthInfo; @@ -17,7 +17,7 @@ public class MicrosoftAuthenticator implements Authenticator { private static String clientId; private MinecraftProfile profile; - private AuthenticationToken authenticationToken; + private MicrosoftSession session; private final MicrosoftAuthenticationController controller; @@ -30,28 +30,28 @@ private MicrosoftAuthenticator() { * Create with exist token * This method will take a long time and block current thread, please run in new thread * - * @param token token used in authenticator + * @param session token used in authenticator * @param callback a callback to display verification link and code to user * @return MicrosoftAuthenticator */ - public static MicrosoftAuthenticator token(AuthenticationToken token, Consumer callback) throws AuthenticationException { + public static MicrosoftAuthenticator session(MicrosoftSession session, Consumer callback) throws AuthenticationException { MicrosoftAuthenticator authenticator = new MicrosoftAuthenticator(); MicrosoftAuthenticationController controller = authenticator.controller; - authenticator.authenticationToken = token; + authenticator.session = session; //Get profile by token try { - authenticator.profile = controller.getMinecraftProfile(token); + authenticator.profile = controller.getMinecraftProfile(session); return authenticator; } catch (AuthenticationException ignored) { } //Refresh tokens try { - token = controller.refreshMicrosoftToken(token); - token = controller.getMinecraftToken(token); - authenticator.authenticationToken = token; - authenticator.profile = controller.getMinecraftProfile(token); + session = controller.refreshMicrosoftToken(session); + session = controller.getMinecraftToken(session); + authenticator.session = session; + authenticator.profile = controller.getMinecraftProfile(session); return authenticator; } catch (AuthenticationException ignored) { } @@ -73,8 +73,8 @@ public static MicrosoftAuthenticator login(Consumer callb MicrosoftAuthenticationController controller = authenticator.controller; //Get token and profile - authenticator.authenticationToken = controller.getMinecraftToken(controller.getMicrosoftToken(callback)); - authenticator.profile = controller.getMinecraftProfile(authenticator.authenticationToken); + authenticator.session = controller.getMinecraftToken(controller.getMicrosoftToken(callback)); + authenticator.profile = controller.getMinecraftProfile(authenticator.session); return authenticator; } @@ -87,8 +87,8 @@ public static MicrosoftAuthenticator login(Consumer callb public AuthInfo auth() { Objects.requireNonNull(profile); - return new AuthInfo(profile.name, authenticationToken.minecraftAccessToken, UUIDUtils.toUUID(profile.id), - Collections.emptyMap(), "mojang"); + return new AuthInfo(profile.name, session.minecraftAccessToken, UUIDUtils.toUUID(profile.id), + Collections.emptyMap(), "msa", session.xboxUserId); } /** @@ -96,8 +96,8 @@ public AuthInfo auth() { * * @return token used in authenticator */ - public AuthenticationToken getAuthenticationToken() { - return authenticationToken; + public MicrosoftSession getSession() { + return session; } /** diff --git a/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/core/MicrosoftAuthenticationController.java b/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/core/MicrosoftAuthenticationController.java index a234fe8..dd10d6c 100644 --- a/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/core/MicrosoftAuthenticationController.java +++ b/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/core/MicrosoftAuthenticationController.java @@ -4,7 +4,7 @@ import jmccc.microsoft.core.response.MicrosoftTokenResponse; import jmccc.microsoft.core.response.MinecraftLoginWithXboxResponse; import jmccc.microsoft.core.response.XboxAuthenticateResponse; -import jmccc.microsoft.entity.AuthenticationToken; +import jmccc.microsoft.entity.MicrosoftSession; import jmccc.microsoft.entity.MicrosoftVerification; import jmccc.microsoft.entity.MinecraftProfile; import org.to2mbn.jmccc.auth.AuthenticationException; @@ -20,7 +20,7 @@ public MicrosoftAuthenticationController(String clientId) { service = new MicrosoftAuthenticationService(clientId); } - public AuthenticationToken getMicrosoftToken(Consumer callback) throws AuthenticationException { + public MicrosoftSession getMicrosoftToken(Consumer callback) throws AuthenticationException { try { //Request authentication MicrosoftDeviceCodeResponse codeRes = service.getMicrosoftDeviceCode(); @@ -42,7 +42,7 @@ public AuthenticationToken getMicrosoftToken(Consumer cal } Objects.requireNonNull(tokenRes); Objects.requireNonNull(tokenRes.accessToken); - AuthenticationToken token = new AuthenticationToken(); + MicrosoftSession token = new MicrosoftSession(); token.microsoftAccessToken = tokenRes.accessToken; token.microsoftRefreshToken = tokenRes.refreshToken; return token; @@ -51,12 +51,12 @@ public AuthenticationToken getMicrosoftToken(Consumer cal } } - public AuthenticationToken refreshMicrosoftToken(AuthenticationToken microsoftToken) throws AuthenticationException { + public MicrosoftSession refreshMicrosoftToken(MicrosoftSession session) throws AuthenticationException { try { - Objects.requireNonNull(microsoftToken); - Objects.requireNonNull(microsoftToken.microsoftRefreshToken); - MicrosoftTokenResponse res = service.refreshMicrosoftToken(microsoftToken.microsoftRefreshToken); - AuthenticationToken token = new AuthenticationToken(); + Objects.requireNonNull(session); + Objects.requireNonNull(session.microsoftRefreshToken); + MicrosoftTokenResponse res = service.refreshMicrosoftToken(session.microsoftRefreshToken); + MicrosoftSession token = new MicrosoftSession(); token.microsoftAccessToken = res.accessToken; token.microsoftRefreshToken = res.refreshToken; return token; @@ -65,27 +65,29 @@ public AuthenticationToken refreshMicrosoftToken(AuthenticationToken microsoftTo } } - public AuthenticationToken getMinecraftToken(AuthenticationToken microsoftToken) throws AuthenticationException { + public MicrosoftSession getMinecraftToken(MicrosoftSession session) throws AuthenticationException { try { - Objects.requireNonNull(microsoftToken); - Objects.requireNonNull(microsoftToken.microsoftAccessToken); - XboxAuthenticateResponse xboxUserToken = service.getXboxUserToken(microsoftToken.microsoftAccessToken); - XboxAuthenticateResponse xboxXstsToken = service.getXboxXstsToken(xboxUserToken.token); + Objects.requireNonNull(session); + Objects.requireNonNull(session.microsoftAccessToken); + XboxAuthenticateResponse xboxUserToken = service.getXboxUserToken(session.microsoftAccessToken); + XboxAuthenticateResponse xboxXstsMcToken = service.getXboxXstsToken(xboxUserToken.token,"rp://api.minecraftservices.com/"); + XboxAuthenticateResponse xboxXstsToken = service.getXboxXstsToken(xboxUserToken.token, "http://xboxlive.com"); + session.xboxUserId = xboxXstsToken.displayClaims.get("xui").getAsJsonArray().get(0).getAsJsonObject().get("xid").getAsString(); - String userHash = xboxXstsToken.displayClaims.get("xui").getAsJsonArray().get(0).getAsJsonObject().get("uhs").getAsString(); - MinecraftLoginWithXboxResponse minecraftToken = service.getMinecraftToken(userHash, xboxXstsToken.token); - microsoftToken.minecraftAccessToken = minecraftToken.accessToken; - return microsoftToken; + String userHash = xboxXstsMcToken.displayClaims.get("xui").getAsJsonArray().get(0).getAsJsonObject().get("uhs").getAsString(); + MinecraftLoginWithXboxResponse minecraftToken = service.getMinecraftToken(userHash, xboxXstsMcToken.token); + session.minecraftAccessToken = minecraftToken.accessToken; + return session; } catch (Exception e) { throw new AuthenticationException(e); } } - public MinecraftProfile getMinecraftProfile(AuthenticationToken minecraftToken) throws AuthenticationException { + public MinecraftProfile getMinecraftProfile(MicrosoftSession session) throws AuthenticationException { try { - Objects.requireNonNull(minecraftToken); - Objects.requireNonNull(minecraftToken.minecraftAccessToken); - return service.getMinecraftProfile(minecraftToken.minecraftAccessToken); + Objects.requireNonNull(session); + Objects.requireNonNull(session.minecraftAccessToken); + return service.getMinecraftProfile(session.minecraftAccessToken); } catch (Exception e) { throw new AuthenticationException(e); } diff --git a/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/core/MicrosoftAuthenticationService.java b/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/core/MicrosoftAuthenticationService.java index 2f3ad5c..de7698f 100644 --- a/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/core/MicrosoftAuthenticationService.java +++ b/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/core/MicrosoftAuthenticationService.java @@ -78,9 +78,9 @@ public XboxAuthenticateResponse getXboxUserToken(String microsoftAccessToken) th .execute().handleResponse(new JsonResponseHander<>(XboxAuthenticateResponse.class)); } - public XboxAuthenticateResponse getXboxXstsToken(String xboxUserToken) throws IOException { + public XboxAuthenticateResponse getXboxXstsToken(String xboxUserToken, String relyingParty) throws IOException { XboxAuthenticateRequest req = new XboxAuthenticateRequest(); - req.relyingParty = "rp://api.minecraftservices.com/"; + req.relyingParty = relyingParty; req.properties.addProperty("SandboxId", "RETAIL"); JsonArray arr = new JsonArray(); arr.add(xboxUserToken); diff --git a/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/entity/AuthenticationToken.java b/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/entity/MicrosoftSession.java similarity index 76% rename from jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/entity/AuthenticationToken.java rename to jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/entity/MicrosoftSession.java index 1eb2db9..180c922 100644 --- a/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/entity/AuthenticationToken.java +++ b/jmccc-microsoft-authenticator/src/main/java/jmccc/microsoft/entity/MicrosoftSession.java @@ -5,7 +5,7 @@ /** * Token used in authenticator, which can be serialized and save to file */ -public class AuthenticationToken implements Serializable { +public class MicrosoftSession implements Serializable { /** * Microsoft access token */ @@ -18,4 +18,8 @@ public class AuthenticationToken implements Serializable { * Minecraft access token */ public String minecraftAccessToken; + /** + * Xbox User ID + */ + public String xboxUserId; } diff --git a/jmccc/src/main/java/org/to2mbn/jmccc/auth/AuthInfo.java b/jmccc/src/main/java/org/to2mbn/jmccc/auth/AuthInfo.java index 1706eab..11046d4 100644 --- a/jmccc/src/main/java/org/to2mbn/jmccc/auth/AuthInfo.java +++ b/jmccc/src/main/java/org/to2mbn/jmccc/auth/AuthInfo.java @@ -14,11 +14,12 @@ public class AuthInfo implements Serializable { private static final long serialVersionUID = 1L; - private String username; - private String token; - private UUID uuid; - private Map properties; - private String userType; + private final String username; + private final String token; + private final UUID uuid; + private final Map properties; + private final String userType; + private final String xboxUserId; /** * Constructs an AuthInfo. @@ -31,17 +32,34 @@ public class AuthInfo implements Serializable { * @throws NullPointerException if any of the params is null */ public AuthInfo(String username, String token, UUID uuid, Map properties, String userType) { + this(username, token, uuid, properties, userType, ""); + } + + /** + * Constructs an AuthInfo with Xbox User ID. + * + * @param username the username + * @param token the access token + * @param uuid the uuid of the login + * @param properties the properties + * @param userType the type of the login + * @param xboxUserId Xbox User ID(XUID) + * @throws NullPointerException if any of the params is null + */ + public AuthInfo(String username, String token, UUID uuid, Map properties, String userType, String xboxUserId) { Objects.requireNonNull(username); Objects.requireNonNull(token); Objects.requireNonNull(uuid); Objects.requireNonNull(properties); Objects.requireNonNull(userType); + Objects.requireNonNull(xboxUserId); this.username = username; this.token = token; this.uuid = uuid; this.properties = properties; this.userType = userType; + this.xboxUserId = xboxUserId; } /** @@ -89,6 +107,15 @@ public String getUserType() { return userType; } + /** + * Get Xbox User ID + * + * @return Xbox User ID + */ + public String getXboxUserId() { + return xboxUserId; + } + @Override public String toString() { return String.format("AuthInfo [username=%s, token=%s, uuid=%s, properties=%s, userType=%s]", username, token, uuid, properties, userType); diff --git a/jmccc/src/main/java/org/to2mbn/jmccc/launch/LauncherImpl.java b/jmccc/src/main/java/org/to2mbn/jmccc/launch/LauncherImpl.java index 7256d2d..7119ab9 100644 --- a/jmccc/src/main/java/org/to2mbn/jmccc/launch/LauncherImpl.java +++ b/jmccc/src/main/java/org/to2mbn/jmccc/launch/LauncherImpl.java @@ -15,6 +15,7 @@ import org.to2mbn.jmccc.version.parsing.Versions; import java.io.*; +import java.nio.file.Files; import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -137,6 +138,7 @@ private LaunchArgument generateLaunchArgs(LaunchOption option) throws LaunchExce tokens.put("launcher_version", "3.0"); tokens.put("library_directory", mcdir.getLibraries().getAbsolutePath()); tokens.put("classpath_separator", Platform.getPathSeparator()); + tokens.put("auth_xuid", auth.getXboxUserId()); String type = version.getType(); if (type != null) { @@ -163,7 +165,7 @@ private void decompressZipWithExcludes(File zip, File outputDir, Set exc if (!outputDir.exists()) outputDir.mkdirs(); - try (ZipInputStream in = new ZipInputStream(new FileInputStream(zip))) { + try (ZipInputStream in = new ZipInputStream(Files.newInputStream(zip.toPath()))) { ZipEntry entry; byte[] buf = null; @@ -200,7 +202,7 @@ private void decompressZipWithExcludes(File zip, File outputDir, Set exc // same length, check the content match = true; if (!nativeFastCheck) { - try (InputStream targetin = new BufferedInputStream(new FileInputStream(outFile))) { + try (InputStream targetin = new BufferedInputStream(Files.newInputStream(outFile.toPath()))) { for (int i = 0; i < len; i++) { if (buf[i] != (byte) targetin.read()) { match = false; @@ -218,7 +220,7 @@ private void decompressZipWithExcludes(File zip, File outputDir, Set exc if (entry.isDirectory()) { outFile.mkdir();//Fix extract directory as file } else { - try (OutputStream out = new FileOutputStream(outFile)) { + try (OutputStream out = Files.newOutputStream(outFile.toPath())) { out.write(buf, 0, len); } } diff --git a/jmccc/src/main/java/org/to2mbn/jmccc/util/UUIDUtils.java b/jmccc/src/main/java/org/to2mbn/jmccc/util/UUIDUtils.java index e8bed5b..c3b9069 100644 --- a/jmccc/src/main/java/org/to2mbn/jmccc/util/UUIDUtils.java +++ b/jmccc/src/main/java/org/to2mbn/jmccc/util/UUIDUtils.java @@ -1,5 +1,6 @@ package org.to2mbn.jmccc.util; +import java.util.Base64; import java.util.UUID; public final class UUIDUtils { @@ -32,4 +33,8 @@ public static String randomUnsignedUUID() { return unsign(UUID.randomUUID()); } + public static String randomUnsignedUuidBase64() { + return Base64.getEncoder().encodeToString(randomUnsignedUUID().toUpperCase().getBytes()); + } + }