@@ -21,7 +21,6 @@ import com.jfoenix.controls.JFXButton;
|
||||
import com.jfoenix.controls.JFXDialogLayout;
|
||||
import com.jfoenix.controls.JFXTextField;
|
||||
|
||||
import javafx.beans.binding.Bindings;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.layout.StackPane;
|
||||
@@ -39,7 +38,6 @@ import java.io.IOException;
|
||||
|
||||
import static org.jackhuang.hmcl.setting.ConfigHolder.config;
|
||||
import static org.jackhuang.hmcl.ui.FXUtils.loadFXML;
|
||||
import static org.jackhuang.hmcl.util.Lang.thread;
|
||||
import static org.jackhuang.hmcl.util.i18n.I18n.i18n;
|
||||
|
||||
public class AddAuthlibInjectorServerPane extends StackPane implements DialogAware {
|
||||
@@ -70,24 +68,13 @@ public class AddAuthlibInjectorServerPane extends StackPane implements DialogAwa
|
||||
transitionHandler = new TransitionHandler(addServerContainer);
|
||||
transitionHandler.setContent(addServerPane, ContainerAnimations.NONE.getAnimationProducer());
|
||||
|
||||
btnAddNext.disableProperty().bind(
|
||||
Bindings.createBooleanBinding(txtServerUrl::validate, txtServerUrl.textProperty()).not());
|
||||
btnAddNext.disableProperty().bind(txtServerUrl.textProperty().isEmpty());
|
||||
nextPane.hideSpinner();
|
||||
|
||||
txtServerUrl.setText("https://");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDialogShown() {
|
||||
txtServerUrl.requestFocus();
|
||||
txtServerUrl.selectEnd();
|
||||
}
|
||||
|
||||
private String fixInputUrl(String url) {
|
||||
if (!url.endsWith("/")) {
|
||||
url += "/";
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
private String resolveFetchExceptionMessage(Throwable exception) {
|
||||
@@ -110,13 +97,13 @@ public class AddAuthlibInjectorServerPane extends StackPane implements DialogAwa
|
||||
|
||||
lblCreationWarning.setText("");
|
||||
|
||||
String url = fixInputUrl(txtServerUrl.getText());
|
||||
String url = txtServerUrl.getText();
|
||||
|
||||
nextPane.showSpinner();
|
||||
addServerPane.setDisable(true);
|
||||
|
||||
Task.of(() -> {
|
||||
serverBeingAdded = AuthlibInjectorServer.fetchServerInfo(url);
|
||||
serverBeingAdded = AuthlibInjectorServer.locateServer(url);
|
||||
}).finalized(Schedulers.javafx(), (variables, isDependentsSucceeded) -> {
|
||||
addServerPane.setDisable(false);
|
||||
nextPane.hideSpinner();
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
package org.jackhuang.hmcl.ui.construct;
|
||||
|
||||
import com.jfoenix.validation.base.ValidatorBase;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.scene.control.TextInputControl;
|
||||
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
||||
public class URLValidator extends ValidatorBase {
|
||||
|
||||
private final ObservableList<String> protocols = FXCollections.observableArrayList();
|
||||
|
||||
public URLValidator() {
|
||||
super();
|
||||
}
|
||||
|
||||
public ObservableList<String> getProtocols() {
|
||||
return protocols;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void eval() {
|
||||
if (srcControl.get() instanceof TextInputControl) {
|
||||
try {
|
||||
URL url = new URL(((TextInputControl) srcControl.get()).getText());
|
||||
if (protocols.isEmpty())
|
||||
hasErrors.set(false);
|
||||
else
|
||||
hasErrors.set(!protocols.contains(url.getProtocol()));
|
||||
} catch (MalformedURLException e) {
|
||||
hasErrors.set(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import com.jfoenix.controls.*?>
|
||||
<?import org.jackhuang.hmcl.ui.construct.URLValidator?>
|
||||
<?import org.jackhuang.hmcl.ui.construct.SpinnerPane?>
|
||||
|
||||
<fx:root xmlns="http://javafx.com/javafx"
|
||||
@@ -16,16 +15,7 @@
|
||||
<Label text="%account.injector.add" />
|
||||
</heading>
|
||||
<body>
|
||||
<JFXTextField fx:id="txtServerUrl" promptText="%account.injector.server_url" onAction="#onAddNext">
|
||||
<validators>
|
||||
<URLValidator message="%input.url">
|
||||
<protocols>
|
||||
<String fx:value="http" />
|
||||
<String fx:value="https" />
|
||||
</protocols>
|
||||
</URLValidator>
|
||||
</validators>
|
||||
</JFXTextField>
|
||||
<JFXTextField fx:id="txtServerUrl" promptText="%account.injector.server_url" onAction="#onAddNext" />
|
||||
</body>
|
||||
<actions>
|
||||
<Label fx:id="lblCreationWarning" />
|
||||
|
||||
@@ -17,23 +17,104 @@
|
||||
*/
|
||||
package org.jackhuang.hmcl.auth.authlibinjector;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.jackhuang.hmcl.util.Lang.tryCast;
|
||||
import static org.jackhuang.hmcl.util.Logging.LOG;
|
||||
import static org.jackhuang.hmcl.util.io.IOUtils.readFullyWithoutClosing;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
import org.jackhuang.hmcl.util.gson.JsonUtils;
|
||||
import org.jackhuang.hmcl.util.io.NetworkUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.jackhuang.hmcl.util.Lang.tryCast;
|
||||
|
||||
public class AuthlibInjectorServer {
|
||||
|
||||
public static AuthlibInjectorServer fetchServerInfo(String url) throws IOException {
|
||||
private static final int MAX_REDIRECTS = 5;
|
||||
|
||||
public static AuthlibInjectorServer locateServer(String url) throws IOException {
|
||||
url = parseInputUrl(url);
|
||||
HttpURLConnection conn;
|
||||
int redirectCount = 0;
|
||||
for (;;) {
|
||||
conn = (HttpURLConnection) new URL(url).openConnection();
|
||||
Optional<String> ali = getApiLocationIndication(conn);
|
||||
if (ali.isPresent()) {
|
||||
conn.disconnect();
|
||||
url = ali.get();
|
||||
if (redirectCount >= MAX_REDIRECTS) {
|
||||
throw new IOException("Exceeded maximum number of redirects (" + MAX_REDIRECTS + ")");
|
||||
}
|
||||
redirectCount++;
|
||||
LOG.info("Redirect API root to: " + url);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
JsonObject response = JsonUtils.fromNonNullJson(NetworkUtils.doGet(NetworkUtils.toURL(url)), JsonObject.class);
|
||||
return parseResponse(url, readFullyWithoutClosing(conn.getInputStream()));
|
||||
} finally {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
private static Optional<String> getApiLocationIndication(URLConnection conn) {
|
||||
return Optional.ofNullable(conn.getHeaderFields().get("X-Authlib-Injector-API-Location"))
|
||||
.flatMap(list -> list.isEmpty() ? Optional.empty() : Optional.of(list.get(0)))
|
||||
.flatMap(indication -> {
|
||||
String currentUrl = appendSuffixSlash(conn.getURL().toString());
|
||||
String newUrl;
|
||||
try {
|
||||
newUrl = appendSuffixSlash(new URL(conn.getURL(), indication).toString());
|
||||
} catch (MalformedURLException e) {
|
||||
LOG.warning("Failed to resolve absolute ALI, the header is [" + indication + "]. Ignore it.");
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (newUrl.equals(currentUrl)) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
return Optional.of(newUrl);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static String parseInputUrl(String url) {
|
||||
String lowercased = url.toLowerCase();
|
||||
if (!lowercased.startsWith("http://") && !lowercased.startsWith("https://")) {
|
||||
url = "https://" + url;
|
||||
}
|
||||
|
||||
url = appendSuffixSlash(url);
|
||||
return url;
|
||||
}
|
||||
|
||||
private static String appendSuffixSlash(String url) {
|
||||
if (!url.endsWith("/")) {
|
||||
return url + "/";
|
||||
} else {
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
public static AuthlibInjectorServer fetchServerInfo(String url) throws IOException {
|
||||
try (InputStream in = new URL(url).openStream()) {
|
||||
return parseResponse(url, readFullyWithoutClosing(in));
|
||||
}
|
||||
}
|
||||
|
||||
private static AuthlibInjectorServer parseResponse(String url, byte[] rawResponse) throws IOException {
|
||||
try {
|
||||
JsonObject response = JsonUtils.fromNonNullJson(new String(rawResponse, UTF_8), JsonObject.class);
|
||||
String name = extractServerName(response).orElse(url);
|
||||
return new AuthlibInjectorServer(url, name);
|
||||
} catch (JsonParseException e) {
|
||||
|
||||
Reference in New Issue
Block a user