Authlib Injector support

This commit is contained in:
huanghongxun
2018-02-17 23:28:05 +08:00
parent 83bc6748a3
commit 24ec0adacf
33 changed files with 716 additions and 137 deletions

View File

@@ -57,6 +57,12 @@ public abstract class Account {
*/
public abstract AuthInfo logIn(MultiCharacterSelector selector, Proxy proxy) throws AuthenticationException;
public AuthInfo logInWithPassword(MultiCharacterSelector selector, String password) throws AuthenticationException {
return logInWithPassword(selector, password, Proxy.NO_PROXY);
}
public abstract AuthInfo logInWithPassword(MultiCharacterSelector selector, String password, Proxy proxy) throws AuthenticationException;
public abstract boolean canPlayOffline();
/**

View File

@@ -64,6 +64,11 @@ public class OfflineAccount extends Account {
return new AuthInfo(username, uuid, uuid);
}
@Override
public AuthInfo logInWithPassword(MultiCharacterSelector selector, String password, Proxy proxy) throws AuthenticationException {
return logIn(selector, proxy);
}
@Override
public void logOut() {
// Offline account need not log out.

View File

@@ -32,7 +32,7 @@ public class OfflineAccountFactory extends AccountFactory<OfflineAccount> {
}
@Override
public OfflineAccount fromUsername(String username, String password) {
public OfflineAccount fromUsername(String username, String password, Object additionalData) {
return new OfflineAccount(username, getUUIDFromUserName(username));
}

View File

@@ -29,13 +29,7 @@ public class AuthlibInjectorAccount extends YggdrasilAccount {
// 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);
}
});
Thread thread = Lang.thread(() -> flag.set(getTask.test()));
AuthInfo info = super.logIn(selector, proxy);
try {
@@ -53,6 +47,29 @@ public class AuthlibInjectorAccount extends YggdrasilAccount {
}
}
@Override
public AuthInfo logInWithPassword(MultiCharacterSelector selector, String password, 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(() -> flag.set(getTask.test()));
AuthInfo info = super.logInWithPassword(selector, password, 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();

View File

@@ -0,0 +1,19 @@
package org.jackhuang.hmcl.auth.yggdrasil;
public class AuthlibInjectorServerInfo {
private final String serverIp;
private final String serverName;
public AuthlibInjectorServerInfo(String serverIp, String serverName) {
this.serverIp = serverIp;
this.serverName = serverName;
}
public String getServerIp() {
return serverIp;
}
public String getServerName() {
return serverName;
}
}

View File

@@ -0,0 +1,34 @@
package org.jackhuang.hmcl.auth.yggdrasil;
public class AuthlibInjectorServerResponse {
private final Meta meta;
public AuthlibInjectorServerResponse() {
this(new Meta());
}
public AuthlibInjectorServerResponse(Meta meta) {
this.meta = meta;
}
public Meta getMeta() {
return meta;
}
public static class Meta {
private final String serverName;
public Meta() {
this("");
}
public Meta(String serverName) {
this.serverName = serverName;
}
public String getServerName() {
return serverName;
}
}
}

View File

@@ -132,24 +132,47 @@ public class YggdrasilAccount extends Account {
}
}
@Override
public AuthInfo logInWithPassword(MultiCharacterSelector selector, String password, Proxy proxy) throws AuthenticationException {
logInWithPassword0(password, proxy);
if (!isLoggedIn())
throw new AuthenticationException("Wrong password for account " + username);
if (selectedProfile == null) {
if (profiles == null || profiles.length <= 0)
throw new NoCharacterException(this);
selectedProfile = selector.select(this, Arrays.asList(profiles));
}
return new AuthInfo(selectedProfile, accessToken, userType, GSON.toJson(userProperties));
}
private void logIn0(Proxy proxy) throws AuthenticationException {
if (StringUtils.isNotBlank(accessToken)) {
if (StringUtils.isBlank(userId))
if (StringUtils.isNotBlank(username))
userId = username;
else
throw new AuthenticationException("Invalid uuid and username");
if (checkTokenValidity(proxy)) {
isOnline = true;
return;
}
logIn1(routeRefresh, new RefreshRequest(accessToken, clientToken), proxy);
logInWithToken(proxy);
} else if (StringUtils.isNotBlank(password))
logIn1(routeAuthenticate, new AuthenticationRequest(username, password, clientToken), proxy);
logInWithPassword0(password, proxy);
else
throw new AuthenticationException("Password cannot be blank");
}
private void logInWithToken(Proxy proxy) throws AuthenticationException {
if (StringUtils.isBlank(userId))
if (StringUtils.isNotBlank(username))
userId = username;
else
throw new AuthenticationException("Invalid uuid and username");
if (checkTokenValidity(proxy)) {
isOnline = true;
return;
}
logIn1(routeRefresh, new RefreshRequest(accessToken, clientToken), proxy);
}
public void logInWithPassword0(String password, Proxy proxy) throws AuthenticationException {
logIn1(routeAuthenticate, new AuthenticationRequest(username, password, clientToken), proxy);
}
private void logIn1(URL url, Object input, Proxy proxy) throws AuthenticationException {
AuthenticationResponse response = makeRequest(url, input, proxy)
.orElseThrow(() -> new AuthenticationException("Server response empty"));

View File

@@ -138,10 +138,16 @@ public class DefaultLauncher extends Launcher {
configuration.put("${assets_root}", gameAssets.getAbsolutePath());
res.addAll(Arguments.parseArguments(version.getArguments().map(Arguments::getJvm).orElseGet(this::getDefaultJVMArguments), configuration));
if (authInfo.getArguments() != null && authInfo.getArguments().getJvm() != null && !authInfo.getArguments().getJvm().isEmpty())
res.addAll(Arguments.parseArguments(authInfo.getArguments().getJvm(), configuration));
res.add(version.getMainClass());
Map<String, Boolean> features = getFeatures();
res.addAll(Arguments.parseArguments(version.getArguments().map(Arguments::getGame).orElseGet(this::getDefaultGameArguments), configuration, features));
if (authInfo.getArguments() != null && authInfo.getArguments().getGame() != null && !authInfo.getArguments().getGame().isEmpty())
res.addAll(Arguments.parseArguments(authInfo.getArguments().getGame(), configuration, features));
res.addAll(Arguments.parseStringArguments(version.getMinecraftArguments().map(StringUtils::tokenize).orElseGet(LinkedList::new), configuration));
// Optional Minecraft arguments

View File

@@ -192,6 +192,7 @@ public final class TaskExecutor {
// do nothing
} catch (Exception e) {
lastException = e;
variables.set("lastException", e);
Logging.LOG.log(Level.FINE, "Task failed: " + task.getName(), e);
task.onDone().fireEvent(new TaskEvent(this, task, true));
taskListeners.forEach(it -> it.onFailed(task, e));

View File

@@ -35,15 +35,15 @@ public final class AutoTypingMap<K> {
this.impl = impl;
}
public <V> V get(K key) {
public synchronized <V> V get(K key) {
return (V) impl.get(key);
}
public <V> Optional<V> getOptional(K key) {
public synchronized <V> Optional<V> getOptional(K key) {
return Optional.ofNullable(get(key));
}
public void set(K key, Object value) {
public synchronized void set(K key, Object value) {
if (value != null)
impl.put(key, value);
}

View File

@@ -93,7 +93,7 @@ public final class NetworkUtils {
public static HttpURLConnection createConnection(URL url, Proxy proxy) throws IOException {
initHttps();
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
HttpURLConnection connection = (HttpURLConnection) url.openConnection(proxy);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setConnectTimeout(15000);