Skip to content

Commit

Permalink
feat(microsoft): ctrl + click the Microsoft button to choose account (
Browse files Browse the repository at this point in the history
closes #46) (#84)
  • Loading branch information
axieum committed Jun 7, 2023
1 parent e606c2a commit d63c490
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 7 deletions.
55 changes: 53 additions & 2 deletions src/main/java/me/axieum/mcmod/authme/api/util/MicrosoftUtils.java
Expand Up @@ -93,6 +93,30 @@ public static CompletableFuture<String> acquireMSAuthCode(
return acquireMSAuthCode(url -> Util.getOperatingSystem().open(url), browserMessage, executor);
}

/**
* Navigates to the Microsoft login with user interaction, and listens for
* a successful login callback.
*
* <p>NB: You must manually interrupt the executor thread if the
* completable future is cancelled!
*
* @param browserMessage function that takes true if success, and returns
* a message to be shown in the browser after
* logging in
* @param executor executor to run the login task on
* @param prompt optional Microsoft interaction prompt override
* @return completable future for the Microsoft auth token
* @see #acquireMSAuthCode(Consumer, Function, Executor)
*/
public static CompletableFuture<String> acquireMSAuthCode(
final Function<Boolean, @NotNull String> browserMessage,
final Executor executor,
final @Nullable MicrosoftPrompt prompt
)
{
return acquireMSAuthCode(url -> Util.getOperatingSystem().open(url), browserMessage, executor, prompt);
}

/**
* Generates a Microsoft login link, triggers the given browser action, and
* listens for a successful login callback.
Expand All @@ -112,6 +136,31 @@ public static CompletableFuture<String> acquireMSAuthCode(
final Function<Boolean, @NotNull String> browserMessage,
final Executor executor
)
{
return acquireMSAuthCode(browserAction, browserMessage, executor, null);
}

/**
* Generates a Microsoft login link with user interaction, triggers the
* given browser action, and listens for a successful login callback.
*
* <p>NB: You must manually interrupt the executor thread if the
* completable future is cancelled!
*
* @param browserAction consumer that opens the generated login url
* @param browserMessage function that takes true if success, and returns
* a message to be shown in the browser after
* logging in
* @param executor executor to run the login task on
* @param prompt optional Microsoft interaction prompt override
* @return completable future for the Microsoft auth token
*/
public static CompletableFuture<String> acquireMSAuthCode(
final Consumer<URI> browserAction,
final Function<Boolean, @NotNull String> browserMessage,
final Executor executor,
final @Nullable MicrosoftPrompt prompt
)
{
return CompletableFuture.supplyAsync(() -> {
LOGGER.info("Acquiring Microsoft auth code...");
Expand Down Expand Up @@ -168,8 +217,10 @@ public static CompletableFuture<String> acquireMSAuthCode(
)
.addParameter("scope", "XboxLive.signin offline_access")
.addParameter("state", state);
if (getConfig().methods.microsoft.prompt != MicrosoftPrompt.DEFAULT) {
uriBuilder.addParameter("prompt", getConfig().methods.microsoft.prompt.toString());
if (prompt != null || getConfig().methods.microsoft.prompt != MicrosoftPrompt.DEFAULT) {
uriBuilder.addParameter(
"prompt", (prompt != null ? prompt : getConfig().methods.microsoft.prompt).toString()
);
}
final URI uri = uriBuilder.build();

Expand Down
Expand Up @@ -5,6 +5,7 @@
import net.minecraft.client.gui.tooltip.Tooltip;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.client.gui.widget.TexturedButtonWidget;
import net.minecraft.client.util.InputUtil;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
Expand Down Expand Up @@ -52,12 +53,16 @@ protected void init()
width / 2 - 20 - 10 - 4, height / 2 - 5, 20, 20,
0, 0, 20, WIDGETS_TEXTURE, 128, 128,
button -> {
// If 'Left Control' is being held, enforce user interaction
final boolean selectAccount = InputUtil.isKeyPressed(
client.getWindow().getHandle(), InputUtil.GLFW_KEY_LEFT_CONTROL
);
if (getConfig().methods.microsoft.isDefaults()) {
client.setScreen(new MicrosoftAuthScreen(this, parentScreen));
client.setScreen(new MicrosoftAuthScreen(this, parentScreen, selectAccount));
} else {
AuthMe.LOGGER.warn("Non-default Microsoft authentication URLs are in use!");
ConfirmScreen confirmScreen = new ConfirmScreen(
accepted -> client.setScreen(accepted ? new MicrosoftAuthScreen(this, parentScreen) : this),
a -> client.setScreen(a ? new MicrosoftAuthScreen(this, parentScreen, selectAccount) : this),
Text.translatable("gui.authme.microsoft.warning.title"),
Text.translatable("gui.authme.microsoft.warning.body"),
Text.translatable("gui.authme.microsoft.warning.accept"),
Expand All @@ -69,7 +74,13 @@ protected void init()
},
Text.translatable("gui.authme.method.button.microsoft")
);
msButton.setTooltip(Tooltip.of(Text.translatable("gui.authme.method.button.microsoft")));
msButton.setTooltip(Tooltip.of(
Text.translatable("gui.authme.method.button.microsoft")
.append("\n")
.append(
Text.translatable("gui.authme.method.button.microsoft.selectAccount").formatted(Formatting.GRAY)
)
));
addDrawableChild(msButton);

// Add a button for the 'Mojang (or legacy)' authentication method
Expand Down
Expand Up @@ -29,16 +29,20 @@ public class MicrosoftAuthScreen extends AuthScreen
private CompletableFuture<Void> task = null;
// The current progress/status of the login task
private Text status = null;
// True if Microsoft should prompt to select an account
private final boolean selectAccount;

/**
* Constructs a new authentication via Microsoft screen.
*
* @param parentScreen parent (or last) screen that opened this screen
* @param successScreen screen to be returned to after a successful login
* @param selectAccount true if Microsoft should prompt to select an account
*/
public MicrosoftAuthScreen(Screen parentScreen, Screen successScreen)
public MicrosoftAuthScreen(Screen parentScreen, Screen successScreen, boolean selectAccount)
{
super(Text.translatable("gui.authme.microsoft.title"), parentScreen, successScreen);
this.selectAccount = selectAccount;
this.closeOnSuccess = true;
}

Expand Down Expand Up @@ -71,7 +75,11 @@ protected void init()
// Start the login task
task = MicrosoftUtils
// Acquire a Microsoft auth code
.acquireMSAuthCode(success -> Text.translatable("gui.authme.microsoft.browser").getString(), executor)
.acquireMSAuthCode(
success -> Text.translatable("gui.authme.microsoft.browser").getString(),
executor,
selectAccount ? MicrosoftUtils.MicrosoftPrompt.SELECT_ACCOUNT : null
)

// Exchange the Microsoft auth code for an access token
.thenComposeAsync(msAuthCode -> {
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/assets/authme/lang/en_us.json
Expand Up @@ -12,6 +12,7 @@
"gui.authme.method.title": "Pick a login method",
"gui.authme.method.greeting": "Hello, %s!",
"gui.authme.method.button.microsoft": "Microsoft",
"gui.authme.method.button.microsoft.selectAccount": "Ctrl + click to choose account",
"gui.authme.method.button.mojang": "Mojang (or legacy)",
"gui.authme.method.button.offline": "Offline",

Expand Down

0 comments on commit d63c490

Please sign in to comment.