mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2024-11-27 06:10:08 +08:00
HMCLCore authlib injector support
This commit is contained in:
parent
bfed651263
commit
83bc6748a3
@ -121,11 +121,11 @@ public final class Main extends Application {
|
||||
}
|
||||
|
||||
public static final File MINECRAFT_DIRECTORY = getWorkingDirectory("minecraft");
|
||||
public static final File HMCL_DIRECTORY = getWorkingDirectory("hmcl");
|
||||
|
||||
public static final String VERSION = "@HELLO_MINECRAFT_LAUNCHER_VERSION_FOR_GRADLE_REPLACING@";
|
||||
public static final String NAME = "HMCL";
|
||||
public static final String TITLE = NAME + " " + VERSION;
|
||||
public static final File APPDATA = getWorkingDirectory("hmcl");
|
||||
public static final ResourceBundle RESOURCE_BUNDLE = Settings.INSTANCE.getLocale().getResourceBundle();
|
||||
public static final UpdateChecker UPDATE_CHECKER = new UpdateChecker(VersionNumber.asVersion(VERSION));
|
||||
public static final CrashReporter CRASH_REPORTER = new CrashReporter();
|
||||
|
@ -21,6 +21,7 @@ import com.google.gson.JsonParseException;
|
||||
import org.jackhuang.hmcl.mod.Modpack;
|
||||
import org.jackhuang.hmcl.util.CompressingUtils;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
import java.io.File;
|
||||
@ -81,13 +82,9 @@ public final class HMCLModpackManager {
|
||||
*/
|
||||
public static Modpack readHMCLModpackManifest(File file) throws IOException, JsonParseException {
|
||||
String manifestJson = CompressingUtils.readTextZipEntry(file, "modpack.json");
|
||||
Modpack manifest = Constants.GSON.fromJson(manifestJson, Modpack.class);
|
||||
if (manifest == null)
|
||||
throw new JsonParseException("`modpack.json` not found. " + file + " is not a valid HMCL modpack.");
|
||||
Modpack manifest = Lang.requireJsonNonNull(Constants.GSON.fromJson(manifestJson, Modpack.class));
|
||||
String gameJson = CompressingUtils.readTextZipEntry(file, "minecraft/pack.json");
|
||||
Version game = Constants.GSON.fromJson(gameJson, Version.class);
|
||||
if (game == null)
|
||||
throw new JsonParseException("`minecraft/pack.json` not found. " + file + " iot a valid HMCL modpack.");
|
||||
Version game = Lang.requireJsonNonNull(Constants.GSON.fromJson(gameJson, Version.class));
|
||||
if (game.getJar() == null)
|
||||
if (StringUtils.isBlank(manifest.getVersion()))
|
||||
throw new JsonParseException("Cannot recognize the game version of modpack " + file + ".");
|
||||
|
@ -17,15 +17,19 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.setting;
|
||||
|
||||
import org.jackhuang.hmcl.Main;
|
||||
import org.jackhuang.hmcl.auth.Account;
|
||||
import org.jackhuang.hmcl.auth.AccountFactory;
|
||||
import org.jackhuang.hmcl.auth.OfflineAccount;
|
||||
import org.jackhuang.hmcl.auth.OfflineAccountFactory;
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount;
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccountFactory;
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.*;
|
||||
import org.jackhuang.hmcl.task.FileDownloadTask;
|
||||
import org.jackhuang.hmcl.util.FileUtils;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.Pair;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URL;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@ -37,14 +41,17 @@ public final class Accounts {
|
||||
|
||||
public static final String OFFLINE_ACCOUNT_KEY = "offline";
|
||||
public static final String YGGDRASIL_ACCOUNT_KEY = "yggdrasil";
|
||||
public static final String AUTHLIB_INJECTOR_ACCOUNT_KEY = "authlibInjector";
|
||||
|
||||
public static final Map<String, AccountFactory<?>> ACCOUNT_FACTORY = Lang.mapOf(
|
||||
new Pair<>(OFFLINE_ACCOUNT_KEY, OfflineAccountFactory.INSTANCE),
|
||||
new Pair<>(YGGDRASIL_ACCOUNT_KEY, YggdrasilAccountFactory.INSTANCE)
|
||||
new Pair<>(YGGDRASIL_ACCOUNT_KEY, new YggdrasilAccountFactory()),
|
||||
new Pair<>(AUTHLIB_INJECTOR_ACCOUNT_KEY, new AuthlibInjectorAccountFactory(Accounts::downloadAuthlibInjector))
|
||||
);
|
||||
|
||||
public static String getAccountType(Account account) {
|
||||
if (account instanceof OfflineAccount) return OFFLINE_ACCOUNT_KEY;
|
||||
else if (account instanceof AuthlibInjectorAccount) return AUTHLIB_INJECTOR_ACCOUNT_KEY;
|
||||
else if (account instanceof YggdrasilAccount) return YGGDRASIL_ACCOUNT_KEY;
|
||||
else return YGGDRASIL_ACCOUNT_KEY;
|
||||
}
|
||||
@ -75,4 +82,16 @@ public final class Accounts {
|
||||
static String getAccountId(String username, String character) {
|
||||
return username + ":" + character;
|
||||
}
|
||||
|
||||
private static String downloadAuthlibInjector() throws Exception {
|
||||
AuthlibInjectorBuildInfo buildInfo = AuthlibInjectorBuildInfo.requestBuildInfo();
|
||||
File jar = new File(Main.HMCL_DIRECTORY, "authlib-injector.jar");
|
||||
File local = new File(Main.HMCL_DIRECTORY, "authlib-injector.txt");
|
||||
int buildNumber = Integer.parseInt(FileUtils.readText(local));
|
||||
if (buildNumber < buildInfo.getBuildNumber()) {
|
||||
new FileDownloadTask(new URL(buildInfo.getUrl()), jar).run();
|
||||
FileUtils.writeText(local, String.valueOf(buildInfo.getBuildNumber()));
|
||||
}
|
||||
return jar.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package org.jackhuang.hmcl.setting;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import org.jackhuang.hmcl.Main;
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.AuthlibInjectorBuildInfo;
|
||||
import org.jackhuang.hmcl.util.JavaVersion;
|
||||
|
||||
import java.util.LinkedList;
|
||||
@ -91,6 +92,9 @@ public final class Config {
|
||||
@SerializedName("logLines")
|
||||
private int logLines = 100;
|
||||
|
||||
@SerializedName("authlibInjectorServerURL")
|
||||
private String authlibInjectorServerURL = AuthlibInjectorBuildInfo.UPDATE_URL;
|
||||
|
||||
public String getSelectedProfile() {
|
||||
return selectedProfile;
|
||||
}
|
||||
@ -278,4 +282,18 @@ public final class Config {
|
||||
public void setLogLines(int logLines) {
|
||||
this.logLines = logLines;
|
||||
}
|
||||
|
||||
public String getAuthlibInjectorServerURL() {
|
||||
return authlibInjectorServerURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will not invoke Settings.INSTANCE.save()
|
||||
* @param authlibInjectorServerURL new server url.
|
||||
*/
|
||||
public void setAuthlibInjectorServerURL(String authlibInjectorServerURL) {
|
||||
this.authlibInjectorServerURL = authlibInjectorServerURL;
|
||||
// Do not invoke Settings.INSTANCE.save()
|
||||
// Because we want users set it theirself.
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import javafx.scene.text.Font;
|
||||
import org.jackhuang.hmcl.Main;
|
||||
import org.jackhuang.hmcl.auth.Account;
|
||||
import org.jackhuang.hmcl.auth.AccountFactory;
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.AuthlibInjectorBuildInfo;
|
||||
import org.jackhuang.hmcl.download.BMCLAPIDownloadProvider;
|
||||
import org.jackhuang.hmcl.download.DownloadProvider;
|
||||
import org.jackhuang.hmcl.download.MojangDownloadProvider;
|
||||
@ -39,10 +40,7 @@ import org.jackhuang.hmcl.util.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.Authenticator;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.PasswordAuthentication;
|
||||
import java.net.Proxy;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
@ -106,6 +104,13 @@ public class Settings {
|
||||
});
|
||||
|
||||
loadProxy();
|
||||
|
||||
try {
|
||||
new URL(SETTINGS.getAuthlibInjectorServerURL());
|
||||
} catch (MalformedURLException ex) {
|
||||
Logging.LOG.log(Level.SEVERE, "Authlib injector server URL is malformed, using official update url.", ex);
|
||||
SETTINGS.setAuthlibInjectorServerURL(AuthlibInjectorBuildInfo.UPDATE_URL);
|
||||
}
|
||||
}
|
||||
|
||||
private Config initSettings() {
|
||||
@ -275,6 +280,10 @@ public class Settings {
|
||||
SETTINGS.setLogLines(logLines);
|
||||
}
|
||||
|
||||
public String getAuthlibInjectorServerURL() {
|
||||
return SETTINGS.getAuthlibInjectorServerURL();
|
||||
}
|
||||
|
||||
public DownloadProvider getDownloadProvider() {
|
||||
switch (SETTINGS.getDownloadType()) {
|
||||
case 0:
|
||||
|
@ -154,7 +154,7 @@ public class AppDataUpgrader extends IUpgrader {
|
||||
|
||||
public static class AppDataUpgraderPackGzTask extends Task {
|
||||
|
||||
public static final File BASE_FOLDER = Main.getWorkingDirectory("hmcl");
|
||||
public static final File BASE_FOLDER = Main.HMCL_DIRECTORY;
|
||||
public static final File HMCL_VER_FILE = new File(BASE_FOLDER, "hmclver.json");
|
||||
|
||||
public static File getSelf(String ver) {
|
||||
|
@ -28,10 +28,14 @@ import java.util.Map;
|
||||
public abstract class AccountFactory<T extends Account> {
|
||||
|
||||
public final T fromUsername(String username) {
|
||||
return fromUsername(username, "");
|
||||
return fromUsername(username, "", null);
|
||||
}
|
||||
|
||||
public abstract T fromUsername(String username, String password);
|
||||
public final T fromUsername(String username, String password) {
|
||||
return fromUsername(username, password, null);
|
||||
}
|
||||
|
||||
public abstract T fromUsername(String username, String password, Object additionalData);
|
||||
|
||||
protected abstract T fromStorageImpl(Map<Object, Object> storage);
|
||||
|
||||
|
@ -18,12 +18,15 @@
|
||||
package org.jackhuang.hmcl.auth;
|
||||
|
||||
import org.jackhuang.hmcl.auth.yggdrasil.GameProfile;
|
||||
import org.jackhuang.hmcl.game.Arguments;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
@Immutable
|
||||
public final class AuthInfo {
|
||||
|
||||
private final String username;
|
||||
@ -32,6 +35,7 @@ public final class AuthInfo {
|
||||
private final UserType userType;
|
||||
private final String userProperties;
|
||||
private final String userPropertyMap;
|
||||
private final Arguments arguments;
|
||||
|
||||
public AuthInfo(String username, String userId, String authToken) {
|
||||
this(username, userId, authToken, UserType.LEGACY);
|
||||
@ -46,12 +50,17 @@ public final class AuthInfo {
|
||||
}
|
||||
|
||||
public AuthInfo(String username, String userId, String authToken, UserType userType, String userProperties, String userPropertyMap) {
|
||||
this(username, userId, authToken, userType, userProperties, userPropertyMap, null);
|
||||
}
|
||||
|
||||
public AuthInfo(String username, String userId, String authToken, UserType userType, String userProperties, String userPropertyMap, Arguments arguments) {
|
||||
this.username = username;
|
||||
this.userId = userId;
|
||||
this.authToken = authToken;
|
||||
this.userType = userType;
|
||||
this.userProperties = userProperties;
|
||||
this.userPropertyMap = userPropertyMap;
|
||||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
public AuthInfo(GameProfile profile, String authToken, UserType userType, String userProperties) {
|
||||
@ -93,4 +102,12 @@ public final class AuthInfo {
|
||||
public String getUserPropertyMap() {
|
||||
return userPropertyMap;
|
||||
}
|
||||
|
||||
public Arguments getArguments() {
|
||||
return arguments;
|
||||
}
|
||||
|
||||
public AuthInfo setArguments(Arguments arguments) {
|
||||
return new AuthInfo(username, userId, authToken, userType, userProperties, userPropertyMap, arguments);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,68 @@
|
||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||
|
||||
import org.jackhuang.hmcl.auth.AuthInfo;
|
||||
import org.jackhuang.hmcl.auth.AuthenticationException;
|
||||
import org.jackhuang.hmcl.auth.MultiCharacterSelector;
|
||||
import org.jackhuang.hmcl.game.Arguments;
|
||||
import org.jackhuang.hmcl.task.GetTask;
|
||||
import org.jackhuang.hmcl.util.ExceptionalSupplier;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
|
||||
import java.net.Proxy;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class AuthlibInjectorAccount extends YggdrasilAccount {
|
||||
private final String serverBaseURL;
|
||||
private final ExceptionalSupplier<String, ?> injectorJarPath;
|
||||
|
||||
public AuthlibInjectorAccount(ExceptionalSupplier<String, ?> injectorJarPath, String serverBaseURL, String username) {
|
||||
super(serverBaseURL + "authserver/", serverBaseURL + "sessionserver/", username);
|
||||
|
||||
this.injectorJarPath = injectorJarPath;
|
||||
this.serverBaseURL = serverBaseURL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthInfo logIn(MultiCharacterSelector selector, Proxy proxy) throws AuthenticationException {
|
||||
// Authlib Injector recommends launchers to pre-fetch the server basic information before launched the game to save time.
|
||||
GetTask getTask = new GetTask(NetworkUtils.toURL(serverBaseURL));
|
||||
AtomicBoolean flag = new AtomicBoolean(true);
|
||||
Thread thread = Lang.thread(() -> {
|
||||
try {
|
||||
getTask.run();
|
||||
} catch (Exception ignore) {
|
||||
flag.set(false);
|
||||
}
|
||||
});
|
||||
|
||||
AuthInfo info = super.logIn(selector, proxy);
|
||||
try {
|
||||
thread.join();
|
||||
|
||||
String arg = "-javaagent:" + injectorJarPath.get() + "=" + serverBaseURL;
|
||||
Arguments arguments = Arguments.addJVMArguments(null, arg);
|
||||
|
||||
if (flag.get())
|
||||
arguments = Arguments.addJVMArguments(arguments, "-Dorg.to2mbn.authlibinjector.config.prefetched=" + getTask.getResult());
|
||||
|
||||
return info.setArguments(arguments);
|
||||
} catch (Exception e) {
|
||||
throw new AuthenticationException("Unable to get authlib injector jar path", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object, Object> toStorageImpl() {
|
||||
Map<Object, Object> map = super.toStorageImpl();
|
||||
map.put(STORAGE_KEY_SERVER_BASE_URL, serverBaseURL);
|
||||
return map;
|
||||
}
|
||||
|
||||
public String getServerBaseURL() {
|
||||
return serverBaseURL;
|
||||
}
|
||||
|
||||
public static final String STORAGE_KEY_SERVER_BASE_URL = "serverBaseURL";
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||
|
||||
import org.jackhuang.hmcl.auth.AccountFactory;
|
||||
import org.jackhuang.hmcl.util.ExceptionalSupplier;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
import org.jackhuang.hmcl.util.UUIDTypeAdapter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static org.jackhuang.hmcl.auth.yggdrasil.AuthlibInjectorAccount.STORAGE_KEY_SERVER_BASE_URL;
|
||||
import static org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount.*;
|
||||
|
||||
public class AuthlibInjectorAccountFactory extends AccountFactory<YggdrasilAccount> {
|
||||
private final ExceptionalSupplier<String, ?> injectorJarPathSupplier;
|
||||
|
||||
public AuthlibInjectorAccountFactory(ExceptionalSupplier<String, ?> injectorJarPathSupplier) {
|
||||
this.injectorJarPathSupplier = injectorJarPathSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthlibInjectorAccount fromUsername(String username, String password, Object additionalData) {
|
||||
if (!(additionalData instanceof String) || !NetworkUtils.isURL((String) additionalData))
|
||||
throw new IllegalArgumentException("Additional data should be server base url string for authlib injector accounts.");
|
||||
|
||||
AuthlibInjectorAccount account = new AuthlibInjectorAccount(injectorJarPathSupplier, (String) additionalData, username);
|
||||
account.setPassword(password);
|
||||
return account;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthlibInjectorAccount fromStorageImpl(Map<Object, Object> storage) {
|
||||
String username = Lang.get(storage, STORAGE_KEY_USER_NAME, String.class)
|
||||
.orElseThrow(() -> new IllegalArgumentException("storage does not have key " + STORAGE_KEY_USER_NAME));
|
||||
String serverBaseURL = Lang.get(storage, STORAGE_KEY_SERVER_BASE_URL, String.class)
|
||||
.orElseThrow(() -> new IllegalArgumentException("storage does not have key " + STORAGE_KEY_SERVER_BASE_URL));
|
||||
|
||||
AuthlibInjectorAccount account = new AuthlibInjectorAccount(injectorJarPathSupplier, serverBaseURL, username);
|
||||
account.setUserId(Lang.get(storage, STORAGE_KEY_USER_ID, String.class, username));
|
||||
account.setAccessToken(Lang.get(storage, STORAGE_KEY_ACCESS_TOKEN, String.class, null));
|
||||
account.setClientToken(Lang.get(storage, STORAGE_KEY_CLIENT_TOKEN, String.class)
|
||||
.orElseThrow(() -> new IllegalArgumentException("storage does not have key " + STORAGE_KEY_CLIENT_TOKEN)));
|
||||
|
||||
Lang.get(storage, STORAGE_KEY_USER_PROPERTIES, List.class)
|
||||
.ifPresent(account.getUserProperties()::fromList);
|
||||
Optional<String> profileId = Lang.get(storage, STORAGE_KEY_PROFILE_ID, String.class);
|
||||
Optional<String> profileName = Lang.get(storage, STORAGE_KEY_PROFILE_NAME, String.class);
|
||||
GameProfile profile = null;
|
||||
if (profileId.isPresent() && profileName.isPresent()) {
|
||||
profile = new GameProfile(UUIDTypeAdapter.fromString(profileId.get()), profileName.get());
|
||||
Lang.get(storage, STORAGE_KEY_PROFILE_PROPERTIES, List.class)
|
||||
.ifPresent(profile.getProperties()::fromList);
|
||||
}
|
||||
account.setSelectedProfile(profile);
|
||||
return account;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
package org.jackhuang.hmcl.auth.yggdrasil;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
import org.jackhuang.hmcl.util.NetworkUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@Immutable
|
||||
public final class AuthlibInjectorBuildInfo {
|
||||
|
||||
private final int buildNumber;
|
||||
private final String url;
|
||||
|
||||
public AuthlibInjectorBuildInfo() {
|
||||
this(0, "");
|
||||
}
|
||||
|
||||
public AuthlibInjectorBuildInfo(int buildNumber, String url) {
|
||||
this.buildNumber = buildNumber;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public int getBuildNumber() {
|
||||
return buildNumber;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public static AuthlibInjectorBuildInfo requestBuildInfo() throws IOException, JsonParseException {
|
||||
return requestBuildInfo(UPDATE_URL);
|
||||
}
|
||||
|
||||
public static AuthlibInjectorBuildInfo requestBuildInfo(String updateUrl) throws IOException, JsonParseException {
|
||||
return Lang.requireJsonNonNull(Constants.GSON.fromJson(NetworkUtils.doGet(NetworkUtils.toURL(updateUrl)), AuthlibInjectorBuildInfo.class));
|
||||
}
|
||||
|
||||
public static final String UPDATE_URL = "https://authlib-injector.to2mbn.org/api/buildInfo";
|
||||
}
|
@ -35,7 +35,7 @@ import java.util.*;
|
||||
*
|
||||
* @author huang
|
||||
*/
|
||||
public final class YggdrasilAccount extends Account {
|
||||
public class YggdrasilAccount extends Account {
|
||||
|
||||
private final String username;
|
||||
private String password;
|
||||
@ -48,8 +48,15 @@ public final class YggdrasilAccount extends Account {
|
||||
private GameProfile[] profiles;
|
||||
private UserType userType = UserType.LEGACY;
|
||||
|
||||
public YggdrasilAccount(String username) {
|
||||
public YggdrasilAccount(String baseAuthServer, String baseSessionServer, String username) {
|
||||
this.baseAuthServer = baseAuthServer;
|
||||
this.baseSessionServer = baseSessionServer;
|
||||
this.baseProfile = baseSessionServer + "session/minecraft/profile/";
|
||||
this.username = username;
|
||||
|
||||
this.routeAuthenticate = NetworkUtils.toURL(baseAuthServer + "authenticate");
|
||||
this.routeRefresh = NetworkUtils.toURL(baseAuthServer + "refresh");
|
||||
this.routeValidate = NetworkUtils.toURL(baseAuthServer + "validate");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -136,9 +143,9 @@ public final class YggdrasilAccount extends Account {
|
||||
isOnline = true;
|
||||
return;
|
||||
}
|
||||
logIn1(ROUTE_REFRESH, new RefreshRequest(accessToken, clientToken), proxy);
|
||||
logIn1(routeRefresh, new RefreshRequest(accessToken, clientToken), proxy);
|
||||
} else if (StringUtils.isNotBlank(password))
|
||||
logIn1(ROUTE_AUTHENTICATE, new AuthenticationRequest(username, password, clientToken), proxy);
|
||||
logIn1(routeAuthenticate, new AuthenticationRequest(username, password, clientToken), proxy);
|
||||
else
|
||||
throw new AuthenticationException("Password cannot be blank");
|
||||
}
|
||||
@ -250,7 +257,7 @@ public final class YggdrasilAccount extends Account {
|
||||
return false;
|
||||
|
||||
try {
|
||||
makeRequest(ROUTE_VALIDATE, new ValidateRequest(accessToken, clientToken), proxy);
|
||||
makeRequest(routeValidate, new ValidateRequest(accessToken, clientToken), proxy);
|
||||
return true;
|
||||
} catch (AuthenticationException e) {
|
||||
return false;
|
||||
@ -268,7 +275,7 @@ public final class YggdrasilAccount extends Account {
|
||||
if (StringUtils.isBlank(userId))
|
||||
throw new IllegalStateException("Not logged in");
|
||||
|
||||
ProfileResponse response = GSON.fromJson(NetworkUtils.doGet(NetworkUtils.toURL(BASE_PROFILE + UUIDTypeAdapter.fromUUID(profile.getId()))), ProfileResponse.class);
|
||||
ProfileResponse response = GSON.fromJson(NetworkUtils.doGet(NetworkUtils.toURL(baseProfile + UUIDTypeAdapter.fromUUID(profile.getId()))), ProfileResponse.class);
|
||||
if (response.getProperties() == null) return Optional.empty();
|
||||
Property textureProperty = response.getProperties().get("textures");
|
||||
if (textureProperty == null) return Optional.empty();
|
||||
@ -287,11 +294,12 @@ public final class YggdrasilAccount extends Account {
|
||||
return "YggdrasilAccount[username=" + getUsername() + "]";
|
||||
}
|
||||
|
||||
private static final String BASE_URL = "https://authserver.mojang.com/";
|
||||
private static final String BASE_PROFILE = "https://sessionserver.mojang.com/session/minecraft/profile/";
|
||||
private static final URL ROUTE_AUTHENTICATE = NetworkUtils.toURL(BASE_URL + "authenticate");
|
||||
private static final URL ROUTE_REFRESH = NetworkUtils.toURL(BASE_URL + "refresh");
|
||||
private static final URL ROUTE_VALIDATE = NetworkUtils.toURL(BASE_URL + "validate");
|
||||
private final String baseAuthServer;
|
||||
private final String baseSessionServer;
|
||||
private final String baseProfile;
|
||||
private final URL routeAuthenticate;
|
||||
private final URL routeRefresh;
|
||||
private final URL routeValidate;
|
||||
|
||||
static final String STORAGE_KEY_ACCESS_TOKEN = "accessToken";
|
||||
static final String STORAGE_KEY_PROFILE_NAME = "displayName";
|
||||
|
@ -31,15 +31,23 @@ import static org.jackhuang.hmcl.auth.yggdrasil.YggdrasilAccount.*;
|
||||
*
|
||||
* @author huangyuhui
|
||||
*/
|
||||
public final class YggdrasilAccountFactory extends AccountFactory<YggdrasilAccount> {
|
||||
public static final YggdrasilAccountFactory INSTANCE = new YggdrasilAccountFactory();
|
||||
public class YggdrasilAccountFactory extends AccountFactory<YggdrasilAccount> {
|
||||
|
||||
private YggdrasilAccountFactory() {
|
||||
private final String baseAuthServer;
|
||||
private final String baseSessionServer;
|
||||
|
||||
public YggdrasilAccountFactory() {
|
||||
this(MOJANG_AUTH_SERVER, MOJANG_SESSION_SERVER);
|
||||
}
|
||||
|
||||
public YggdrasilAccountFactory(String baseAuthServer, String baseSessionServer) {
|
||||
this.baseAuthServer = baseAuthServer;
|
||||
this.baseSessionServer = baseSessionServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public YggdrasilAccount fromUsername(String username, String password) {
|
||||
YggdrasilAccount account = new YggdrasilAccount(username);
|
||||
public YggdrasilAccount fromUsername(String username, String password, Object additionalData) {
|
||||
YggdrasilAccount account = new YggdrasilAccount(MOJANG_AUTH_SERVER, MOJANG_SESSION_SERVER, username);
|
||||
account.setPassword(password);
|
||||
return account;
|
||||
}
|
||||
@ -49,7 +57,7 @@ public final class YggdrasilAccountFactory extends AccountFactory<YggdrasilAccou
|
||||
String username = Lang.get(storage, STORAGE_KEY_USER_NAME, String.class)
|
||||
.orElseThrow(() -> new IllegalArgumentException("storage does not have key " + STORAGE_KEY_USER_NAME));
|
||||
|
||||
YggdrasilAccount account = new YggdrasilAccount(username);
|
||||
YggdrasilAccount account = new YggdrasilAccount(baseAuthServer, baseSessionServer, username);
|
||||
account.setUserId(Lang.get(storage, STORAGE_KEY_USER_ID, String.class, username));
|
||||
account.setAccessToken(Lang.get(storage, STORAGE_KEY_ACCESS_TOKEN, String.class, null));
|
||||
account.setClientToken(Lang.get(storage, STORAGE_KEY_CLIENT_TOKEN, String.class)
|
||||
@ -69,4 +77,6 @@ public final class YggdrasilAccountFactory extends AccountFactory<YggdrasilAccou
|
||||
return account;
|
||||
}
|
||||
|
||||
private static final String MOJANG_AUTH_SERVER = "https://authserver.mojang.com/";
|
||||
private static final String MOJANG_SESSION_SERVER = "https://sessionserver.mojang.com/";
|
||||
}
|
||||
|
@ -66,6 +66,18 @@ public final class Arguments {
|
||||
return new Arguments(Lang.merge(arguments.getGame(), list), arguments.getJvm());
|
||||
}
|
||||
|
||||
public static Arguments addJVMArguments(Arguments arguments, String... jvmArguments) {
|
||||
return addJVMArguments(arguments, Arrays.asList(jvmArguments));
|
||||
}
|
||||
|
||||
public static Arguments addJVMArguments(Arguments arguments, List<String> jvmArguments) {
|
||||
List<Argument> list = jvmArguments.stream().map(StringArgument::new).collect(Collectors.toList());
|
||||
if (arguments == null)
|
||||
return new Arguments(null, list);
|
||||
else
|
||||
return new Arguments(arguments.getGame(), Lang.merge(arguments.getJvm(), list));
|
||||
}
|
||||
|
||||
public static Arguments merge(Arguments a, Arguments b) {
|
||||
if (a == null)
|
||||
return b;
|
||||
|
@ -22,6 +22,7 @@ import com.google.gson.annotations.SerializedName;
|
||||
import org.jackhuang.hmcl.util.CompressingUtils;
|
||||
import org.jackhuang.hmcl.util.Constants;
|
||||
import org.jackhuang.hmcl.util.Immutable;
|
||||
import org.jackhuang.hmcl.util.Lang;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -119,9 +120,7 @@ public final class CurseManifest {
|
||||
*/
|
||||
public static Modpack readCurseForgeModpackManifest(File f) throws IOException, JsonParseException {
|
||||
String json = CompressingUtils.readTextZipEntry(f, "manifest.json");
|
||||
CurseManifest manifest = Constants.GSON.fromJson(json, CurseManifest.class);
|
||||
if (manifest == null)
|
||||
throw new JsonParseException("`manifest.json` not found. Not a valid Curse modpack.");
|
||||
CurseManifest manifest = Lang.requireJsonNonNull(Constants.GSON.fromJson(json, CurseManifest.class));
|
||||
return new Modpack(manifest.getName(), manifest.getAuthor(), manifest.getVersion(), manifest.getMinecraft().getGameVersion(),
|
||||
CompressingUtils.readTextZipEntryQuietly(f, "modlist.html").orElse( "No description"), manifest);
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ public final class DateTypeAdapter implements JsonSerializer<Date>, JsonDeserial
|
||||
cleaned = cleaned.substring(0, 22) + cleaned.substring(23);
|
||||
return ISO_8601_FORMAT.parse(cleaned);
|
||||
} catch (Exception e) {
|
||||
throw new JsonSyntaxException("Invalid date: " + string, e);
|
||||
throw new JsonParseException("Invalid date: " + string, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,8 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.util;
|
||||
|
||||
import com.google.gson.JsonParseException;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
@ -22,6 +24,16 @@ public final class Lang {
|
||||
public static final Consumer EMPTY_CONSUMER = a -> {
|
||||
};
|
||||
|
||||
public static <T> T requireJsonNonNull(T obj) throws JsonParseException {
|
||||
return requireJsonNonNull(obj, "Json object cannot be null.");
|
||||
}
|
||||
|
||||
public static <T> T requireJsonNonNull(T obj, String message) throws JsonParseException {
|
||||
if (obj == null)
|
||||
throw new JsonParseException(message);
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> mapOf(Pair<K, V>... pairs) {
|
||||
HashMap<K, V> map = new HashMap<>();
|
||||
for (Pair<K, V> pair : pairs)
|
||||
|
@ -25,6 +25,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.security.GeneralSecurityException;
|
||||
@ -187,4 +188,13 @@ public final class NetworkUtils {
|
||||
public static URL toURL(String str) {
|
||||
return Lang.invoke(() -> new URL(str));
|
||||
}
|
||||
|
||||
public static boolean isURL(String str) {
|
||||
try {
|
||||
new URL(str);
|
||||
return true;
|
||||
} catch (MalformedURLException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,6 +1,5 @@
|
||||
#Sun Oct 22 14:32:40 CST 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-bin.zip
|
||||
|
4
gradlew
vendored
4
gradlew
vendored
@ -78,14 +78,14 @@ if [ -n "$JAVA_HOME" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
path of your Java installation."
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD="java"
|
||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
path of your Java installation."
|
||||
location of your Java installation."
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
|
4
gradlew.bat
vendored
4
gradlew.bat
vendored
@ -27,7 +27,7 @@ echo.
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo path of your Java installation.
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
@ -41,7 +41,7 @@ echo.
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
||||
echo.
|
||||
echo Please set the JAVA_HOME variable in your environment to match the
|
||||
echo path of your Java installation.
|
||||
echo location of your Java installation.
|
||||
|
||||
goto fail
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user