Implement Microsoft account login (#1397)

* Implement Microsoft account login
* Create proxied web request class
* Whole bunch of code that doesn't work
* I finally FIXED IT
It took me 2 hours to resolve the problem
* Fill the missed method summary
* Remove some unused code
* Revert http version
* Remove JSON parsing bug workaround
Not needed anymore as per e06438b582
* Remove comment asking about clientID
Client ID is used for session token refreshes. Random UUID without hyphens
Co-authored-by: ORelio <ORelio@users.noreply.github.com>
This commit is contained in:
ReinforceZwei 2021-01-07 04:14:51 +08:00 committed by GitHub
parent 479f80ccf1
commit c04c597aba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 690 additions and 4 deletions

View file

@ -328,6 +328,7 @@ namespace MinecraftClient.Protocol
}
public enum LoginResult { OtherError, ServiceUnavailable, SSLError, Success, WrongPassword, AccountMigrated, NotPremium, LoginRequired, InvalidToken, InvalidResponse, NullError };
public enum AccountType { Mojang, Microsoft };
/// <summary>
/// Allows to login to a premium Minecraft account using the Yggdrasil authentication scheme.
@ -336,7 +337,20 @@ namespace MinecraftClient.Protocol
/// <param name="pass">Password</param>
/// <param name="session">In case of successful login, will contain session information for multiplayer</param>
/// <returns>Returns the status of the login (Success, Failure, etc.)</returns>
public static LoginResult GetLogin(string user, string pass, out SessionToken session)
public static LoginResult GetLogin(string user, string pass, AccountType type, out SessionToken session)
{
if (type == AccountType.Microsoft)
{
return MicrosoftLogin(user, pass, out session);
}
else if (type == AccountType.Mojang)
{
return MojangLogin(user, pass, out session);
}
else throw new InvalidOperationException("Account type must be Mojang or Microsoft");
}
private static LoginResult MojangLogin(string user, string pass, out SessionToken session)
{
session = new SessionToken() { ClientID = Guid.NewGuid().ToString().Replace("-", "") };
@ -415,6 +429,44 @@ namespace MinecraftClient.Protocol
}
}
private static LoginResult MicrosoftLogin(string email, string password, out SessionToken session)
{
session = new SessionToken() { ClientID = Guid.NewGuid().ToString().Replace("-", "") };
var ms = new XboxLive();
var mc = new MinecraftWithXbox();
try
{
var msaResponse = ms.UserLogin(email, password, ms.PreAuth());
var xblResponse = ms.XblAuthenticate(msaResponse);
var xsts = ms.XSTSAuthenticate(xblResponse); // Might throw even password correct
string accessToken = mc.LoginWithXbox(xsts.UserHash, xsts.Token);
bool hasGame = mc.UserHasGame(accessToken);
if (hasGame)
{
var profile = mc.GetUserProfile(accessToken);
session.PlayerName = profile.UserName;
session.PlayerID = profile.UUID;
session.ID = accessToken;
return LoginResult.Success;
}
else
{
return LoginResult.NotPremium;
}
}
catch (Exception e)
{
ConsoleIO.WriteLineFormatted("§cMicrosoft authenticate failed: " + e.Message);
if (Settings.DebugMessages)
{
ConsoleIO.WriteLineFormatted("§c" + e.StackTrace);
}
return LoginResult.WrongPassword; // Might not always be wrong password
}
}
/// <summary>
/// Validates whether accessToken must be refreshed
/// </summary>