mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-11 08:27:29 -04:00
check sha1 of assets (optionally), hide all other windows, when fatal error occurred
This commit is contained in:
parent
16ef8d7b06
commit
9d12a40596
@ -34,6 +34,7 @@ import de.bixilon.minosoft.util.task.Task;
|
||||
import de.bixilon.minosoft.util.task.TaskImportance;
|
||||
import javafx.application.Platform;
|
||||
import javafx.scene.control.Dialog;
|
||||
import javafx.stage.Stage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
@ -85,11 +86,19 @@ public final class Minosoft {
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
// hide all other gui parts
|
||||
StartProgressWindow.hideDialog();
|
||||
Launcher.exit();
|
||||
Platform.runLater(() -> {
|
||||
Dialog<Boolean> dialog = new Dialog<>();
|
||||
dialog.setTitle("Critical Error");
|
||||
dialog.setHeaderText("An error occurred while starting Minosoft");
|
||||
dialog.setContentText(exception.getMessage());
|
||||
dialog.setContentText(exception.getLocalizedMessage());
|
||||
|
||||
Stage stage = (Stage) dialog.getDialogPane().getScene().getWindow();
|
||||
stage.setAlwaysOnTop(true);
|
||||
stage.toFront();
|
||||
dialog.setOnCloseRequest(dialogEvent -> System.exit(1));
|
||||
dialog.showAndWait();
|
||||
System.exit(1);
|
||||
});
|
||||
@ -101,7 +110,7 @@ public final class Minosoft {
|
||||
|
||||
taskWorker.addTask(new Task(progress -> {
|
||||
progress.countUp();
|
||||
LocaleManager.load(config.getString(ConfigurationPaths.LANGUAGE));
|
||||
LocaleManager.load(config.getString(ConfigurationPaths.GENERAL_LANGUAGE));
|
||||
progress.countDown();
|
||||
|
||||
}, "Minosoft Language", "", Priorities.HIGH, TaskImportance.REQUIRED));
|
||||
@ -143,7 +152,7 @@ public final class Minosoft {
|
||||
|
||||
taskWorker.addTask(new Task(progress -> {
|
||||
progress.countUp();
|
||||
MinecraftLocaleManager.load(config.getString(ConfigurationPaths.LANGUAGE));
|
||||
MinecraftLocaleManager.load(config.getString(ConfigurationPaths.GENERAL_LANGUAGE));
|
||||
progress.countDown();
|
||||
|
||||
}, "Mojang language", "", Priorities.HIGH, TaskImportance.REQUIRED, new HashSet<>(Collections.singleton("Assets"))));
|
||||
|
@ -91,6 +91,7 @@ public class Configuration {
|
||||
public boolean getBoolean(ConfigurationPaths path) {
|
||||
return switch (path) {
|
||||
case NETWORK_FAKE_CLIENT_BRAND -> config.getAsJsonObject("network").get("fake-network-brand").getAsBoolean();
|
||||
case DEBUG_VERIFY_ASSETS -> config.getAsJsonObject("debug").get("verify-assets").getAsBoolean();
|
||||
default -> throw new RuntimeException(String.format("Illegal boolean value: %s", path));
|
||||
};
|
||||
}
|
||||
@ -98,6 +99,7 @@ public class Configuration {
|
||||
public void putBoolean(ConfigurationPaths path, boolean value) {
|
||||
switch (path) {
|
||||
case NETWORK_FAKE_CLIENT_BRAND -> config.getAsJsonObject("network").addProperty("fake-network-brand", value);
|
||||
case DEBUG_VERIFY_ASSETS -> config.getAsJsonObject("debug").addProperty("verify-assets", value);
|
||||
default -> throw new RuntimeException(String.format("Illegal boolean value: %s", path));
|
||||
}
|
||||
}
|
||||
@ -122,7 +124,7 @@ public class Configuration {
|
||||
return switch (path) {
|
||||
case ACCOUNT_SELECTED -> config.getAsJsonObject("accounts").get("selected").getAsString();
|
||||
case GENERAL_LOG_LEVEL -> config.getAsJsonObject("general").get("log-level").getAsString();
|
||||
case LANGUAGE -> config.getAsJsonObject("general").get("language").getAsString();
|
||||
case GENERAL_LANGUAGE -> config.getAsJsonObject("general").get("language").getAsString();
|
||||
case MAPPINGS_URL -> config.getAsJsonObject("download").getAsJsonObject("urls").get("mappings").getAsString();
|
||||
case CLIENT_TOKEN -> config.getAsJsonObject("accounts").get("client-token").getAsString();
|
||||
default -> throw new RuntimeException(String.format("Illegal String value: %s", path));
|
||||
@ -133,7 +135,7 @@ public class Configuration {
|
||||
switch (path) {
|
||||
case ACCOUNT_SELECTED -> config.getAsJsonObject("accounts").addProperty("selected", value);
|
||||
case GENERAL_LOG_LEVEL -> config.getAsJsonObject("general").addProperty("log-level", value);
|
||||
case LANGUAGE -> config.getAsJsonObject("general").addProperty("language", value);
|
||||
case GENERAL_LANGUAGE -> config.getAsJsonObject("general").addProperty("language", value);
|
||||
case MAPPINGS_URL -> config.getAsJsonObject("download").getAsJsonObject("urls").addProperty("mappings", value);
|
||||
case CLIENT_TOKEN -> config.getAsJsonObject("accounts").addProperty("client-token", value);
|
||||
default -> throw new RuntimeException(String.format("Illegal String value: %s", path));
|
||||
|
@ -21,5 +21,6 @@ public enum ConfigurationPaths {
|
||||
CLIENT_TOKEN,
|
||||
MAPPINGS_URL,
|
||||
ACCOUNT_SELECTED,
|
||||
LANGUAGE,
|
||||
GENERAL_LANGUAGE,
|
||||
DEBUG_VERIFY_ASSETS,
|
||||
}
|
@ -19,6 +19,8 @@ import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import de.bixilon.minosoft.Config;
|
||||
import de.bixilon.minosoft.Minosoft;
|
||||
import de.bixilon.minosoft.config.ConfigurationPaths;
|
||||
import de.bixilon.minosoft.logging.Log;
|
||||
import de.bixilon.minosoft.logging.LogLevels;
|
||||
import de.bixilon.minosoft.util.CountUpAndDownLatch;
|
||||
@ -146,7 +148,17 @@ public class AssetsManager {
|
||||
|
||||
private static boolean verifyAssetHash(String hash) {
|
||||
// file does not exist
|
||||
return getAssetSize(hash) != -1;// ToDo
|
||||
if (getAssetSize(hash) == -1) {
|
||||
return false;
|
||||
}
|
||||
if (!Minosoft.config.getBoolean(ConfigurationPaths.DEBUG_VERIFY_ASSETS)) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
return hash.equals(Util.sha1Gzip(new File(getAssetDiskPath(hash))));
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void generateJarAssets() throws IOException {
|
||||
|
@ -33,11 +33,16 @@ import java.io.IOException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class Launcher {
|
||||
private static Stage stage;
|
||||
private static boolean exit = false;
|
||||
|
||||
public static void start() throws Exception {
|
||||
Log.info("Starting launcher...");
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
Platform.runLater(() -> {
|
||||
if (exit) {
|
||||
return;
|
||||
}
|
||||
Stage stage = new Stage();
|
||||
|
||||
GUITools.versionList.setCellFactory(new Callback<>() {
|
||||
@ -73,14 +78,27 @@ public class Launcher {
|
||||
|
||||
stage.setTitle(LocaleManager.translate(Strings.MAIN_WINDOW_TITLE));
|
||||
stage.getIcons().add(GUITools.logo);
|
||||
stage.show();
|
||||
stage.setOnCloseRequest(windowEvent -> System.exit(0));
|
||||
if (Minosoft.getSelectedAccount() == null) {
|
||||
MainWindow.manageAccounts();
|
||||
}
|
||||
if (exit) {
|
||||
return;
|
||||
}
|
||||
stage.show();
|
||||
Launcher.stage = stage;
|
||||
latch.countDown();
|
||||
});
|
||||
latch.await();
|
||||
Log.info("Launcher started!");
|
||||
}
|
||||
|
||||
public static void exit() {
|
||||
exit = true;
|
||||
if (stage == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Platform.runLater(() -> stage.close());
|
||||
}
|
||||
}
|
@ -29,26 +29,33 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class StartProgressWindow extends Application {
|
||||
public static CountDownLatch toolkitLatch = new CountDownLatch(2);
|
||||
private static Dialog<Boolean> progressDialog;
|
||||
private static boolean exit = false;
|
||||
|
||||
public static void show(CountUpAndDownLatch progress) {
|
||||
if (exit) {
|
||||
return;
|
||||
}
|
||||
new Thread(() -> {
|
||||
if (progress.getCount() == 0) {
|
||||
return;
|
||||
}
|
||||
AtomicReference<ProgressBar> progressBar = new AtomicReference<>();
|
||||
AtomicReference<Dialog<Boolean>> progressDialog = new AtomicReference<>();
|
||||
Platform.runLater(() -> {
|
||||
progressDialog.set(new Dialog<>());
|
||||
progressDialog.get().setTitle(LocaleManager.translate(Strings.MINOSOFT_STILL_STARTING_TITLE));
|
||||
progressDialog.get().setHeaderText(LocaleManager.translate(Strings.MINOSOFT_STILL_STARTING_HEADER));
|
||||
progressDialog = new Dialog<>();
|
||||
progressDialog.setTitle(LocaleManager.translate(Strings.MINOSOFT_STILL_STARTING_TITLE));
|
||||
progressDialog.setHeaderText(LocaleManager.translate(Strings.MINOSOFT_STILL_STARTING_HEADER));
|
||||
GridPane grid = new GridPane();
|
||||
progressBar.set(new ProgressBar());
|
||||
progressBar.get().setProgress(1.0F - ((float) progress.getCount() / progress.getTotal()));
|
||||
grid.add(progressBar.get(), 0, 0);
|
||||
progressDialog.get().getDialogPane().setContent(grid);
|
||||
progressDialog.get().show();
|
||||
progressDialog.getDialogPane().setContent(grid);
|
||||
if (exit) {
|
||||
return;
|
||||
}
|
||||
progressDialog.show();
|
||||
|
||||
Stage stage = (Stage) progressDialog.get().getDialogPane().getScene().getWindow();
|
||||
Stage stage = (Stage) progressDialog.getDialogPane().getScene().getWindow();
|
||||
stage.setAlwaysOnTop(true);
|
||||
stage.toFront();
|
||||
|
||||
@ -61,11 +68,7 @@ public class StartProgressWindow extends Application {
|
||||
}
|
||||
Platform.runLater(() -> progressBar.get().setProgress(1.0F - ((float) progress.getCount() / progress.getTotal())));
|
||||
}
|
||||
|
||||
Platform.runLater(() -> {
|
||||
progressDialog.get().setResult(Boolean.TRUE);
|
||||
progressDialog.get().hide();
|
||||
});
|
||||
hideDialog();
|
||||
}).start();
|
||||
}
|
||||
|
||||
@ -77,6 +80,17 @@ public class StartProgressWindow extends Application {
|
||||
Log.debug("Initialized JavaFX Toolkit!");
|
||||
}
|
||||
|
||||
public static void hideDialog() {
|
||||
exit = true;
|
||||
if (progressDialog == null) {
|
||||
return;
|
||||
}
|
||||
Platform.runLater(() -> {
|
||||
progressDialog.setResult(Boolean.TRUE);
|
||||
progressDialog.hide();
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Stage stage) {
|
||||
toolkitLatch.countDown();
|
||||
|
@ -102,17 +102,40 @@ public final class Util {
|
||||
}
|
||||
|
||||
public static String sha1(byte[] data) {
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(data);
|
||||
try {
|
||||
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
|
||||
crypt.reset();
|
||||
crypt.update(data);
|
||||
return byteArrayToHexString(crypt.digest());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return sha1(inputStream);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String sha1(File file) throws IOException {
|
||||
return sha1(new FileInputStream(file));
|
||||
}
|
||||
|
||||
public static String sha1Gzip(File file) throws IOException {
|
||||
return sha1(new GZIPInputStream(new FileInputStream(file)));
|
||||
}
|
||||
|
||||
public static String sha1(InputStream inputStream) throws IOException {
|
||||
try {
|
||||
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
|
||||
crypt.reset();
|
||||
|
||||
byte[] buffer = new byte[4096];
|
||||
int length;
|
||||
while ((length = inputStream.read(buffer, 0, 4096)) != -1) {
|
||||
crypt.update(buffer, 0, length);
|
||||
}
|
||||
return byteArrayToHexString(crypt.digest());
|
||||
} catch (NoSuchAlgorithmException | FileNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static String byteArrayToHexString(byte[] b) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (byte value : b) {
|
||||
|
@ -23,5 +23,8 @@
|
||||
"urls": {
|
||||
"mappings": "https://gitlab.com/Bixilon/minosoft/-/raw/master/data/mcdata/%s.tar.gz?inline=false"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"verify-assets": true
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user