feat(microsoft): WIP: handle credentials expiration.
This commit is contained in:
@@ -20,8 +20,9 @@ package org.jackhuang.hmcl.ui;
|
|||||||
import org.jackhuang.hmcl.auth.Account;
|
import org.jackhuang.hmcl.auth.Account;
|
||||||
import org.jackhuang.hmcl.auth.AuthInfo;
|
import org.jackhuang.hmcl.auth.AuthInfo;
|
||||||
import org.jackhuang.hmcl.auth.AuthenticationException;
|
import org.jackhuang.hmcl.auth.AuthenticationException;
|
||||||
|
import org.jackhuang.hmcl.auth.microsoft.MicrosoftAccount;
|
||||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
||||||
import org.jackhuang.hmcl.ui.account.AccountLoginPane;
|
import org.jackhuang.hmcl.ui.account.AccountLoginWithPasswordDialog;
|
||||||
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
@@ -39,7 +40,7 @@ public final class DialogController {
|
|||||||
CountDownLatch latch = new CountDownLatch(1);
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
AtomicReference<AuthInfo> res = new AtomicReference<>(null);
|
AtomicReference<AuthInfo> res = new AtomicReference<>(null);
|
||||||
runInFX(() -> {
|
runInFX(() -> {
|
||||||
AccountLoginPane pane = new AccountLoginPane(account, it -> {
|
AccountLoginWithPasswordDialog pane = new AccountLoginWithPasswordDialog(account, it -> {
|
||||||
res.set(it);
|
res.set(it);
|
||||||
latch.countDown();
|
latch.countDown();
|
||||||
}, latch::countDown);
|
}, latch::countDown);
|
||||||
@@ -47,6 +48,8 @@ public final class DialogController {
|
|||||||
});
|
});
|
||||||
latch.await();
|
latch.await();
|
||||||
return Optional.ofNullable(res.get()).orElseThrow(CancellationException::new);
|
return Optional.ofNullable(res.get()).orElseThrow(CancellationException::new);
|
||||||
|
} else if (account instanceof MicrosoftAccount) {
|
||||||
|
|
||||||
}
|
}
|
||||||
return account.logIn();
|
return account.logIn();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed;
|
|||||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||||
|
|
||||||
public class AccountLoginPane extends StackPane {
|
public class AccountLoginWithPasswordDialog extends StackPane {
|
||||||
private final Account oldAccount;
|
private final Account oldAccount;
|
||||||
private final Consumer<AuthInfo> success;
|
private final Consumer<AuthInfo> success;
|
||||||
private final Runnable failed;
|
private final Runnable failed;
|
||||||
@@ -57,7 +57,7 @@ public class AccountLoginPane extends StackPane {
|
|||||||
private final Label lblCreationWarning = new Label();
|
private final Label lblCreationWarning = new Label();
|
||||||
private final JFXProgressBar progressBar;
|
private final JFXProgressBar progressBar;
|
||||||
|
|
||||||
public AccountLoginPane(Account oldAccount, Consumer<AuthInfo> success, Runnable failed) {
|
public AccountLoginWithPasswordDialog(Account oldAccount, Consumer<AuthInfo> success, Runnable failed) {
|
||||||
this.oldAccount = oldAccount;
|
this.oldAccount = oldAccount;
|
||||||
this.success = success;
|
this.success = success;
|
||||||
this.failed = failed;
|
this.failed = failed;
|
||||||
@@ -100,7 +100,17 @@ public class MicrosoftAccount extends Account {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AuthInfo logInWithPassword(String password) throws AuthenticationException {
|
public AuthInfo logInWithPassword(String password) throws AuthenticationException {
|
||||||
throw new UnsupportedOperationException();
|
MicrosoftSession acquiredSession = service.authenticate();
|
||||||
|
|
||||||
|
if (acquiredSession.getProfile() == null) {
|
||||||
|
session = service.refresh(acquiredSession);
|
||||||
|
} else {
|
||||||
|
session = acquiredSession;
|
||||||
|
}
|
||||||
|
|
||||||
|
authenticated = true;
|
||||||
|
invalidate();
|
||||||
|
return session.toAuthInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -119,7 +119,12 @@ public class MicrosoftService {
|
|||||||
pair("client_secret", callback.getClientSecret()),
|
pair("client_secret", callback.getClientSecret()),
|
||||||
pair("refresh_token", oldSession.getRefreshToken()),
|
pair("refresh_token", oldSession.getRefreshToken()),
|
||||||
pair("grant_type", "refresh_token"))
|
pair("grant_type", "refresh_token"))
|
||||||
.accept("application/json").getJson(LiveRefreshResponse.class);
|
.accept("application/json")
|
||||||
|
.ignoreHttpErrorCode(400)
|
||||||
|
.ignoreHttpErrorCode(401)
|
||||||
|
.getJson(LiveRefreshResponse.class);
|
||||||
|
|
||||||
|
handleLiveErrorMessage(response);
|
||||||
|
|
||||||
return authenticateViaLiveAccessToken(response.accessToken, response.refreshToken);
|
return authenticateViaLiveAccessToken(response.accessToken, response.refreshToken);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -129,6 +134,22 @@ public class MicrosoftService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleLiveErrorMessage(LiveErrorResponse response) throws AuthenticationException {
|
||||||
|
if (response.error == null || response.errorDescription == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (response.error) {
|
||||||
|
case "invalid_grant":
|
||||||
|
if (response.errorDescription.contains("The user must sign in again and if needed grant the client application access to the requested scope")) {
|
||||||
|
throw new CredentialExpiredException();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RemoteAuthenticationException(response.error, response.errorDescription, "");
|
||||||
|
}
|
||||||
|
|
||||||
private String getUhs(XBoxLiveAuthenticationResponse response, String existingUhs) throws AuthenticationException {
|
private String getUhs(XBoxLiveAuthenticationResponse response, String existingUhs) throws AuthenticationException {
|
||||||
if (response.errorCode != 0) {
|
if (response.errorCode != 0) {
|
||||||
throw new XboxAuthorizationException(response.errorCode, response.redirectUrl);
|
throw new XboxAuthorizationException(response.errorCode, response.redirectUrl);
|
||||||
@@ -336,13 +357,24 @@ public class MicrosoftService {
|
|||||||
public static class NoXuiException extends AuthenticationException {
|
public static class NoXuiException extends AuthenticationException {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class LiveErrorResponse {
|
||||||
|
@SerializedName("error")
|
||||||
|
public String error;
|
||||||
|
|
||||||
|
@SerializedName("error_description")
|
||||||
|
public String errorDescription;
|
||||||
|
|
||||||
|
@SerializedName("correlation_id")
|
||||||
|
public String correlationId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Error response: {"error":"invalid_grant","error_description":"The provided
|
* Error response: {"error":"invalid_grant","error_description":"The provided
|
||||||
* value for the 'redirect_uri' is not valid. The value must exactly match the
|
* value for the 'redirect_uri' is not valid. The value must exactly match the
|
||||||
* redirect URI used to obtain the authorization
|
* redirect URI used to obtain the authorization
|
||||||
* code.","correlation_id":"??????"}
|
* code.","correlation_id":"??????"}
|
||||||
*/
|
*/
|
||||||
public static class LiveAuthorizationResponse {
|
public static class LiveAuthorizationResponse extends LiveErrorResponse {
|
||||||
@SerializedName("token_type")
|
@SerializedName("token_type")
|
||||||
public String tokenType;
|
public String tokenType;
|
||||||
|
|
||||||
@@ -365,7 +397,7 @@ public class MicrosoftService {
|
|||||||
public String foci;
|
public String foci;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class LiveRefreshResponse {
|
private static class LiveRefreshResponse extends LiveErrorResponse {
|
||||||
@SerializedName("expires_in")
|
@SerializedName("expires_in")
|
||||||
int expiresIn;
|
int expiresIn;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user