From 12bf090895b97ae9694a523ccba8fdda2023a6a5 Mon Sep 17 00:00:00 2001
From: comp500 <comp500@users.noreply.github.com>
Date: Mon, 24 Jun 2019 17:27:28 +0100
Subject: [PATCH] Fix hash serialisation in JSON, check index hash

---
 .../packwiz/installer/UpdateManager.java      | 26 ++++++----
 .../packwiz/installer/metadata/IndexFile.java |  5 +-
 .../installer/metadata/ManifestFile.java      | 10 ++--
 .../packwiz/installer/metadata/ModFile.java   |  3 +-
 .../metadata/hash/GeneralHashingSource.java   |  2 +-
 .../packwiz/installer/metadata/hash/Hash.java | 48 +++++++++++++++++++
 .../installer/metadata/hash/HashUtils.java    |  2 +-
 .../metadata/hash/HashingSourceHasher.java    | 16 +++++--
 .../installer/metadata/hash/IHasher.java      |  2 +-
 .../metadata/hash/Murmur2Hasher.java          | 16 +++++--
 .../packwiz/installer/ui/CLIHandler.java      |  1 +
 11 files changed, 105 insertions(+), 26 deletions(-)
 create mode 100644 src/main/java/link/infra/packwiz/installer/metadata/hash/Hash.java

diff --git a/src/main/java/link/infra/packwiz/installer/UpdateManager.java b/src/main/java/link/infra/packwiz/installer/UpdateManager.java
index 1814449..5ca183f 100644
--- a/src/main/java/link/infra/packwiz/installer/UpdateManager.java
+++ b/src/main/java/link/infra/packwiz/installer/UpdateManager.java
@@ -21,6 +21,7 @@ import java.util.concurrent.Executors;
 import java.util.stream.Collectors;
 
 import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
 import com.google.gson.JsonIOException;
 import com.google.gson.JsonSyntaxException;
 import com.google.gson.annotations.SerializedName;
@@ -30,6 +31,7 @@ import link.infra.packwiz.installer.metadata.IndexFile;
 import link.infra.packwiz.installer.metadata.ManifestFile;
 import link.infra.packwiz.installer.metadata.PackFile;
 import link.infra.packwiz.installer.metadata.hash.GeneralHashingSource;
+import link.infra.packwiz.installer.metadata.hash.Hash;
 import link.infra.packwiz.installer.metadata.hash.HashUtils;
 import link.infra.packwiz.installer.request.HandlerManager;
 import link.infra.packwiz.installer.ui.IUserInterface;
@@ -109,7 +111,7 @@ public class UpdateManager {
 		this.checkOptions();
 
 		ui.submitProgress(new InstallProgress("Loading manifest file..."));
-		Gson gson = new Gson();
+		Gson gson = new GsonBuilder().registerTypeAdapter(Hash.class, new Hash.TypeHandler()).create();
 		ManifestFile manifest;
 		try {
 			manifest = gson.fromJson(new FileReader(Paths.get(opts.packFolder, opts.manifestFile).toString()),
@@ -141,12 +143,12 @@ public class UpdateManager {
 		}
 
 		if (manifest.packFileHash != null && packFileSource.hashIsEqual(manifest.packFileHash)) {
-			System.out.println("Hash already up to date!");
-			// WOOO it's already up to date
+			System.out.println("Modpack is already up to date!");
 			// todo: --force?
+			return;
 		}
 
-		System.out.println(pf.name);
+		System.out.println("Modpack name: " + pf.name);
 
 		try {
 			processIndex(HandlerManager.getNewLoc(opts.downloadURI, pf.index.file),
@@ -172,7 +174,13 @@ public class UpdateManager {
 		// TODO: implement
 	}
 
-	protected void processIndex(URI indexUri, Object indexHash, String hashFormat, ManifestFile manifest) {
+	protected void processIndex(URI indexUri, Hash indexHash, String hashFormat, ManifestFile manifest) {
+		if (manifest.indexFileHash != null && manifest.indexFileHash.equals(indexHash)) {
+			System.out.println("Modpack files are already up to date!");
+			return;
+		}
+		manifest.indexFileHash = indexHash;
+
 		GeneralHashingSource indexFileSource;
 		try {
 			Source src = HandlerManager.getFileSource(indexUri);
@@ -192,10 +200,8 @@ public class UpdateManager {
 		}
 
 		if (!indexFileSource.hashIsEqual(indexHash)) {
-			System.out.println("Hash problems!!!!!!!");
-			System.out.println(indexHash);
-			System.out.println(indexFileSource.getHash());
 			// TODO: throw exception
+			return;
 		}
 
 		if (manifest.cachedFiles == null) {
@@ -211,7 +217,7 @@ public class UpdateManager {
 			return f;
 		}).filter(f -> {
 			ManifestFile.File cachedFile = manifest.cachedFiles.get(f.file);
-			Object newHash;
+			Hash newHash;
 			try {
 				newHash = HashUtils.getHash(f.hashFormat, f.hash);
 			} catch (Exception e) {
@@ -266,7 +272,7 @@ public class UpdateManager {
 					}
 
 					try {
-						Object hash;
+						Hash hash;
 						String fileHashFormat;
 						if (f.linkedFile != null) {
 							hash = f.linkedFile.getHash();
diff --git a/src/main/java/link/infra/packwiz/installer/metadata/IndexFile.java b/src/main/java/link/infra/packwiz/installer/metadata/IndexFile.java
index 043ef3d..e4da16f 100644
--- a/src/main/java/link/infra/packwiz/installer/metadata/IndexFile.java
+++ b/src/main/java/link/infra/packwiz/installer/metadata/IndexFile.java
@@ -9,6 +9,7 @@ import com.google.gson.annotations.SerializedName;
 import com.moandjiezana.toml.Toml;
 
 import link.infra.packwiz.installer.metadata.hash.GeneralHashingSource;
+import link.infra.packwiz.installer.metadata.hash.Hash;
 import link.infra.packwiz.installer.metadata.hash.HashUtils;
 import link.infra.packwiz.installer.request.HandlerManager;
 import okio.Okio;
@@ -42,7 +43,7 @@ public class IndexFile {
 			if (hashFormat == null || hashFormat.length() == 0) {
 				hashFormat = parentIndexFile.hashFormat;
 			}
-			Object fileHash = HashUtils.getHash(hashFormat, hash);
+			Hash fileHash = HashUtils.getHash(hashFormat, hash);
 			linkedFileURI = HandlerManager.getNewLoc(indexUri, file);
 			Source src = HandlerManager.getFileSource(linkedFileURI);
 			GeneralHashingSource fileStream = HashUtils.getHasher(hashFormat).getHashingSource(src);
@@ -68,7 +69,7 @@ public class IndexFile {
 			}
 		}
 
-		public Object getHash() throws Exception {
+		public Hash getHash() throws Exception {
 			if (hash == null) {
 				throw new Exception("Index file doesn't have a hash");
 			}
diff --git a/src/main/java/link/infra/packwiz/installer/metadata/ManifestFile.java b/src/main/java/link/infra/packwiz/installer/metadata/ManifestFile.java
index 09f2eb6..ecf5c65 100644
--- a/src/main/java/link/infra/packwiz/installer/metadata/ManifestFile.java
+++ b/src/main/java/link/infra/packwiz/installer/metadata/ManifestFile.java
@@ -3,16 +3,18 @@ package link.infra.packwiz.installer.metadata;
 import java.net.URI;
 import java.util.Map;
 
+import link.infra.packwiz.installer.metadata.hash.Hash;
+
 public class ManifestFile {
 	
-	public Object packFileHash = null;
-	public Object indexFileHash = null;
+	public Hash packFileHash = null;
+	public Hash indexFileHash = null;
 	public Map<URI, File> cachedFiles;
 
 	public static class File {
-		public Object hash = null;
+		public Hash hash = null;
 		public boolean isOptional = false;
 		public boolean optionValue = true;
-		public Object linkedFileHash = null;
+		public Hash linkedFileHash = null;
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/link/infra/packwiz/installer/metadata/ModFile.java b/src/main/java/link/infra/packwiz/installer/metadata/ModFile.java
index a4fa417..2c59fdb 100644
--- a/src/main/java/link/infra/packwiz/installer/metadata/ModFile.java
+++ b/src/main/java/link/infra/packwiz/installer/metadata/ModFile.java
@@ -7,6 +7,7 @@ import com.google.gson.annotations.JsonAdapter;
 import com.google.gson.annotations.SerializedName;
 
 import link.infra.packwiz.installer.UpdateManager.Options.Side;
+import link.infra.packwiz.installer.metadata.hash.Hash;
 import link.infra.packwiz.installer.metadata.hash.HashUtils;
 import link.infra.packwiz.installer.request.HandlerManager;
 import okio.Source;
@@ -50,7 +51,7 @@ public class ModFile {
 		return HandlerManager.getFileSource(newLoc);
 	}
 
-	public Object getHash() throws Exception {
+	public Hash getHash() throws Exception {
 		if (download == null) {
 			throw new Exception("Metadata file doesn't have download");
 		}
diff --git a/src/main/java/link/infra/packwiz/installer/metadata/hash/GeneralHashingSource.java b/src/main/java/link/infra/packwiz/installer/metadata/hash/GeneralHashingSource.java
index 1aaba53..6ac9514 100644
--- a/src/main/java/link/infra/packwiz/installer/metadata/hash/GeneralHashingSource.java
+++ b/src/main/java/link/infra/packwiz/installer/metadata/hash/GeneralHashingSource.java
@@ -9,7 +9,7 @@ public abstract class GeneralHashingSource extends ForwardingSource {
 		super(delegate);
 	}
 
-	public abstract Object getHash();
+	public abstract Hash getHash();
 
 	public boolean hashIsEqual(Object compareTo) {
 		return compareTo.equals(getHash());
diff --git a/src/main/java/link/infra/packwiz/installer/metadata/hash/Hash.java b/src/main/java/link/infra/packwiz/installer/metadata/hash/Hash.java
new file mode 100644
index 0000000..0f7eed3
--- /dev/null
+++ b/src/main/java/link/infra/packwiz/installer/metadata/hash/Hash.java
@@ -0,0 +1,48 @@
+package link.infra.packwiz.installer.metadata.hash;
+
+import java.lang.reflect.Type;
+
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.google.gson.JsonPrimitive;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+
+public abstract class Hash {
+	protected abstract String getStringValue();
+
+	protected abstract String getType();
+
+	public static class TypeHandler implements JsonDeserializer<Hash>, JsonSerializer<Hash> {
+
+		@Override
+		public JsonElement serialize(Hash src, Type typeOfSrc, JsonSerializationContext context) {
+			JsonObject out = new JsonObject();
+			out.add("type", new JsonPrimitive(src.getType()));
+			out.add("value", new JsonPrimitive(src.getStringValue()));
+			return out;
+		}
+
+		@Override
+		public Hash deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
+				throws JsonParseException {
+			JsonObject obj = json.getAsJsonObject();
+			String type, value;
+			try {
+				type = obj.get("type").getAsString();
+				value = obj.get("value").getAsString();
+			} catch (NullPointerException e) {
+				throw new JsonParseException("Invalid hash JSON data");
+			}
+			try {
+				return HashUtils.getHash(type, value);
+			} catch (Exception e) {
+				throw new JsonParseException("Failed to create hash object", e);
+			}
+		}
+
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/link/infra/packwiz/installer/metadata/hash/HashUtils.java b/src/main/java/link/infra/packwiz/installer/metadata/hash/HashUtils.java
index 86452ed..47913e2 100644
--- a/src/main/java/link/infra/packwiz/installer/metadata/hash/HashUtils.java
+++ b/src/main/java/link/infra/packwiz/installer/metadata/hash/HashUtils.java
@@ -18,7 +18,7 @@ public class HashUtils {
 		return hasher;
 	}
 
-	public static Object getHash(String type, String value) throws Exception {
+	public static Hash getHash(String type, String value) throws Exception {
 		if (hashTypeConversion.containsKey(type)) {
 			return hashTypeConversion.get(type).getHash(value);
 		}
diff --git a/src/main/java/link/infra/packwiz/installer/metadata/hash/HashingSourceHasher.java b/src/main/java/link/infra/packwiz/installer/metadata/hash/HashingSourceHasher.java
index 5df4211..ea8c985 100644
--- a/src/main/java/link/infra/packwiz/installer/metadata/hash/HashingSourceHasher.java
+++ b/src/main/java/link/infra/packwiz/installer/metadata/hash/HashingSourceHasher.java
@@ -21,7 +21,7 @@ public class HashingSourceHasher implements IHasher {
 		}
 
 		@Override
-		public Object getHash() {
+		public Hash getHash() {
 			if (value == null) {
 				value = new HashingSourceHash(delegateHashing.hash().hex());
 			}
@@ -33,7 +33,7 @@ public class HashingSourceHasher implements IHasher {
 	// this some funky inner class stuff
 	// each of these classes is specific to the instance of the HasherHashingSource
 	// therefore HashingSourceHashes from different parent instances will be not instanceof each other
-	private class HashingSourceHash {
+	private class HashingSourceHash extends Hash {
 		String value;
 		private HashingSourceHash(String value) {
 			this.value = value;
@@ -56,6 +56,16 @@ public class HashingSourceHasher implements IHasher {
 		public String toString() {
 			return type + ": " + value;
 		}
+
+		@Override
+		protected String getStringValue() {
+			return value;
+		}
+
+		@Override
+		protected String getType() {
+			return type;
+		}
 	}
 
 	@Override
@@ -69,7 +79,7 @@ public class HashingSourceHasher implements IHasher {
 	}
 
 	@Override
-	public Object getHash(String value) {
+	public Hash getHash(String value) {
 		return new HashingSourceHash(value);
 	}
 	
diff --git a/src/main/java/link/infra/packwiz/installer/metadata/hash/IHasher.java b/src/main/java/link/infra/packwiz/installer/metadata/hash/IHasher.java
index f037cc8..921705e 100644
--- a/src/main/java/link/infra/packwiz/installer/metadata/hash/IHasher.java
+++ b/src/main/java/link/infra/packwiz/installer/metadata/hash/IHasher.java
@@ -4,5 +4,5 @@ import okio.Source;
 
 public interface IHasher {
 	public GeneralHashingSource getHashingSource(Source delegate);
-	public Object getHash(String value);
+	public Hash getHash(String value);
 }
\ No newline at end of file
diff --git a/src/main/java/link/infra/packwiz/installer/metadata/hash/Murmur2Hasher.java b/src/main/java/link/infra/packwiz/installer/metadata/hash/Murmur2Hasher.java
index ccdeff1..64139da 100644
--- a/src/main/java/link/infra/packwiz/installer/metadata/hash/Murmur2Hasher.java
+++ b/src/main/java/link/infra/packwiz/installer/metadata/hash/Murmur2Hasher.java
@@ -28,7 +28,7 @@ public class Murmur2Hasher implements IHasher {
 		}
 
 		@Override
-		public Object getHash() {
+		public Hash getHash() {
 			if (value == null) {
 				byte[] data = computeNormalizedArray(internalBuffer.readByteArray());
 				value = new Murmur2Hash(Murmur2Lib.hash32(data, data.length, 1));
@@ -54,7 +54,7 @@ public class Murmur2Hasher implements IHasher {
 
 	}
 
-	private class Murmur2Hash {
+	private class Murmur2Hash extends Hash {
 		int value;
 		private Murmur2Hash(String value) {
 			// Parsing as long then casting to int converts values gt int max value but lt uint max value
@@ -79,6 +79,16 @@ public class Murmur2Hasher implements IHasher {
 		public String toString() {
 			return "murmur2: " + value;
 		}
+
+		@Override
+		protected String getStringValue() {
+			return Integer.toString(value);
+		}
+
+		@Override
+		protected String getType() {
+			return "murmur2";
+		}
 	}
 
 	@Override
@@ -87,7 +97,7 @@ public class Murmur2Hasher implements IHasher {
 	}
 
 	@Override
-	public Object getHash(String value) {
+	public Hash getHash(String value) {
 		return new Murmur2Hash(value);
 	}
 	
diff --git a/src/main/java/link/infra/packwiz/installer/ui/CLIHandler.java b/src/main/java/link/infra/packwiz/installer/ui/CLIHandler.java
index 2e24e0c..e142299 100644
--- a/src/main/java/link/infra/packwiz/installer/ui/CLIHandler.java
+++ b/src/main/java/link/infra/packwiz/installer/ui/CLIHandler.java
@@ -27,6 +27,7 @@ public class CLIHandler implements IUserInterface {
 	@Override
 	public void executeManager(Runnable task) {
 		task.run();
+		System.out.println("Finished successfully!");
 	}
 	
 }