Skip to content

Commit

Permalink
Add sha256 support for library verification to the launcher and a fla…
Browse files Browse the repository at this point in the history
…g to disable it. (#1656)

* Add sha256 checksum validation for libraries in the launcher.

* Add a system property to skip library verification.

* Replace the system property with a cli option to disable library validation.

* Fix copy paste javadoc.
  • Loading branch information
leMaik authored Oct 27, 2023
1 parent 3b7bd9b commit 47b7f25
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 13 deletions.
4 changes: 3 additions & 1 deletion chunky/src/java/se/llbit/chunky/main/CommandLineOptions.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ enum Mode {
" --launcher forces the launcher window to be displayed",
" --version print the launcher version and exit",
" --verbose verbose logging in the launcher",
" --console show the GUI console in headless mode");
" --console show the GUI console in headless mode",
" --dangerouslyDisableLibraryValidation",
" disable library checksum validation (not recommended)");

/**
* True if any command line option provided was invalid.
Expand Down
8 changes: 4 additions & 4 deletions launcher/src/se/llbit/chunky/launcher/ChunkyDeployer.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public static boolean checkVersionIntegrity(String version) {
case INCOMPLETE_INFO:
System.err.println("Missing library name or checksum");
return false;
case MD5_MISMATCH:
case CHECKSUM_MISMATCH:
System.err.println("Library MD5 checksum mismatch");
return false;
case MISSING:
Expand Down Expand Up @@ -473,7 +473,7 @@ public static boolean canLaunch(VersionInfo version, ChunkyLauncherController la
// Version not available!
System.err.println("Found no installed Chunky version.");
if (reportErrors) {
launcher.launcherError("No Chunky Available",
launcher.launcherError("No Chunky version available",
"There is no local Chunky version installed. Please try updating.");
}
return false;
Expand All @@ -482,9 +482,9 @@ public static boolean canLaunch(VersionInfo version, ChunkyLauncherController la
// TODO: add a way to fix this (delete corrupt version and then update)!
System.err.println("Version integrity check failed for version " + version.name);
if (reportErrors) {
launcher.launcherError("Chunky Version is Corrupt",
launcher.launcherError("Chunky version is corrupt",
"Version integrity check failed for version "
+ version.name + ". Please select another version.");
+ version.name + ". Please select another version or check for updates to repair it.");
}
return false;
}
Expand Down
4 changes: 4 additions & 0 deletions launcher/src/se/llbit/chunky/launcher/ChunkyLauncher.java
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ else if (!settings.javaOptions.contains(args[i + 1]))
System.err.println("This does not appear to be a 64-bit JVM.");
}
System.exit(is64Bit ? 0 : -1);
case "--dangerouslyDisableLibraryValidation":
System.out.println("Library validation is disabled.");
LauncherSettings.disableLibraryValidation = true;
break;
default:
if (!headlessOptions.isEmpty()) {
headlessOptions += " ";
Expand Down
25 changes: 19 additions & 6 deletions launcher/src/se/llbit/chunky/launcher/VersionInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class VersionInfo implements Comparable<VersionInfo> {

public enum LibraryStatus {
PASSED("Installed"),
MD5_MISMATCH("To be downloaded (checksum mismatch)"),
CHECKSUM_MISMATCH("To be downloaded (checksum mismatch)"),
INCOMPLETE_INFO("Incomplete library information"),
MISSING("To be downloaded (file missing)"),
MALFORMED_URL("Download failed (malformed URL)"),
Expand All @@ -64,19 +64,22 @@ public String downloadStatus() {
public static class Library {
public final String name;
public final String md5;
public final String sha256;
public final String url;
public final int size;

public Library(String name, String md5, int size) {
public Library(String name, String md5, String sha256, int size) {
this.name = name;
this.md5 = md5;
this.sha256 = sha256;
this.url = "";
this.size = size;
}

public Library(JsonObject obj) {
name = obj.get("name").stringValue("");
md5 = obj.get("md5").stringValue("");
sha256 = obj.get("sha256").stringValue("");
url = obj.get("url").stringValue("");
size = obj.get("size").intValue(1);
}
Expand All @@ -86,16 +89,25 @@ public File getFile(File libDir) {
}

public LibraryStatus testIntegrity(File libDir) {
if (name.isEmpty() || md5.isEmpty()) {
if (name.isEmpty() || (!LauncherSettings.disableLibraryValidation && md5.isEmpty() && sha256.isEmpty())) {
return LibraryStatus.INCOMPLETE_INFO;
}
File library = new File(libDir, name);
if (!library.isFile()) {
return LibraryStatus.MISSING;
}
String libMD5 = Util.md5sum(library);
if (!libMD5.equalsIgnoreCase(md5)) {
return LibraryStatus.MD5_MISMATCH;
if (!LauncherSettings.disableLibraryValidation) {
if (!sha256.isEmpty()) {
String libSha256 = Util.sha256sum(library);
if (!libSha256.equalsIgnoreCase(sha256)) {
return LibraryStatus.CHECKSUM_MISMATCH;
}
} else {
String libMD5 = Util.md5sum(library);
if (!libMD5.equalsIgnoreCase(md5)) {
return LibraryStatus.CHECKSUM_MISMATCH;
}
}
}
return LibraryStatus.PASSED;
}
Expand All @@ -104,6 +116,7 @@ public JsonObject json() {
JsonObject obj = new JsonObject();
obj.add("name", name);
obj.add("md5", md5);
obj.add("sha256", sha256);
obj.add("url", url);
obj.add("size", size);
return obj;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public UpdateDialogController(ChunkyLauncherController launcher, VersionInfo ver
case DOWNLOADED_OK:
imageStream = getClass().getResourceAsStream("cached.png");
break;
case MD5_MISMATCH:
case CHECKSUM_MISMATCH:
case MISSING:
imageStream = getClass().getResourceAsStream("refresh.png");
break;
Expand Down
2 changes: 2 additions & 0 deletions lib/src/se/llbit/chunky/launcher/LauncherSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ public class LauncherSettings {
static final ReleaseChannel SNAPSHOT_RELEASE_CHANNEL = new ReleaseChannel(
"snapshot", "Snapshot", "snapshot.json", "Latest nightly snapshot of Chunky.");

public static boolean disableLibraryValidation = false;

public int settingsRevision = 0;

public String javaDir = "";
Expand Down
25 changes: 24 additions & 1 deletion lib/src/se/llbit/util/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static String md5sum(File library) {
try {
MessageDigest digest = MessageDigest.getInstance("MD5");
try (FileInputStream in = new FileInputStream(library);
DigestInputStream dis = new DigestInputStream(in, digest)) {
DigestInputStream dis = new DigestInputStream(in, digest)) {
byte[] buf = new byte[2048];
int n;
do {
Expand All @@ -59,6 +59,29 @@ public static String md5sum(File library) {
}
}

/**
* @return the SHA256 hash sum of the given file, in hexadecimal format.
* Returns an error message if there was an error computing the checksum.
*/
public static String sha256sum(File library) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
try (FileInputStream in = new FileInputStream(library);
DigestInputStream dis = new DigestInputStream(in, digest)) {
byte[] buf = new byte[2048];
int n;
do {
n = dis.read(buf);
} while (n != -1);
return byteArrayToHexString(digest.digest());
} catch (IOException e) {
return "sha256 compute error: " + e.getMessage();
}
} catch (NoSuchAlgorithmException e) {
return "sha256 compute error: " + e.getMessage();
}
}

private static byte[] NIBBLE_TO_HEX = "0123456789ABCDEF".getBytes();

/**
Expand Down
1 change: 1 addition & 0 deletions releasetools/src/releasetools/ReleaseBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ private static JsonObject libraryJson(File lib) {
JsonObject library = new JsonObject();
library.add("name", lib.getName());
library.add("md5", Util.md5sum(lib));
library.add("sha256", Util.sha256sum(lib));
library.add("size", (int) Math.min(Integer.MAX_VALUE, lib.length()));
return library;
}
Expand Down

0 comments on commit 47b7f25

Please sign in to comment.