feat: MicrosoftAccount: find skin by uuid instead of fetching profile.

This commit is contained in:
huanghongxun 2021-09-04 02:07:58 +08:00
parent bb15d72032
commit 72ca0f20a1
2 changed files with 57 additions and 13 deletions

View File

@ -21,14 +21,17 @@ import javafx.beans.binding.ObjectBinding;
import org.jackhuang.hmcl.auth.*;
import org.jackhuang.hmcl.auth.yggdrasil.Texture;
import org.jackhuang.hmcl.auth.yggdrasil.TextureType;
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilService;
import org.jackhuang.hmcl.util.javafx.BindingMapping;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.UUID;
import java.util.logging.Level;
import static java.util.Objects.requireNonNull;
import static org.jackhuang.hmcl.util.Logging.LOG;
public class MicrosoftAccount extends Account {
@ -77,7 +80,7 @@ public class MicrosoftAccount extends Account {
@Override
public AuthInfo logIn() throws AuthenticationException {
if (!authenticated) {
if (service.validate(session.getTokenType(), session.getAccessToken())) {
if (service.validate(session.getNotAfter(), session.getTokenType(), session.getAccessToken())) {
authenticated = true;
} else {
MicrosoftSession acquiredSession = service.refresh(session);
@ -116,9 +119,15 @@ public class MicrosoftAccount extends Account {
@Override
public ObjectBinding<Optional<Map<TextureType, Texture>>> getTextures() {
return BindingMapping.of(service.getProfileRepository().binding(session.getAuthorization()))
.map(profile -> profile.flatMap(MicrosoftService::getTextures));
return BindingMapping.of(service.getProfileRepository().binding(getUUID()))
.map(profile -> profile.flatMap(it -> {
try {
return YggdrasilService.getTextures(it);
} catch (ServerResponseMalformedException e) {
LOG.log(Level.WARNING, "Failed to parse texture payload", e);
return Optional.empty();
}
}));
}
@Override

View File

@ -17,15 +17,16 @@
*/
package org.jackhuang.hmcl.auth.microsoft;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import com.google.gson.annotations.SerializedName;
import org.jackhuang.hmcl.auth.*;
import org.jackhuang.hmcl.auth.yggdrasil.CompleteGameProfile;
import org.jackhuang.hmcl.auth.yggdrasil.RemoteAuthenticationException;
import org.jackhuang.hmcl.auth.yggdrasil.Texture;
import org.jackhuang.hmcl.auth.yggdrasil.TextureType;
import org.jackhuang.hmcl.util.gson.JsonUtils;
import org.jackhuang.hmcl.util.gson.TolerableValidationException;
import org.jackhuang.hmcl.util.gson.Validation;
import org.jackhuang.hmcl.util.gson.*;
import org.jackhuang.hmcl.util.io.HttpRequest;
import org.jackhuang.hmcl.util.io.NetworkUtils;
import org.jackhuang.hmcl.util.io.ResponseCodeException;
@ -60,17 +61,17 @@ public class MicrosoftService {
private final OAuthCallback callback;
private final ObservableOptionalCache<String, MinecraftProfileResponse, AuthenticationException> profileRepository;
private final ObservableOptionalCache<UUID, CompleteGameProfile, AuthenticationException> profileRepository;
public MicrosoftService(OAuthCallback callback) {
this.callback = requireNonNull(callback);
this.profileRepository = new ObservableOptionalCache<>(authorization -> {
LOG.info("Fetching properties");
return getCompleteProfile(authorization);
this.profileRepository = new ObservableOptionalCache<>(uuid -> {
LOG.info("Fetching properties of " + uuid);
return getCompleteGameProfile(uuid);
}, (uuid, e) -> LOG.log(Level.WARNING, "Failed to fetch properties of " + uuid, e), POOL);
}
public ObservableOptionalCache<String, MinecraftProfileResponse, AuthenticationException> getProfileRepository() {
public ObservableOptionalCache<UUID, CompleteGameProfile, AuthenticationException> getProfileRepository() {
return profileRepository;
}
@ -213,10 +214,14 @@ public class MicrosoftService {
}
}
public boolean validate(String tokenType, String accessToken) throws AuthenticationException {
public boolean validate(long notAfter, String tokenType, String accessToken) throws AuthenticationException {
requireNonNull(tokenType);
requireNonNull(accessToken);
if (System.currentTimeMillis() > notAfter) {
return false;
}
try {
getMinecraftProfile(tokenType, accessToken);
return true;
@ -275,6 +280,31 @@ public class MicrosoftService {
return JsonUtils.fromNonNullJson(result, MinecraftProfileResponse.class);
}
public Optional<CompleteGameProfile> getCompleteGameProfile(UUID uuid) throws AuthenticationException {
Objects.requireNonNull(uuid);
return Optional.ofNullable(GSON.fromJson(request(NetworkUtils.toURL("https://sessionserver.mojang.com/session/minecraft/profile/" + UUIDTypeAdapter.fromUUID(uuid)), null), CompleteGameProfile.class));
}
private static String request(URL url, Object payload) throws AuthenticationException {
try {
if (payload == null)
return NetworkUtils.doGet(url);
else
return NetworkUtils.doPost(url, payload instanceof String ? (String) payload : GSON.toJson(payload), "application/json");
} catch (IOException e) {
throw new ServerDisconnectException(e);
}
}
private static <T> T fromJson(String text, Class<T> typeOfT) throws ServerResponseMalformedException {
try {
return GSON.fromJson(text, typeOfT);
} catch (JsonParseException e) {
throw new ServerResponseMalformedException(text, e);
}
}
public static class XboxAuthorizationException extends AuthenticationException {
private final long errorCode;
@ -487,4 +517,9 @@ public class MicrosoftService {
String waitFor() throws InterruptedException, ExecutionException;
}
private static final Gson GSON = new GsonBuilder()
.registerTypeAdapter(UUID.class, UUIDTypeAdapter.INSTANCE)
.registerTypeAdapterFactory(ValidationTypeAdapterFactory.INSTANCE)
.create();
}